|
@@ -35,63 +35,18 @@
|
|
|
|
|
|
|
|
<!-- 区域展示组件 -->
|
|
<!-- 区域展示组件 -->
|
|
|
<region :allKnowledgeList="displayAllKnowledgeList" @add-practice="handleAddPractice" />
|
|
<region :allKnowledgeList="displayAllKnowledgeList" @add-practice="handleAddPractice" />
|
|
|
-
|
|
|
|
|
- <!-- ==================== 测试:CommonTree 公共树形组件 ==================== -->
|
|
|
|
|
- <div class="tree_test_section">
|
|
|
|
|
- <div class="tree_test_title">
|
|
|
|
|
- <span>📋 公共树形组件(CommonTree)测试区域</span>
|
|
|
|
|
- <el-button-group>
|
|
|
|
|
- <el-button size="mini" type="primary" @click="testGetChecked">获取选中节点</el-button>
|
|
|
|
|
- <el-button size="mini" @click="testClearChecked">清空选中</el-button>
|
|
|
|
|
- </el-button-group>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 左侧树形组件 -->
|
|
|
|
|
- <div class="tree_test_body">
|
|
|
|
|
- <div class="tree_panel">
|
|
|
|
|
- <CommonTree
|
|
|
|
|
- ref="treeTestRef"
|
|
|
|
|
- :tree-data="mockTreeData"
|
|
|
|
|
- :tree-props="{ label: 'label', children: 'children' }"
|
|
|
|
|
- node-key="id"
|
|
|
|
|
- show-checkbox
|
|
|
|
|
- :default-expand-all="false"
|
|
|
|
|
- @node-click="handleTestNodeClick"
|
|
|
|
|
- @node-check="handleTestNodeCheck"
|
|
|
|
|
- @ai-explain="handleTestAiExplain"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 右侧回传日志面板 -->
|
|
|
|
|
- <div class="tree_log_panel">
|
|
|
|
|
- <div class="log_title">回传事件日志:</div>
|
|
|
|
|
- <div class="log_list">
|
|
|
|
|
- <div v-for="(log, idx) in eventLogs" :key="idx" class="log_item" :class="'log-' + log.type">
|
|
|
|
|
- <div class="log_tag">[{{ log.tag }}]</div>
|
|
|
|
|
- <div class="log_time">{{ log.time }}</div>
|
|
|
|
|
- <pre class="log_content">{{ log.msg }}</pre>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-if="eventLogs.length === 0" class="log_empty">
|
|
|
|
|
- 请点击左侧树节点 / 勾选复选框 / 悬停后点"AI讲解"按钮 ↖
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
import CircularDiffusion from './knowledgeGraph/circularDiffusion.vue';
|
|
import CircularDiffusion from './knowledgeGraph/circularDiffusion.vue';
|
|
|
import Region from './knowledgeGraph/region.vue';
|
|
import Region from './knowledgeGraph/region.vue';
|
|
|
-import CommonTree from '@/components/CommonTree.vue';
|
|
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
name: 'KnowledgeGraph',
|
|
name: 'KnowledgeGraph',
|
|
|
components: {
|
|
components: {
|
|
|
CircularDiffusion,
|
|
CircularDiffusion,
|
|
|
- Region,
|
|
|
|
|
- CommonTree
|
|
|
|
|
|
|
+ Region
|
|
|
},
|
|
},
|
|
|
props: {
|
|
props: {
|
|
|
activeView: {
|
|
activeView: {
|
|
@@ -151,84 +106,6 @@ export default {
|
|
|
{ label: '初二', value: 'grade2' },
|
|
{ label: '初二', value: 'grade2' },
|
|
|
{ label: '初三', value: 'grade3' }
|
|
{ label: '初三', value: 'grade3' }
|
|
|
],
|
|
],
|
|
|
- // CommonTree 事件日志列表(用于右侧回传展示)
|
|
|
|
|
- eventLogs: [],
|
|
|
|
|
- // ========== 测试 CommonTree 组件的树形假数据 ==========
|
|
|
|
|
- // 结构:id / label / count(可选)/ children(可选)
|
|
|
|
|
- mockTreeData: [
|
|
|
|
|
- {
|
|
|
|
|
- id: 'chinese',
|
|
|
|
|
- label: '语言文学应用',
|
|
|
|
|
- count: 60,
|
|
|
|
|
- children: [
|
|
|
|
|
- {
|
|
|
|
|
- id: 'modern-reading',
|
|
|
|
|
- label: '现代文阅读',
|
|
|
|
|
- count: 60,
|
|
|
|
|
- children: [
|
|
|
|
|
- { id: 'discourse', label: '论述类文本阅读', count: 60 },
|
|
|
|
|
- { id: 'practical', label: '实用类文本阅读', count: 60 },
|
|
|
|
|
- { id: 'literary', label: '文学类文本阅读', count: 60 }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 'ancient-reading',
|
|
|
|
|
- label: '古代诗文阅读',
|
|
|
|
|
- count: 60,
|
|
|
|
|
- children: [
|
|
|
|
|
- { id: 'classical-chinese', label: '文言文阅读', count: 60 },
|
|
|
|
|
- { id: 'ancient-poetry', label: '古代诗歌阅读', count: 60 },
|
|
|
|
|
- { id: 'water-resource', label: '水资源跨区域调配对区域发展的影响', count: 60 }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 'whole-book',
|
|
|
|
|
- label: '整本书阅读',
|
|
|
|
|
- count: 60,
|
|
|
|
|
- children: [
|
|
|
|
|
- {
|
|
|
|
|
- id: 'literary-classics',
|
|
|
|
|
- label: '文学名著',
|
|
|
|
|
- count: 60,
|
|
|
|
|
- children: [
|
|
|
|
|
- { id: 'luoshen', label: '《洛神赋》', count: 60 },
|
|
|
|
|
- { id: 'tengwang', label: '《滕王阁序》', count: 60 }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- { id: 'culture-classics', label: '文化经典', count: 60 },
|
|
|
|
|
- { id: 'academic-works', label: '学术著作', count: 60 }
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 'math',
|
|
|
|
|
- label: '数学知识体系',
|
|
|
|
|
- count: 140,
|
|
|
|
|
- children: [
|
|
|
|
|
- {
|
|
|
|
|
- id: 'math-function',
|
|
|
|
|
- label: '函数与方程',
|
|
|
|
|
- count: 30,
|
|
|
|
|
- children: [
|
|
|
|
|
- { id: 'quadratic', label: '一元二次方程', count: 20 },
|
|
|
|
|
- { id: 'function-graph', label: '函数图像', count: 10 }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 'math-geometry',
|
|
|
|
|
- label: '几何图形',
|
|
|
|
|
- count: 50,
|
|
|
|
|
- children: [
|
|
|
|
|
- { id: 'triangle', label: '三角形', count: 20 },
|
|
|
|
|
- { id: 'circle-prop', label: '圆的性质', count: 30 }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- { id: 'math-probability', label: '概率统计', count: 30 },
|
|
|
|
|
- { id: 'math-solid', label: '立体几何', count: 30 }
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
// 假数据:表格树形结构数据(用于图表渲染)
|
|
// 假数据:表格树形结构数据(用于图表渲染)
|
|
|
// knowledgeType: 1=薄弱(红色), 2=良好(黄色), 3=优秀(绿色)
|
|
// knowledgeType: 1=薄弱(红色), 2=良好(黄色), 3=优秀(绿色)
|
|
|
// gradeScoreRate: 年级得分率,用于判断节点是否有数据
|
|
// gradeScoreRate: 年级得分率,用于判断节点是否有数据
|
|
@@ -517,95 +394,6 @@ export default {
|
|
|
// 处理加入练习
|
|
// 处理加入练习
|
|
|
handleAddPractice(item) {
|
|
handleAddPractice(item) {
|
|
|
this.$emit('add-practice', item);
|
|
this.$emit('add-practice', item);
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- // ==================== CommonTree 组件测试方法 ====================
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 追加日志到右侧面板
|
|
|
|
|
- * @param {String} type - 日志类型(info/warn/success/error)
|
|
|
|
|
- * @param {String} tag - 显示标签
|
|
|
|
|
- * @param {String} msg - 日志内容
|
|
|
|
|
- */
|
|
|
|
|
- appendLog(type, tag, msg) {
|
|
|
|
|
- const now = new Date();
|
|
|
|
|
- const time = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
|
|
|
|
|
- this.eventLogs.unshift({ type, tag, time, msg });
|
|
|
|
|
- // 只保留最近10条日志
|
|
|
|
|
- if (this.eventLogs.length > 10) this.eventLogs.pop();
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 【事件回传1】树节点点击(单选)
|
|
|
|
|
- * @param {Object} data - 当前节点用户数据
|
|
|
|
|
- * @param {Object} node - el-tree 节点实例
|
|
|
|
|
- */
|
|
|
|
|
- handleTestNodeClick(data, node) {
|
|
|
|
|
- const logMsg =
|
|
|
|
|
- `节点ID: ${data.id}\n` +
|
|
|
|
|
- `节点名称: ${data.label}\n` +
|
|
|
|
|
- `节点层级: ${node.level}\n` +
|
|
|
|
|
- `是否叶子: ${node.isLeaf ? '是' : '否'}\n` +
|
|
|
|
|
- `计数count: ${data.count ?? '无'}\n` +
|
|
|
|
|
- `\n完整data: ${JSON.stringify(data, null, 2)}`;
|
|
|
|
|
- console.log('%c[KnowledgeGraph] node-click 回传数据: ', 'background:#2E64FA;color:#fff;padding:4px 8px;border-radius:4px;', { data, node });
|
|
|
|
|
- this.appendLog('info', '节点点击', logMsg);
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 【事件回传2】复选框勾选变化(多选)
|
|
|
|
|
- * @param {Object} data - 当前操作的节点数据
|
|
|
|
|
- * @param {Object} checkedInfo - 勾选状态详情 { checkedNodes, checkedKeys, halfCheckedKeys }
|
|
|
|
|
- */
|
|
|
|
|
- handleTestNodeCheck(data, checkedInfo) {
|
|
|
|
|
- const selectedLabels = checkedInfo.checkedNodes.map(n => n.label).join('、') || '(无)';
|
|
|
|
|
- const logMsg =
|
|
|
|
|
- `当前操作节点: ${data.label}\n` +
|
|
|
|
|
- `已勾选节点数: ${checkedInfo.checkedNodes.length}\n` +
|
|
|
|
|
- `已勾选key: [${checkedInfo.checkedKeys.join(', ')}]\n` +
|
|
|
|
|
- `半选key: [${(checkedInfo.halfCheckedKeys || []).join(', ') || '无'}]\n` +
|
|
|
|
|
- `\n已勾选节点名称: ${selectedLabels}`;
|
|
|
|
|
- console.log('%c[KnowledgeGraph] node-check 回传数据: ', 'background:#3BA272;color:#fff;padding:4px 8px;border-radius:4px;', { data, checkedInfo });
|
|
|
|
|
- this.appendLog('success', '复选框勾选', logMsg);
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 【事件回传3】AI讲解按钮点击
|
|
|
|
|
- * @param {Object} payload { nodeData, nodeInstance, nodeKey, nodeLabel }
|
|
|
|
|
- */
|
|
|
|
|
- handleTestAiExplain(payload) {
|
|
|
|
|
- const { nodeData, nodeKey, nodeLabel } = payload;
|
|
|
|
|
- const logMsg =
|
|
|
|
|
- `节点Key: ${nodeKey}\n` +
|
|
|
|
|
- `节点名称: ${nodeLabel}\n` +
|
|
|
|
|
- `节点层级: ${payload.nodeInstance.level}\n` +
|
|
|
|
|
- `计数count: ${nodeData.count ?? '无'}\n` +
|
|
|
|
|
- `\n完整节点数据: ${JSON.stringify(nodeData, null, 2)}`;
|
|
|
|
|
- console.log('%c[KnowledgeGraph] ai-explain 回传数据: ', 'background:#FAC858;color:#333;padding:4px 8px;border-radius:4px;', payload);
|
|
|
|
|
- this.appendLog('warn', 'AI讲解', logMsg);
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 按钮测试:获取所有勾选的节点(调用组件暴露方法)
|
|
|
|
|
- */
|
|
|
|
|
- testGetChecked() {
|
|
|
|
|
- const nodes = this.$refs.treeTestRef.getCheckedNodes(false);
|
|
|
|
|
- const keys = this.$refs.treeTestRef.getCheckedKeys(false);
|
|
|
|
|
- const logMsg =
|
|
|
|
|
- `勾选节点对象数: ${nodes.length}\n` +
|
|
|
|
|
- `勾选节点key数组: ${JSON.stringify(keys)}\n` +
|
|
|
|
|
- `勾选节点名称: ${nodes.map(n => n.label).join('、') || '(无)'}`;
|
|
|
|
|
- console.log('%c[KnowledgeGraph] getCheckedNodes 结果: ', 'background:#67C23A;color:#fff;padding:4px 8px;border-radius:4px;', nodes, keys);
|
|
|
|
|
- this.appendLog('success', '获取选中节点', logMsg);
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 按钮测试:清空所有勾选节点
|
|
|
|
|
- */
|
|
|
|
|
- testClearChecked() {
|
|
|
|
|
- this.$refs.treeTestRef.clearChecked();
|
|
|
|
|
- console.log('%c[KnowledgeGraph] clearChecked 已清空', 'background:#E6A23C;color:#fff;padding:4px 8px;border-radius:4px;');
|
|
|
|
|
- this.appendLog('info', '清空选中', '已通过 clearChecked() 方法清空所有复选框勾选状态');
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
@@ -666,131 +454,6 @@ export default {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /* ==================== CommonTree 测试区域样式 ==================== */
|
|
|
|
|
- .tree_test_section {
|
|
|
|
|
- margin-top: 15px;
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- border-radius: 10px;
|
|
|
|
|
- padding: 15px 20px 20px;
|
|
|
|
|
-
|
|
|
|
|
- /* 测试区标题栏 */
|
|
|
|
|
- .tree_test_title {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
- padding-bottom: 12px;
|
|
|
|
|
- margin-bottom: 12px;
|
|
|
|
|
- border-bottom: 1px solid #eceef3;
|
|
|
|
|
- font-size: 15px;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /* 测试区主体:左树右日志 */
|
|
|
|
|
- .tree_test_body {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- gap: 16px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /* 左侧树形面板(必须白色,因为树形末尾竖线用白色块截断) */
|
|
|
|
|
- .tree_panel {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- height: 420px;
|
|
|
|
|
- border: 1px solid #eceef3;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- padding: 8px 0 8px 4px;
|
|
|
|
|
- overflow-y: auto;
|
|
|
|
|
- background: #fff;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /* 右侧事件日志面板 */
|
|
|
|
|
- .tree_log_panel {
|
|
|
|
|
- width: 420px;
|
|
|
|
|
- height: 420px;
|
|
|
|
|
- border: 1px solid #eceef3;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
-
|
|
|
|
|
- .log_title {
|
|
|
|
|
- padding: 10px 14px;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- color: #666;
|
|
|
|
|
- background: #f5f7fa;
|
|
|
|
|
- border-bottom: 1px solid #eceef3;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .log_list {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- overflow-y: auto;
|
|
|
|
|
- padding: 10px 12px;
|
|
|
|
|
-
|
|
|
|
|
- /* 单条日志 */
|
|
|
|
|
- .log_item {
|
|
|
|
|
- border: 1px solid #eef0f3;
|
|
|
|
|
- border-radius: 6px;
|
|
|
|
|
- margin-bottom: 8px;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
-
|
|
|
|
|
- .log_tag, .log_time {
|
|
|
|
|
- display: inline-block;
|
|
|
|
|
- padding: 2px 8px;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .log_tag {
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- color: #fff;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .log_time {
|
|
|
|
|
- color: #909399;
|
|
|
|
|
- background: #f5f7fa;
|
|
|
|
|
- border-bottom: 1px solid #eef0f3;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .log_content {
|
|
|
|
|
- margin: 0;
|
|
|
|
|
- padding: 8px 10px;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- color: #444;
|
|
|
|
|
- line-height: 1.6;
|
|
|
|
|
- white-space: pre-wrap;
|
|
|
|
|
- word-break: break-all;
|
|
|
|
|
- font-family: Consolas, Monaco, monospace;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /* 按事件类型设置标签颜色 */
|
|
|
|
|
- &.log-info {
|
|
|
|
|
- .log_tag { background: #2E64FA; }
|
|
|
|
|
- border-left: 3px solid #2E64FA;
|
|
|
|
|
- }
|
|
|
|
|
- &.log-success {
|
|
|
|
|
- .log_tag { background: #3BA272; }
|
|
|
|
|
- border-left: 3px solid #3BA272;
|
|
|
|
|
- }
|
|
|
|
|
- &.log-warn {
|
|
|
|
|
- .log_tag { background: #E6A23C; }
|
|
|
|
|
- border-left: 3px solid #E6A23C;
|
|
|
|
|
- }
|
|
|
|
|
- &.log-error {
|
|
|
|
|
- .log_tag { background: #F56C6C; }
|
|
|
|
|
- border-left: 3px solid #F56C6C;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .log_empty {
|
|
|
|
|
- padding: 30px 12px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- color: #909399;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/* 自定义滚动条样式 */
|
|
/* 自定义滚动条样式 */
|
|
|
&::-webkit-scrollbar {
|
|
&::-webkit-scrollbar {
|
|
|
width: 6px;
|
|
width: 6px;
|