|
|
@@ -0,0 +1,162 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import type { SearchResult } from "@/types/search.types";
|
|
|
+import { onMounted, ref, type Ref } from "vue";
|
|
|
+import G6 from '@antv/g6';
|
|
|
+import SearchResultList from "../search/components/SearchResultList.vue";
|
|
|
+import PropertyComponent from "./components/PropertyComponent.vue";
|
|
|
+
|
|
|
+const keyword = ref('');
|
|
|
+
|
|
|
+function onSearch() {
|
|
|
+ console.log('keyword', keyword);
|
|
|
+}
|
|
|
+
|
|
|
+// 搜索结果
|
|
|
+const searchResult: Ref<SearchResult | null> = ref(null);
|
|
|
+
|
|
|
+const data = {
|
|
|
+ // 点集
|
|
|
+ nodes: [
|
|
|
+ {
|
|
|
+ id: 'node1',
|
|
|
+ label: 'node1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'node2',
|
|
|
+ label: 'node2',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'node3',
|
|
|
+ label: 'node3',
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ // 边集
|
|
|
+ edges: [
|
|
|
+ {
|
|
|
+ source: 'node1',
|
|
|
+ target: 'node2',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ source: 'node1',
|
|
|
+ target: 'node3',
|
|
|
+ }
|
|
|
+ ],
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const graph = new G6.Graph({
|
|
|
+ container: 'graph',
|
|
|
+ layout: {
|
|
|
+ type: 'forceAtlas2',
|
|
|
+ preventOverlap: true,
|
|
|
+ kr: 20,
|
|
|
+ },
|
|
|
+ modes: {
|
|
|
+ default: ['drag-canvas', 'zoom-canvas', 'drag-node'], // 允许拖拽画布、放缩画布、拖拽节点
|
|
|
+ },
|
|
|
+ nodeStateStyles: {
|
|
|
+ // 鼠标 hover 上节点,即 hover 状态为 true 时的样式
|
|
|
+ hover: {
|
|
|
+ fill: 'lightsteelblue',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ defaultNode: {
|
|
|
+ size: 60,
|
|
|
+ type: 'circle',
|
|
|
+ style: {
|
|
|
+ stroke: '#666',
|
|
|
+ fill: 'steelblue'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ defaultEdge: {
|
|
|
+ label: '下级学科',
|
|
|
+ size: 1,
|
|
|
+ color: '#e2e2e2',
|
|
|
+ style: {
|
|
|
+ endArrow: {
|
|
|
+ path: 'M 0,0 L 8,4 L 8,-4 Z',
|
|
|
+ fill: '#e2e2e2',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ graph.data(data); // 读取 Step 2 中的数据源到图上
|
|
|
+ graph.render(); // 渲染图
|
|
|
+ graph.on('node:click', event => {
|
|
|
+ console.log('node:click', event.item?.getID());
|
|
|
+ const index = data['nodes'].findIndex(n => n.id == event.item?.getID())
|
|
|
+ if (index > -1) {
|
|
|
+ console.log(data['nodes'][index])
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="search-box">
|
|
|
+ <a-input-search
|
|
|
+ v-model:value="keyword"
|
|
|
+ placeholder="请输入关键词进行搜索"
|
|
|
+ enter-button="查 询"
|
|
|
+ size="large"
|
|
|
+ @search="onSearch"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <a-row :gutter="16" type="flex" class="graph-container">
|
|
|
+ <a-col :span="18">
|
|
|
+ <div class="graph-wrap">
|
|
|
+ <div id="graph" class="graph"></div>
|
|
|
+ </div>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="6">
|
|
|
+ <div class="property-wrap">
|
|
|
+ <PropertyComponent :data="{name: 'a', docCount: 10, keywords: {'a': 1}}" />
|
|
|
+ </div>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ <div class="articles-wrap">
|
|
|
+ <SearchResultList :data="searchResult" v-if="searchResult" />
|
|
|
+ <a-empty v-else description="暂无数据" />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+@import "@/assets/variables.scss";
|
|
|
+
|
|
|
+.search-box {
|
|
|
+ width: 65%;
|
|
|
+ margin: 0 auto;
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.graph-container {
|
|
|
+ margin-top: 10px;
|
|
|
+
|
|
|
+ .graph-wrap,
|
|
|
+ .property-wrap {
|
|
|
+ border: 1px solid $border-color;
|
|
|
+ background-color: white;
|
|
|
+ padding: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .graph-wrap {
|
|
|
+ height: 600px;
|
|
|
+
|
|
|
+ .graph {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .property-wrap {
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.articles-wrap {
|
|
|
+ margin-top: 10px;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: white;
|
|
|
+ border: 1px solid $border-color;
|
|
|
+}
|
|
|
+</style>
|