瀏覽代碼

Merge branch 'main' into 'dev_20221112'

# Conflicts:
#   src/services/search.service.ts
#   src/views/search/SearchResultView.vue
蒋文林 3 年之前
父節點
當前提交
d9624c814f

文件差異過大導致無法顯示
+ 1019 - 10
package-lock.json


+ 2 - 1
package.json

@@ -13,6 +13,7 @@
     "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
   },
   "dependencies": {
+    "@antv/g6": "^4.7.16",
     "@types/lodash": "^4.14.188",
     "ant-design-vue": "^3.2.13",
     "axios": "^1.1.3",
@@ -47,4 +48,4 @@
   "msw": {
     "workerDirectory": "public"
   }
-}
+}

src/assets/base.css → src/assets/base.scss


+ 0 - 1
src/assets/main.css

@@ -1 +0,0 @@
-@import "./base.css";

+ 1 - 0
src/assets/main.scss

@@ -0,0 +1 @@
+@import "./base.scss";

+ 2 - 0
src/assets/variables.scss

@@ -0,0 +1,2 @@
+
+$border-color: #d9d9d9;

+ 2 - 2
src/components/NavMenu.vue

@@ -71,8 +71,8 @@ function getOpenKeys(path: string): string[] {
         <NodeIndexOutlined />
       </template>
       <template #title>知识导航</template>
-      <a-menu-item key="/knowledge-graph/nav">
-        <RouterLink to="/knowledge-graph/nav">建筑工程科技导航</RouterLink>
+      <a-menu-item key="/knowledge-graph/search">
+        <RouterLink to="/knowledge-graph/search">建筑工程科技导航</RouterLink>
       </a-menu-item>
     </a-sub-menu>
   </a-menu>

+ 1 - 1
src/main.ts

@@ -7,7 +7,7 @@ import router from "./router";
 
 import "ant-design-vue/dist/antd.less";
 
-import "./assets/main.css";
+import "./assets/main.scss";
 
 import { worker } from './mocks/browser';
 if (process.env.NODE_ENV === 'development') {

+ 3 - 3
src/router/index.ts

@@ -61,9 +61,9 @@ const router = createRouter({
       component: RouteView,
       children: [
         {
-          path: "nav",
-          name: "KnowledgeGraphNav",
-          component: () => import("../views/knowledge-grapn/KnowLedgeGraphNavView.vue")
+          path: "search",
+          name: "KnowledgeGraph",
+          component: () => import("../views/knowledge-grapn/KnowledgeGraphView.vue")
         }
       ]
     },

+ 13 - 0
src/services/knowledgeGraph.service.ts

@@ -0,0 +1,13 @@
+import type { AxiosResponse } from "axios";
+import httpClient from "./httpClient";
+import type { Response } from "@/types/response.types";
+import type { Property } from "@/types/knowledgeGraph.types";
+
+/**
+ * 根据学科ID查询学科属性
+ * @param id 学科ID
+ * @returns 学科属性
+ */
+export function fetchProperty(id: number): Promise<AxiosResponse<Response<Property>>> {
+  return httpClient.get(`/knowledgeGraph/property/${id}`);
+}

+ 31 - 0
src/stores/knowledge-graph.ts

@@ -0,0 +1,31 @@
+import { ref, type Ref } from "vue";
+import { defineStore } from "pinia";
+import * as kgService from "@/services/knowledgeGraph.service";
+import * as searchService from "@/services/search.service";
+import type { Property } from "@/types/knowledgeGraph.types";
+import type { SearchResult } from "@/types/search.types";
+
+export const useKnowledgeGraphStore = defineStore('knowledge-graph', () => {
+  const property: Ref<Property> = ref({} as Property);
+
+  const searchResult: Ref<SearchResult | null> = ref(null);
+
+  function fetchProperty(id: number) {
+    kgService.fetchProperty(id).then((resp) => {
+      property.value = resp.data.data;
+    })
+  }
+
+  function search(name: string) {
+    searchService.search(`TP=("${name}")`).then((resp) => {
+      searchResult.value = resp.data.data;
+    });
+  }
+
+  return {
+    property,
+    searchResult,
+    fetchProperty,
+    search,
+  }
+});

+ 5 - 0
src/types/knowledgeGraph.types.ts

@@ -0,0 +1,5 @@
+export interface Property {
+  name: string,
+  docCount: number,
+  keywords: {[index: string]: number}
+}

+ 0 - 1
src/views/knowledge-grapn/KnowLedgeGraphNavView.vue

@@ -1 +0,0 @@
-<template>知识导航</template>

+ 162 - 0
src/views/knowledge-grapn/KnowLedgeGraphView.vue

@@ -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="查&nbsp;&nbsp;询"
+      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>

+ 20 - 0
src/views/knowledge-grapn/components/PropertyComponent.vue

@@ -0,0 +1,20 @@
+<script setup lang="ts">
+export interface Props {
+  name: string;
+  docCount: number,
+  keywords: {[index: string]: number}
+}
+
+defineProps<{
+  data: Props
+}>();
+</script>
+
+<template>
+  <p><span>学科名称:</span><span>{{ data.name }}</span></p>
+  <p><span>文献数量:</span><span>{{ data.docCount }}</span></p>
+  <p>
+    <div>关键词排名</div>
+    <div v-for="(value, key) of data.keywords" :key="key">{{ key }} {{ value }}</div>
+  </p>
+</template>