|
@@ -0,0 +1,1150 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="knowledge_graph">
|
|
|
|
|
+
|
|
|
|
|
+ <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>
|
|
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.good }" >
|
|
|
|
|
+ <span class="legend_dot good"></span>
|
|
|
|
|
+ <span class="legend_text">{{ "良好(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>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 视图切换按钮 - 移到knowledge_graph容器下 -->
|
|
|
|
|
+ <div class="view_switcher_container">
|
|
|
|
|
+ <el-button type="text" @click="switchView('graph')" class="switch_btn list_btn">
|
|
|
|
|
+ <i class="icon_switch_graph">
|
|
|
|
|
+ <img src="../../../assets/studentAnalysis/circleBlue.svg" alt="按图形查看">
|
|
|
|
|
+ </i>
|
|
|
|
|
+ 按图形查看
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button type="graph" class="switch_btn graph_btn" @click="switchView('list')">
|
|
|
|
|
+ <i class="icon_switch_list">
|
|
|
|
|
+ <img src="../../../assets/studentAnalysis/iconBlue.svg" alt="按列表查看">
|
|
|
|
|
+ </i>
|
|
|
|
|
+ 按列表查看
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 图形查看容器 -->
|
|
|
|
|
+ <div v-if="activeView === 'graph'" class="graph_content">
|
|
|
|
|
+ <!-- 左侧图表 -->
|
|
|
|
|
+ <div class="chart_container">
|
|
|
|
|
+ <!-- 顶部容器:图例和视图切换按钮 -->
|
|
|
|
|
+ <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>
|
|
|
|
|
+ <div class="legend_item" :class="{ 'selected': selectedLegend.good }" >
|
|
|
|
|
+ <span class="legend_dot good"></span>
|
|
|
|
|
+ <span class="legend_text">{{ "良好(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>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 视图切换按钮 -->
|
|
|
|
|
+ <div class="view_switcher_container" v-if="activeView === 'graph'" :class="activeView">
|
|
|
|
|
+ <el-button type="graph" @click="switchView('graph')" class="switch_btn graph_btn">
|
|
|
|
|
+ <i class="icon_switch_graph">
|
|
|
|
|
+ <img src="../../../assets/studentAnalysis/circleBlue.svg" alt="按图形查看">
|
|
|
|
|
+ </i>
|
|
|
|
|
+ 按图形查看
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button type="text" class="switch_btn list_btn" @click="switchView('list')">
|
|
|
|
|
+ <i class="icon_switch_list"><img src="../../../assets/studentAnalysis/iconGrey.svg" alt="按列表查看"></i>
|
|
|
|
|
+ 按列表查看
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div ref="chart" class="chart" style="width: 100%;"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 右侧容器,包含tab和知识点列表 -->
|
|
|
|
|
+ <div class="knowledge_right_container">
|
|
|
|
|
+ <!-- Tab切换 -->
|
|
|
|
|
+ <div class="knowledge_tab">
|
|
|
|
|
+ <div class="tab_item" :class="{ active: activeTab === 'zero' }" @click="activeTab = 'zero'">
|
|
|
|
|
+ 零分知识点
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="tab_item" :class="{ active: activeTab === 'highFreq' }" @click="activeTab = 'highFreq'">
|
|
|
|
|
+ 高频错题知识点
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 右侧知识点列表 -->
|
|
|
|
|
+ <div class="knowledge_list">
|
|
|
|
|
+ <div class="list_item" v-for="(item, index) in knowledgeItems" :key="index"
|
|
|
|
|
+ @click="handleItemClick(item, index)" :class="{ active: selectedIndex === index }">
|
|
|
|
|
+ <div class="item_header">
|
|
|
|
|
+ <span class="item_dot"></span>
|
|
|
|
|
+ <el-tooltip
|
|
|
|
|
+ :content="item.knowledgeName"
|
|
|
|
|
+ placement="top"
|
|
|
|
|
+ effect="light"
|
|
|
|
|
+ :disabled="item.knowledgeName.length < 15"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="item_title">{{item.knowledgeName}}</span>
|
|
|
|
|
+ </el-tooltip>
|
|
|
|
|
+ <span class="item_tag" v-if="item.scoreRateDiff">{{ item.scoreRateDiff }} %</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="item_info">
|
|
|
|
|
+ <span class="item_score">
|
|
|
|
|
+ <span class="score_label">得分率:</span>
|
|
|
|
|
+ <span class="score_first" v-if="item.gradeScoreRate">{{item.gradeScoreRate}}%</span>
|
|
|
|
|
+ <span class="score_separator" v-if="item.classScoreRate">|</span>
|
|
|
|
|
+ <span class="score_second" v-if="item.classScoreRate">{{item.classScoreRate}}%</span>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="item_exam_count">考试数: <span class="exam_count">{{ item.examNum || 0 }}</span></span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 列表查看容器 -->
|
|
|
|
|
+ <div v-if="activeView === 'list'" class="list_content">
|
|
|
|
|
+
|
|
|
|
|
+ <vxe-table :data="tableData" style="width: 100%;" maxHeight="480px" border show-header
|
|
|
|
|
+ :tree-config="{ childrenField: 'children', hasChildField: 'hasChildren', showIcon: true, iconOpen: 'el-icon-remove', iconClose: 'el-icon-circle-plus' }"
|
|
|
|
|
+ :scroll-y="{ enabled: true, gt: 480 }" fixed-header
|
|
|
|
|
+ :header-cell-style="{ color: '#333' }">
|
|
|
|
|
+
|
|
|
|
|
+ <vxe-table-column type="tree" tree-node prop="title" :title="subjectName" >
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="knowledge_item">
|
|
|
|
|
+ <span class="knowledge_title">{{ row.knowledgeName }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </vxe-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 只有当班级名称不是年级且不为空时,才显示班级得分率列 -->
|
|
|
|
|
+ <vxe-table-column prop="classRate" title="班级得分率" width="180" align="center">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="rate_info" v-if="row.classScoreRate !== null">
|
|
|
|
|
+ <span class="rate_dot" :class="getRateClass(row.classScoreRate)"></span>
|
|
|
|
|
+ <span class="rate_value">{{ row.classScoreRate }}%</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </vxe-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <vxe-table-column prop="gradeScoreRate" title="年级得分率" width="180" align="center">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="rate_info">
|
|
|
|
|
+ <span class="rate_dot" :class="getRateClass(row.gradeScoreRate)"></span>
|
|
|
|
|
+ <span class="rate_value">{{ row.gradeScoreRate }}%</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </vxe-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 只有当班级名称不是年级且不为空时,才显示得分率差列 -->
|
|
|
|
|
+ <vxe-table-column prop="diff" title="得分率差" width="150" align="center">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="rate_info" v-if="row.scoreRateDiff !== null">
|
|
|
|
|
+ <span class="rate_dot" :class="getRateClass(row.scoreRateDiff)"></span>
|
|
|
|
|
+ <span class="diff_value" :class="{ 'diff_negative': row.scoreRateDiff !== null && row.scoreRateDiff < 0 }">
|
|
|
|
|
+ {{ row.scoreRateDiff !== null && row.scoreRateDiff >= 0 ? '+' : '' }}{{ row.scoreRateDiff }}%
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </vxe-table-column>
|
|
|
|
|
+ </vxe-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+// 引入echarts
|
|
|
|
|
+import * as echarts from 'echarts';
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: 'zeroScoreKnowledge',
|
|
|
|
|
+ props: {
|
|
|
|
|
+ mode: {
|
|
|
|
|
+ type: String,
|
|
|
|
|
+ default: 'grade',
|
|
|
|
|
+ validator: (value) => {
|
|
|
|
|
+ return ['grade', 'class'].includes(value);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // activeView: { // 当前视图,graph或list 年级画像还是学生画像
|
|
|
|
|
+ // type: String,
|
|
|
|
|
+ // default: 'graph',
|
|
|
|
|
+ // validator: (value) => {
|
|
|
|
|
+ // return ['graph', 'list'].includes(value);
|
|
|
|
|
+ // }
|
|
|
|
|
+ // },
|
|
|
|
|
+ subjectName: { // 科目名称
|
|
|
|
|
+ type: String,
|
|
|
|
|
+ default: '知识点'
|
|
|
|
|
+ },
|
|
|
|
|
+ subjectScoreRate: { // 科目得分率
|
|
|
|
|
+ type: Number,
|
|
|
|
|
+ default: 0
|
|
|
|
|
+ },
|
|
|
|
|
+ tableData: { // 知识点表格数据
|
|
|
|
|
+ type: Array,
|
|
|
|
|
+ default: () => []
|
|
|
|
|
+ },
|
|
|
|
|
+ classGroupName: { // 班级名称
|
|
|
|
|
+ type: String,
|
|
|
|
|
+ default: ''
|
|
|
|
|
+ },
|
|
|
|
|
+ fatalVulnerability: { // 零分知识点数据
|
|
|
|
|
+ type: Array,
|
|
|
|
|
+ default: () => []
|
|
|
|
|
+ },
|
|
|
|
|
+ highVulnerability: { // 高频错题知识点数据
|
|
|
|
|
+ type: Array,
|
|
|
|
|
+ default: () => []
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ // 根据当前tab返回对应的数据
|
|
|
|
|
+ knowledgeItems() {
|
|
|
|
|
+ return this.activeTab === 'zero' ? this.fatalVulnerability : this.highVulnerability;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ chart: null, // echarts实例
|
|
|
|
|
+ // 图例选中状态
|
|
|
|
|
+ selectedLegend: {
|
|
|
|
|
+ weak: true,
|
|
|
|
|
+ good: true,
|
|
|
|
|
+ excellent: true
|
|
|
|
|
+ },
|
|
|
|
|
+ // 选中的知识点索引
|
|
|
|
|
+ selectedIndex: 0,
|
|
|
|
|
+ // 零分知识点、高频知识点Tab切换状态
|
|
|
|
|
+ activeTab: 'zero',
|
|
|
|
|
+
|
|
|
|
|
+ // 按图形查看、按列表查看
|
|
|
|
|
+ activeView: 'graph',
|
|
|
|
|
+
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ // 无论在什么模式下,只要默认视图是图形视图就初始化echarts图表
|
|
|
|
|
+ if (this.activeView === 'graph') {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.initChart();
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 实现默认选中逻辑
|
|
|
|
|
+ this.setDefaultSelection();
|
|
|
|
|
+ },
|
|
|
|
|
+ beforeDestroy() {
|
|
|
|
|
+ // 销毁echarts实例
|
|
|
|
|
+ if (this.chart) {
|
|
|
|
|
+ this.chart.dispose();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ watch: {
|
|
|
|
|
+ // 监听mode变化,当切换到班级模式时,班级得分率列和得分率差列才显示
|
|
|
|
|
+ mode(newMode) {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.activeView ='graph';
|
|
|
|
|
+ this.initChart();
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 监听activeView变化,当切换到图形视图时重新初始化图表,切换到列表视图时销毁图表
|
|
|
|
|
+ activeView(newView) {
|
|
|
|
|
+ if (newView === 'graph') {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.initChart();
|
|
|
|
|
+ });
|
|
|
|
|
+ } else if (newView === 'list') {
|
|
|
|
|
+ // 切换到列表视图时销毁图表实例
|
|
|
|
|
+ if (this.chart) {
|
|
|
|
|
+ this.chart.dispose();
|
|
|
|
|
+ this.chart = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 监听tab切换,更新选中索引
|
|
|
|
|
+ activeTab() {
|
|
|
|
|
+ this.selectedIndex = 0;
|
|
|
|
|
+ },
|
|
|
|
|
+ // 监听数据变化,重新设置默认选中项
|
|
|
|
|
+ fatalVulnerability: {
|
|
|
|
|
+ deep: true,
|
|
|
|
|
+ handler() {
|
|
|
|
|
+ this.setDefaultSelection();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ highVulnerability: {
|
|
|
|
|
+ deep: true,
|
|
|
|
|
+ handler() {
|
|
|
|
|
+ this.setDefaultSelection();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ // 设置默认选中项
|
|
|
|
|
+ setDefaultSelection() {
|
|
|
|
|
+ // 如果零分知识点没有数据,切换到高频错题知识点并选中第一条
|
|
|
|
|
+ if (this.fatalVulnerability.length === 0 && this.highVulnerability.length > 0) {
|
|
|
|
|
+ this.activeTab = 'highFreq';
|
|
|
|
|
+ this.selectedIndex = 0;
|
|
|
|
|
+ // 不再自动发送选中事件,只设置选中状态
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.activeTab = 'zero';
|
|
|
|
|
+ // 否则默认选中零分知识点的第一条
|
|
|
|
|
+ this.selectedIndex = 0;
|
|
|
|
|
+ // 不再自动发送选中事件,只设置选中状态
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 切换查看方式
|
|
|
|
|
+ switchView(view) {
|
|
|
|
|
+ console.log(view);
|
|
|
|
|
+ //通过emit事件通知父组件更新activeView
|
|
|
|
|
+ //this.$emit('view-change', view);
|
|
|
|
|
+ this.activeView = view;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 根据得分率获取对应的颜色
|
|
|
|
|
+ getNodeColor(scoreRate) {
|
|
|
|
|
+ const rate = parseFloat(scoreRate);
|
|
|
|
|
+ if (rate >= 85) {
|
|
|
|
|
+ return '#3BA272'; // 优秀 - 绿色
|
|
|
|
|
+ } else if (rate >= 60) {
|
|
|
|
|
+ return '#FAC858'; // 良好 - 黄色
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return '#EE6666'; // 薄弱 - 红色
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 根据屏幕宽度计算合适的缩放值
|
|
|
|
|
+ getZoomValue() {
|
|
|
|
|
+ const screenWidth = window.innerWidth;
|
|
|
|
|
+ if (screenWidth <1100) {
|
|
|
|
|
+ return 1.0; // 小屏幕
|
|
|
|
|
+ } else if (screenWidth >= 1100 && screenWidth <= 1200) {
|
|
|
|
|
+ return 1.15; // 中等屏幕
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return 1.2; // 超大屏幕
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 更新图表缩放
|
|
|
|
|
+ updateChartZoom() {
|
|
|
|
|
+ if (this.chart) {
|
|
|
|
|
+ const zoom = this.getZoomValue();
|
|
|
|
|
+ this.chart.setOption({
|
|
|
|
|
+ series: [
|
|
|
|
|
+ {
|
|
|
|
|
+ zoom: zoom,
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化echarts图表
|
|
|
|
|
+ initChart() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 检查chart容器是否存在
|
|
|
|
|
+ if (!this.$refs.chart) {
|
|
|
|
|
+ console.error('图表容器不存在');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.createChart();
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ console.error('图表初始化失败:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 创建图表
|
|
|
|
|
+ createChart() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 检查chart容器是否存在
|
|
|
|
|
+ if (!this.$refs.chart) {
|
|
|
|
|
+ console.error('图表容器不存在');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 销毁现有的图表实例
|
|
|
|
|
+ if (this.chart) {
|
|
|
|
|
+ this.chart.dispose();
|
|
|
|
|
+ }
|
|
|
|
|
+ // 创建echarts实例
|
|
|
|
|
+ this.chart = echarts.init(this.$refs.chart);
|
|
|
|
|
+
|
|
|
|
|
+ // 保存当前组件实例的引用
|
|
|
|
|
+ const vm = this;
|
|
|
|
|
+
|
|
|
|
|
+ // 根据得分率获取对应的级别
|
|
|
|
|
+ const getNodeLevel = (scoreRate) => {
|
|
|
|
|
+ const rate = parseFloat(scoreRate);
|
|
|
|
|
+ if (rate >= 85) {
|
|
|
|
|
+ return 'excellent'; // 优秀
|
|
|
|
|
+ } else if (rate >= 60) {
|
|
|
|
|
+ return 'good'; // 良好
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return 'weak'; // 薄弱
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 基于表格数据生成树形图数据
|
|
|
|
|
+ const generateTreeData = (data, level = 0) => {
|
|
|
|
|
+ return data.filter(item => {
|
|
|
|
|
+ // 获取节点级别
|
|
|
|
|
+ const nodeLevel = getNodeLevel(item.gradeScoreRate);
|
|
|
|
|
+ // 根据图例选中状态决定是否显示节点
|
|
|
|
|
+ return vm.selectedLegend[nodeLevel];
|
|
|
|
|
+ }).map(item => {
|
|
|
|
|
+ // 根据级别设置统一的节点大小
|
|
|
|
|
+ const nodeSizes = [24, 16, 12, 10, 6];
|
|
|
|
|
+ const symbolSize = nodeSizes[Math.min(level, nodeSizes.length - 1)];
|
|
|
|
|
+
|
|
|
|
|
+ const node = {
|
|
|
|
|
+ name: item.knowledgeName,
|
|
|
|
|
+ symbolSize: symbolSize,
|
|
|
|
|
+ // 根据班级名称是否为年级来选择使用gradeScoreRate或classScoreRate
|
|
|
|
|
+ value: vm.classGroupName === '年级' ? item.gradeScoreRate : item.classScoreRate,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ color: vm.getNodeColor(item.gradeScoreRate)
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (item.children && item.children.length > 0) {
|
|
|
|
|
+ node.children = generateTreeData(item.children, level + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return node;
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 配置项
|
|
|
|
|
+ const option = {
|
|
|
|
|
+ tooltip: {
|
|
|
|
|
+ formatter: (params) => {
|
|
|
|
|
+ // 只有根节点(treePathInfo存在且长度为1)使用组件的subjectScoreRate作为得分率
|
|
|
|
|
+ if (params.treePathInfo && params.treePathInfo.length === 1) {
|
|
|
|
|
+ return `${params.name}<br/>得分率: ${this.subjectScoreRate}%`;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 其他节点(包括treePathInfo不存在的情况)都使用value作为得分率
|
|
|
|
|
+ return `${params.name}<br/>得分率: ${params.value !== null && params.value !== undefined ? params.value : '0'}%`;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ animationDurationUpdate: 1500,
|
|
|
|
|
+ animationEasingUpdate: 'quinticInOut',
|
|
|
|
|
+ series: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'tree',
|
|
|
|
|
+ layout: 'radial',
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ initialTreeDepth: 999, // 设置一个足够大的值,确保所有节点都展开
|
|
|
|
|
+ expandAndCollapse: true,
|
|
|
|
|
+ // 调整树状图布局参数,确保节点均匀分布
|
|
|
|
|
+ orient: 'radial',
|
|
|
|
|
+ roam: true,
|
|
|
|
|
+
|
|
|
|
|
+ // 使用基础配置实现居中
|
|
|
|
|
+ center: ['12%', '10%'],
|
|
|
|
|
+
|
|
|
|
|
+ zoom: this.getZoomValue(),
|
|
|
|
|
+ scaleLimit: {
|
|
|
|
|
+ min: 0.2,
|
|
|
|
|
+ max: 5
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 调整节点大小比例和间距,确保图表在容器中居中
|
|
|
|
|
+ nodeScaleRatio: 1,
|
|
|
|
|
+ layerPadding: [10, 5],
|
|
|
|
|
+ roam: true,
|
|
|
|
|
+
|
|
|
|
|
+ // 使用表格数据生成树形结构
|
|
|
|
|
+ data: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: this.subjectName,
|
|
|
|
|
+ symbolSize: 48,
|
|
|
|
|
+ value: this.subjectScoreRate, // 添加value属性,用于显示得分率
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ // 根据得分率动态设置颜色
|
|
|
|
|
+ color: this.subjectScoreRate >= 85 ? '#3BA272' : // 优秀 - 绿色
|
|
|
|
|
+ this.subjectScoreRate >= 60 ? '#FAC858' : // 良好 - 黄色
|
|
|
|
|
+ '#EE6666' // 薄弱 - 红色
|
|
|
|
|
+ },
|
|
|
|
|
+ children: generateTreeData(this.tableData)
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ color: '#ECEEF3',
|
|
|
|
|
+ width: 2,
|
|
|
|
|
+ type: 'solid'
|
|
|
|
|
+ },
|
|
|
|
|
+ emphasis: {
|
|
|
|
|
+ focus: 'adjacency',
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ width: 2
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 设置配置项
|
|
|
|
|
+ this.chart.setOption(option);
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化后调用resize确保图表正确显示
|
|
|
|
|
+ this.chart.resize();
|
|
|
|
|
+
|
|
|
|
|
+ // 监听窗口大小变化
|
|
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
|
|
+ if (this.chart) {
|
|
|
|
|
+ this.chart.resize();
|
|
|
|
|
+ this.updateChartZoom();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ console.error('图表创建失败:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 更新图表数据
|
|
|
|
|
+ updateChart() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (this.activeView === 'graph' && this.$refs.chart) {
|
|
|
|
|
+ // 重新创建图表,实现刷新效果
|
|
|
|
|
+ this.createChart();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ console.error('图表更新失败:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 根据得分率获取对应的样式类
|
|
|
|
|
+ getRateClass(rate) {
|
|
|
|
|
+ const rateValue = parseFloat(rate);
|
|
|
|
|
+ if (rateValue >= 85) {
|
|
|
|
|
+ return 'rate_excellent';
|
|
|
|
|
+ } else if (rateValue >= 60) {
|
|
|
|
|
+ return 'rate_good';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return 'rate_weak';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 行样式类名方法
|
|
|
|
|
+ rowClassName({ row }) {
|
|
|
|
|
+ return row.highlight ? 'row_highlight' : '';
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 处理知识点列表项点击事件
|
|
|
|
|
+// 向父组件发送事件,传递点击的知识点数据
|
|
|
|
|
+ handleItemClick(item, index) {
|
|
|
|
|
+ // 更新选中索引
|
|
|
|
|
+ this.selectedIndex = index;
|
|
|
|
|
+ // 向父组件发送事件,传递点击的知识点数据
|
|
|
|
|
+ this.$emit('knowledge-item-click', { item, index });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.knowledge_graph {
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ border-radius: 10px;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ .graph_header {
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ .legend {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20px;
|
|
|
|
|
+
|
|
|
|
|
+ .legend_item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 5px;
|
|
|
|
|
+
|
|
|
|
|
+ &.selected {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_dot {
|
|
|
|
|
+ width: 20px;
|
|
|
|
|
+ height: 10px;
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ background: #999999; // 默认灰色
|
|
|
|
|
+
|
|
|
|
|
+ &.weak {
|
|
|
|
|
+ background: #EE6666;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.good {
|
|
|
|
|
+ background: #FAC858;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.excellent {
|
|
|
|
|
+ background: #3BA272;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_text {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #999999; // 默认灰色文字
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 选中状态样式
|
|
|
|
|
+ &.selected {
|
|
|
|
|
+ .legend_dot.weak {
|
|
|
|
|
+ background: #EE6666;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_dot.good {
|
|
|
|
|
+ background: #FAC858;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_dot.excellent {
|
|
|
|
|
+ background: #3BA272;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_text {
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 视图切换按钮样式
|
|
|
|
|
+ .view_switcher_container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20px;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+
|
|
|
|
|
+ .switch_btn {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ background-color: transparent;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-radius: 0;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ transition: color 0.3s ease;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #2E64FA;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .graph_btn {
|
|
|
|
|
+ color: #2E64FA;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 图标样式,确保与文字对齐
|
|
|
|
|
+ .icon_switch_graph,
|
|
|
|
|
+ .icon_switch_list {
|
|
|
|
|
+ img {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ vertical-align: middle;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ margin-top: -3px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 鼠标悬停时图片换色效果
|
|
|
|
|
+ .switch_btn:hover .icon_switch_graph img,
|
|
|
|
|
+ .switch_btn:hover .icon_switch_list img {
|
|
|
|
|
+ filter: brightness(0) saturate(100%) invert(34%) sepia(100%) saturate(5000%) hue-rotate(210deg) brightness(95%) contrast(100%);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 对比选择器样式
|
|
|
|
|
+ .comparison_selector {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+
|
|
|
|
|
+ .student_position {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 对比选择器按钮样式
|
|
|
|
|
+ :deep(.el-button-group) {
|
|
|
|
|
+ .el-button {
|
|
|
|
|
+ padding: 7px 10px;
|
|
|
|
|
+ // border-radius: 4px;
|
|
|
|
|
+
|
|
|
|
|
+ &:not(.el-button--primary) {
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ background-color: #FFFFFF;
|
|
|
|
|
+ border-color: #DCDFE6;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #2E64FA;
|
|
|
|
|
+ border-color: #C6E2FF;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.el-button--primary {
|
|
|
|
|
+ background-color: #2E64FA;
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ border-color: #2E64FA;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background-color: #409EFF;
|
|
|
|
|
+ border-color: #409EFF;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .graph_content {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20px;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ .knowledge_tab {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ border-bottom: 1px solid #ECEEF3;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+
|
|
|
|
|
+ .tab_item {
|
|
|
|
|
+ height: 40px;
|
|
|
|
|
+ line-height: 40px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #666666;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ margin-right: 20px;
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ color: #2E64FA;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+
|
|
|
|
|
+ &::after {
|
|
|
|
|
+ content: '';
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ bottom: -1px;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 2px;
|
|
|
|
|
+ background-color: #2E64FA;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #2E64FA;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 零分知识点:根据文字宽度自适应,不需要内间距
|
|
|
|
|
+ // &:first-child {
|
|
|
|
|
+ // padding: 0;
|
|
|
|
|
+ // white-space: nowrap;
|
|
|
|
|
+ // }
|
|
|
|
|
+
|
|
|
|
|
+ // // 高频错题知识点:占满剩余宽度
|
|
|
|
|
+ // &:last-child {
|
|
|
|
|
+ // padding: 0;
|
|
|
|
|
+ // white-space: nowrap;
|
|
|
|
|
+ // }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .knowledge_right_container {
|
|
|
|
|
+ width: 265px;
|
|
|
|
|
+ height: 630px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chart_container {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ border-radius: 10px 10px 10px 10px;
|
|
|
|
|
+ border: 1px solid #E9EBEF;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ height: 590px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ .top_container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20px;
|
|
|
|
|
+ flex-wrap: wrap; // 小屏幕下自动换行
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+
|
|
|
|
|
+ .legend_item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 5px;
|
|
|
|
|
+ // cursor: pointer;
|
|
|
|
|
+ // opacity: 0.7;
|
|
|
|
|
+ // transition: all 0.3s ease;
|
|
|
|
|
+
|
|
|
|
|
+ &.selected {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_dot {
|
|
|
|
|
+ width: 20px;
|
|
|
|
|
+ height: 10px;
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ background: #999999; // 默认灰色
|
|
|
|
|
+
|
|
|
|
|
+ &.weak {
|
|
|
|
|
+ background: #EE6666;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.good {
|
|
|
|
|
+ background: #FAC858;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.excellent {
|
|
|
|
|
+ background: #3BA272;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_text {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #999999; // 默认灰色文字
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 选中状态样式
|
|
|
|
|
+ &.selected {
|
|
|
|
|
+ .legend_dot.weak {
|
|
|
|
|
+ background: #EE6666;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_dot.good {
|
|
|
|
|
+ background: #FAC858;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_dot.excellent {
|
|
|
|
|
+ background: #3BA272;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .legend_text {
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chart {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ min-height: 590px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .view_switcher_container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20px;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ white-space: nowrap; // 防止按钮换行
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .knowledge_list {
|
|
|
|
|
+ width: 265px;
|
|
|
|
|
+ height: 630px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ padding-right: 10px;
|
|
|
|
|
+
|
|
|
|
|
+ /* 滚动条样式 */
|
|
|
|
|
+ &::-webkit-scrollbar {
|
|
|
|
|
+ width: 6px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
|
|
+ background: #f1f1f1;
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
|
|
+ background: #c1c1c1;
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
+ background: #a1a1a1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .list_item {
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:hover,
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ background: rgba(46, 100, 250, 0.1);
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .item_header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+
|
|
|
|
|
+ .item_dot {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ width: 8px;
|
|
|
|
|
+ height: 8px;
|
|
|
|
|
+ background: #EE6666;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ margin-right: 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .item_title {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .item_tag {
|
|
|
|
|
+ background: #F56C6C;
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ padding: 4px 6px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .item_info {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ margin-top: 8px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ .item_score {
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+
|
|
|
|
|
+ .score_label {
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .score_first {
|
|
|
|
|
+ color: #F56C6C;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .score_separator {
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ margin: 0 4px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .score_second {
|
|
|
|
|
+ color: #666666;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .item_exam_count {
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+
|
|
|
|
|
+ .exam_count {
|
|
|
|
|
+ color: #2E64FA;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .list_content {
|
|
|
|
|
+ border-radius: 10px 10px 10px 10px;
|
|
|
|
|
+ max-height: 480px;
|
|
|
|
|
+ // border: 1px solid #E9EBEF;
|
|
|
|
|
+ // padding: 16px;
|
|
|
|
|
+
|
|
|
|
|
+ .vxe-table {
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ overflow-x: hidden;
|
|
|
|
|
+
|
|
|
|
|
+ .vxe-table--header {
|
|
|
|
|
+ display: table-header-group !important;
|
|
|
|
|
+ visibility: visible !important;
|
|
|
|
|
+ opacity: 1 !important;
|
|
|
|
|
+ height: auto !important;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-icon-circle-plus) {
|
|
|
|
|
+ color: #DCDFE6 !important;
|
|
|
|
|
+ font-size: 16px !important;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-icon-remove) {
|
|
|
|
|
+ color: #2E64FA !important;
|
|
|
|
|
+ font-size: 16px !important;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .vxe-table--body {
|
|
|
|
|
+ .vxe-body--row {
|
|
|
|
|
+ height: 52px;
|
|
|
|
|
+ border-bottom: 1px solid #F0F2F5;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background-color: #f5f7fa;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.row_highlight {
|
|
|
|
|
+ background-color: rgba(195, 219, 255, 0.2);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 树形表格样式 */
|
|
|
|
|
+ .vxe-table {
|
|
|
|
|
+
|
|
|
|
|
+ /* 自定义树形图标样式 */
|
|
|
|
|
+ .vxe-tree-icon {
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ width: 14px;
|
|
|
|
|
+ height: 14px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ margin-right: 6px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 展开状态的节点 */
|
|
|
|
|
+ .vxe-tree-icon--minus {
|
|
|
|
|
+ background-color: #409EFF;
|
|
|
|
|
+ color: white;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 可展开但未展开的节点 */
|
|
|
|
|
+ .vxe-tree-icon--plus {
|
|
|
|
|
+ background-color: #C0C4CC;
|
|
|
|
|
+ color: white;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .knowledge_item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ .knowledge_title {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .rate_info {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .rate_dot {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ width: 10px;
|
|
|
|
|
+ height: 10px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+
|
|
|
|
|
+ &.rate_excellent {
|
|
|
|
|
+ background-color: #3BA272;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.rate_good {
|
|
|
|
|
+ background-color: #FAC858;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.rate_weak {
|
|
|
|
|
+ background-color: #EE6666;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .rate_value {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .diff_value {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+
|
|
|
|
|
+ &.diff_negative {
|
|
|
|
|
+ color: #F56C6C;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|