Parcourir la source

feature 1001581

智能搜索机构统计与过滤实现
Kevin Jiang il y a 2 ans
Parent
commit
5719ccd488

+ 17 - 2
src/stores/search.store.ts

@@ -8,6 +8,7 @@ export const useSearchStore = defineStore('search', () => {
   const result: Ref<SearchResult | null> = ref(null);
   const yearAggResult: Ref<AggItem[] | null> = ref(null);
   const authorAggResult: Ref<AggItem[] | null> = ref(null);
+  const unitAggResult: Ref<AggItem[] | null> = ref(null);
 
   async function search(request: SearchRequest) {
     return searchService.search(request).then((resp) => {
@@ -17,7 +18,8 @@ export const useSearchStore = defineStore('search', () => {
 
   async function aggYear(request: SearchRequest) {
     try {
-      const resp = await searchService.search(request);
+      const params = { ...request, aggs: { year: { sort: "key/desc" } }, size: 0 }
+      const resp = await searchService.search(params);
       yearAggResult.value = resp.aggs.year || [];
     } catch (err) {
       console.log(err);
@@ -26,19 +28,32 @@ export const useSearchStore = defineStore('search', () => {
 
   async function aggAuthor(request: SearchRequest) {
     try {
-      const resp = await searchService.search(request);
+      const params = { ...request, aggs: { AU: { sort: "count/desc" } }, size: 0 }
+      const resp = await searchService.search(params);
       authorAggResult.value = resp.aggs.AU || [];
     } catch (err) {
       console.log(err);
     }
   }
 
+  async function aggUnit(request: SearchRequest) {
+    try {
+      const params = { ...request, aggs: { UN: { sort: "count/desc" } }, size: 0 }
+      const resp = await searchService.search(params);
+      unitAggResult.value = resp.aggs.UN || [];
+    } catch (err) {
+      console.error(err)
+    }
+  }
+
   return {
     result,
     yearAggResult,
     authorAggResult,
+    unitAggResult,
     search,
     aggYear,
     aggAuthor,
+    aggUnit,
   }
 });

+ 7 - 1
src/views/report/components/reference/ReferenceDraw.vue

@@ -104,7 +104,9 @@ defineExpose({
       <span>关键词:{{ keywords.join(", ") }}</span>
     </template>
     <ReferenceSearchBox @search="onReferenceSearchBoxSearch" />
-    <a-divider />
+    <a-divider orientation="left">
+      <span class="total">章节数量:共 {{ total }} 条</span>
+    </a-divider>
     <SpinComponent :spinning="loading">
       <div v-for="(item, index) in referenceSearchResult" :key="index">
         <ReferenceSearchResultItem :data="item" />
@@ -129,6 +131,10 @@ defineExpose({
   margin: 1.2em 0;
 }
 
+.total {
+  font-size: 0.8em;
+}
+
 .pigination-wrap {
   text-align: right;
   margin-top: 1em;

+ 54 - 36
src/views/search/SearchResultView.vue

@@ -12,6 +12,10 @@ import { routeToSearch } from "@/router";
 import AdvancedSearchBox from "./components/AdvancedSearchBox.vue";
 import type { SearchRouteParam } from "@/types/route.type";
 import type { ResultMode, Sort } from "@/types/search.types";
+import FilterCard from "./components/FilterCard.vue";
+import { CompLog } from "@/helpers/log.helper";
+
+const logError = CompLog.logErr("SearchResultView")
 
 const sideBarStore = useSideBarStore();
 
@@ -32,12 +36,14 @@ const pagination = reactive({
   size: 10,
 })
 
-let authorChecked: Ref<string[]> = ref([]);
-let yearChecked: Ref<string[]> = ref([]);
+const authorChecked: Ref<string[]> = ref([]);
+const yearChecked: Ref<string[]> = ref([]);
+const unitChecked = ref<string[]>();
 
 const searchResult = computed(() => searchStore.result);
 const yearAggResult = computed(() => searchStore.yearAggResult);
 const authorAggResult = computed(() => searchStore.authorAggResult);
+const unitAggResult = computed(() => searchStore.unitAggResult);
 
 const searchType: Ref<'simple' | 'advanced'> = ref('simple');
 
@@ -52,6 +58,7 @@ interface SearchParams {
   query: string;
   yearSelected?: string[];
   authorSelected?: string[];
+  unitSelected?: string[];
   sort?: Sort;
   page?: number;
   size?: number;
@@ -82,6 +89,9 @@ function performSearch(searchParams: SearchParams) {
   if (searchParams.authorSelected && searchParams.authorSelected.length > 0) {
     filters.push(`AU=(${searchParams.authorSelected.join(" OR ")})`);
   }
+  if (searchParams.unitSelected && searchParams.unitSelected.length > 0) {
+    filters.push(`UN=(${searchParams.unitSelected.join(" OR ")})`)
+  }
   const filter = filters.join(" AND ");
 
   // size
@@ -102,17 +112,15 @@ function performSearch(searchParams: SearchParams) {
     isSaveHis: true,
   };
 
-  searchStore.search(param).then(() => spinning.value = false).catch(() => spinning.value = false);
-  searchStore.aggYear({
-    ...commonParams,
-    aggs: { year: { sort: "key/desc" } },
-    size: 0,
-  });
-  searchStore.aggAuthor({
-    ...commonParams,
-    aggs: { AU: { sort: "count/desc" } },
-    size: 0,
-  });
+  searchStore.search(param)
+    .then(() => spinning.value = false)
+    .catch((err) => {
+      spinning.value = false
+      logError(err)
+    });
+  searchStore.aggYear(commonParams);
+  searchStore.aggAuthor(commonParams);
+  searchStore.aggUnit(commonParams);
 }
 
 /**
@@ -134,6 +142,7 @@ function doSearch() {
     size: pagination.size,
     yearSelected: yearChecked.value,
     authorSelected: authorChecked.value,
+    unitSelected: unitChecked.value,
     sort: sort.value,
   }
   routeToSearch(params, extras);
@@ -142,6 +151,7 @@ function doSearch() {
     query: query.value,
     yearSelected: yearChecked.value,
     authorSelected: authorChecked.value,
+    unitSelected: unitChecked.value,
     page: pagination.page,
     size: pagination.size,
     sort: sort.value,
@@ -243,16 +253,24 @@ function onModeChange(mode: ResultMode) {
   resultMode.value = mode;
 }
 
-function changeYearChecked() {
+function onYearFilterChange(selected: string[]) {
   pagination.page = 1;
+  yearChecked.value = selected
   doSearch();
 }
 
-function changeAuthorChecked() {
+function onAuthorFilterChange(selected: string[]) {
   pagination.page = 1;
+  authorChecked.value = selected
   doSearch();
 }
 
+function onUnitFilterChange(selected: string[]) {
+  pagination.page = 1;
+  unitChecked.value = selected
+  doSearch()
+}
+
 onUnmounted(() => {
   sideBarStore.setCollapse(false);
 });
@@ -278,27 +296,27 @@ onUnmounted(() => {
           筛选
         </div>
         <a-space direction="vertical" style="width: 100%" v-if="searchResult">
-          <a-card title="年份">
-            <a-checkbox-group v-model:value="yearChecked" style="width: 100%" @change="changeYearChecked"
-              v-if="yearAggResult && yearAggResult.length > 0">
-              <a-row v-for="(item, index) in yearAggResult" :key="index">
-                <a-col :span="20">
-                  <a-checkbox :value="item.key">{{ item.key }}</a-checkbox>
-                </a-col>
-                <a-col :span="4"> {{ item.count }}</a-col>
-              </a-row>
-            </a-checkbox-group>
-          </a-card>
-          <a-card title="作者">
-            <a-checkbox-group v-model:value="authorChecked" style="width: 100%" @change="changeAuthorChecked">
-              <a-row v-for="(item, index) in authorAggResult" :key="index">
-                <a-col :span="20">
-                  <a-checkbox :value="item.key">{{ item.key }}</a-checkbox>
-                </a-col>
-                <a-col :span="4"> {{ item.count }}</a-col>
-              </a-row>
-            </a-checkbox-group>
-          </a-card>
+          <FilterCard
+            v-if="yearAggResult"
+            title="时间"
+            :aggs="yearAggResult"
+            :checked="yearChecked"
+            @change="onYearFilterChange"
+          />
+          <FilterCard
+            v-if="authorAggResult"
+            title="作者"
+            :aggs="authorAggResult"
+            :checked="authorChecked"
+            @change="onAuthorFilterChange"
+          />
+          <FilterCard
+            v-if="unitAggResult"
+            title="机构"
+            :aggs="unitAggResult"
+            :checked="unitChecked"
+            @change="onUnitFilterChange"
+          />
         </a-space>
       </a-col>
       <a-col :span="19">

+ 43 - 0
src/views/search/components/FilterCard.vue

@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import type { AggItem } from "@/types/search.types";
+import { onMounted, ref, type PropType } from "vue"
+
+const props = defineProps({
+  title: String,
+  checked: {
+    type: Array<String>,
+    default: [],
+  },
+  aggs: {
+    type: Object as PropType<AggItem[]>,
+    required: true,
+  }
+});
+
+const selected = ref<string[]>([])
+
+const emits = defineEmits<{
+  (e: "change", selected: string[]): void;
+}>()
+
+function onChange(selected: string[]) {
+  emits("change", selected)
+}
+
+onMounted(() => {
+  selected.value = props.checked as string[]
+})
+</script>
+
+<template>
+  <a-card :title="title">
+    <a-checkbox-group v-model:value="selected" style="width: 100%" @change="onChange">
+      <a-row v-for="(item, index) in aggs" :key="index">
+        <a-col :span="20">
+          <a-checkbox :value="item.key">{{ item.key }}</a-checkbox>
+        </a-col>
+        <a-col :span="4"> {{ item.count }}</a-col>
+      </a-row>
+    </a-checkbox-group>
+  </a-card>
+</template>