瀏覽代碼

Merge branch 'master' into dev_20221112

# Conflicts:
#	src/mocks/search.handler.ts
#	src/types/search.types.ts
#	src/views/search/components/SearchResultItem.vue
唐钦 3 年之前
父節點
當前提交
0534c11cba

+ 18 - 0
src/mocks/doc.handler.ts

@@ -0,0 +1,18 @@
+import type { Doc } from "@/types/doc.types";
+import type { Response } from "@/types/response.types";
+import { rest } from "msw";
+import { urlPrefix } from "./mock.settings";
+
+export const handlers = [
+  rest.get(`${urlPrefix}/doc/:id`, (req, res, ctx) => {
+    const response: Response<Doc> = {
+      status: 200,
+      msg: "",
+      data: {
+        id: parseInt(req.params.id as string),
+        title: "文档标题",
+      }
+    };
+    return res(ctx.status(200), ctx.json(response));
+  })
+];

+ 3 - 1
src/mocks/handlers.ts

@@ -1,5 +1,7 @@
 import { handlers as searchHandlers } from "./search.handler";
+import { handlers as docHandlers } from "./doc.handler";
 
 export const handlers = [
-  ...searchHandlers
+  ...searchHandlers,
+  ...docHandlers,
 ];

+ 12 - 0
src/router/index.ts

@@ -44,6 +44,18 @@ const router = createRouter({
       ]
     },
     {
+      path: "/detail",
+      name: "DetailRoot",
+      component: RouteView,
+      children: [
+        {
+          path: ":id",
+          name: "Detail",
+          component: () => import("../views/detail/DetailView.vue"),
+        }
+      ]
+    },
+    {
       path: "/knowledge-graph",
       name: "KnowledgeGraph",
       component: RouteView,

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

@@ -0,0 +1,13 @@
+import type { Doc } from "@/types/doc.types";
+import type { Response } from "@/types/response.types";
+import type { AxiosResponse } from "axios";
+import httpClient from "./httpClient";
+
+/**
+ * 根据文档ID查询文档详情
+ * @param id 文档ID
+ * @returns axios响应
+ */
+export function fetch(id: number): Promise<AxiosResponse<Response<Doc>>> {
+  return httpClient.get<Response<Doc>>(`/doc/${id}`);
+}

+ 21 - 0
src/stores/doc-detail.ts

@@ -0,0 +1,21 @@
+import type { Doc } from "@/types/doc.types";
+import type { Response } from "@/types/response.types";
+import { defineStore } from "pinia";
+import { ref, type Ref } from "vue";
+import * as docService from "@/services/doc.service";
+import type { AxiosResponse } from "axios";
+
+export const useDocDetailStore = defineStore("docDetail", () => {
+  const doc: Ref<Doc | null> = ref(null);
+
+  function fetch(id: number) {
+    return docService.fetch(id).then((resp: AxiosResponse<Response<Doc>>) => {
+      doc.value = resp.data.data;
+    });
+  }
+
+  return {
+    doc,
+    fetch,
+  }
+});

+ 4 - 0
src/types/doc.types.ts

@@ -0,0 +1,4 @@
+export interface Doc {
+  id: number;
+  title: string;
+}

+ 3 - 2
src/types/search.types.ts

@@ -1,4 +1,5 @@
-export interface Doc {
+export interface SearchResultDoc {
+  id: number,
   title: string;
   authors: string[];
   unit: string;
@@ -9,5 +10,5 @@ export interface Doc {
 export interface SearchResult {
   aggs: any;
   total: number;
-  docs: Doc[];
+  docs: SearchResultDoc[];
 }

+ 49 - 0
src/views/detail/DetailView.vue

@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import { useDocDetailStore } from '@/stores/doc-detail';
+import { useSideBarStore } from '@/stores/side-bar';
+import { onMounted, onUnmounted, computed } from 'vue';
+import { useRoute } from 'vue-router';
+import DocCatalog from './components/DocCatalog.vue';
+
+// 当前路由
+const route = useRoute();
+// 左侧边栏状态
+const sideBarStore = useSideBarStore();
+// 文档详情
+const docDetailStore = useDocDetailStore();
+
+const doc = computed(() => docDetailStore.doc);
+
+onMounted(() => {
+  // 收起左侧边栏
+  sideBarStore.setCollapse(true);
+  // 查询文档详情内容
+  const id = parseInt(route.params.id as string);
+  if (id > 0) {
+    docDetailStore.fetch(id);
+  }
+});
+
+onUnmounted(() => {
+  sideBarStore.setCollapse(false);
+});
+
+</script>
+
+<template>
+  <a-row type="flex" :gutter="24">
+    <a-col :span="4">
+      <h2>目录</h2>
+      <DocCatalog></DocCatalog>
+    </a-col>
+    <a-col :span="20">
+      <div v-if="doc" class="doc-wrap">
+        <h2 class="title">{{ doc.title }}</h2>
+        <p>文档详情</p>
+      </div>
+      <div v-else>
+        <a-empty />
+      </div>
+    </a-col>
+  </a-row>
+</template>

+ 50 - 0
src/views/detail/components/DocCatalog.vue

@@ -0,0 +1,50 @@
+<script setup lang="ts">
+import type { TreeProps } from "ant-design-vue";
+import { ref } from "vue";
+
+const expandedKeys = ref<string[]>([]);
+const selectedKeys = ref<string[]>([]);
+const treeData = ref<TreeProps['treeData']>([
+  {
+    title: 'parent 0',
+    key: '0-0',
+    children: [
+      {
+        title: 'leaf 0-0',
+        key: '0-0-0',
+        isLeaf: true,
+      },
+      {
+        title: 'leaf 0-1',
+        key: '0-0-1',
+        isLeaf: true,
+      },
+    ],
+  },
+  {
+    title: 'parent 1',
+    key: '0-1',
+    children: [
+      {
+        title: 'leaf 1-0',
+        key: '0-1-0',
+        isLeaf: true,
+      },
+      {
+        title: 'leaf 1-1',
+        key: '0-1-1',
+        isLeaf: true,
+      },
+    ],
+  },
+]);
+</script>
+
+<template>
+  <a-directory-tree
+    v-model:expandedKeys="expandedKeys"
+    v-model:selectedKeys="selectedKeys"
+    :tree-data="treeData"
+    :show-icon="false"
+  ></a-directory-tree>
+</template>

+ 7 - 3
src/views/search/components/SearchResultItem.vue

@@ -1,10 +1,10 @@
 <script setup lang="ts">
 import type { PropType } from "vue";
-import type { Doc } from "@/types/search.types";
+import type { SearchResultDoc } from "@/types/search.types";
 
 defineProps({
   data: {
-    type: Object as PropType<Doc>,
+    type: Object as PropType<SearchResultDoc>,
     required: true,
   }
 });
@@ -12,7 +12,11 @@ defineProps({
 
 <template>
   <div class="item">
-    <h1>{{ data.title }}</h1>
+    <h1>
+      <RouterLink :to="'/detail/' + data.id" target="_blank">
+        {{ data.title }}
+      </RouterLink>
+    </h1>
     <p>作者:{{ data.authors.join(",") }}</p>
     <p>机构:{{ data.unit }}</p>
     <p>关键词:{{ data.keywords.join(",") }}</p>