| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- <script setup lang="ts">
- import { onUnmounted, ref, computed, type Ref, onMounted, reactive, h, watch } from "vue";
- import { useRoute } from "vue-router";
- import { LoadingOutlined } from '@ant-design/icons-vue';
- import { useSideBarStore } from "@/stores/side-bar";
- import SearchBox from "./components/SearchBox.vue";
- import SearchResultToolbar from "./components/SearchResultToolbar.vue";
- import SearchResultList from "./components/SearchResultList.vue";
- import type { SearchRequest } from "@/types/request.types";
- import { useSearchStore } from "@/stores/search.store";
- 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 "@/libs/log.lib";
- const logError = CompLog.logErr("SearchResultView")
- const sideBarStore = useSideBarStore();
- const searchStore = useSearchStore();
- // 当前路由对象
- const route = useRoute();
- // 关键词
- const keyword = ref("");
- // 字段
- const field = ref("TP");
- // 排序
- const sort: Ref<Sort> = ref("Relevance");
- const placeholder = ref("请输入文献主题")
- const pagination = reactive({
- page: 1,
- size: 10,
- })
- 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');
- const resultMode: Ref<ResultMode> = ref('detail');
- const query = ref('');
- // 加载状态
- const spinning = ref(true);
- interface SearchParams {
- query: string;
- yearSelected?: string[];
- authorSelected?: string[];
- unitSelected?: string[];
- sort?: Sort;
- page?: number;
- size?: number;
- }
- /**
- * 根据搜索状态数据执行搜索
- * @param searchParams 搜索状态数据
- */
- function performSearch(searchParams: SearchParams) {
- spinning.value = true;
- let sortParam: Object = { "Relevance": "Relevance" };
- if (searchParams.sort) {
- const sort = searchParams.sort;
- if (sort === 'DateDesc') {
- sortParam = { "year": "DESC" }
- } else if (sort === 'DateAsc') {
- sortParam = { "year": "ASC" }
- } else if (sort === 'CitedDesc') {
- sortParam = { "cited": "DESC" }
- }
- }
- let filters: string[] = []
- if (searchParams.yearSelected && searchParams.yearSelected.length > 0) {
- filters.push(`PY=(${searchParams.yearSelected.join(" ")})`);
- }
- 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
- const size = Math.max(searchParams.size || 10, 10);
- // from
- const from = (Math.max(searchParams.page || 1, 1) - 1) * size;
- const commonParams = {
- query: searchParams.query,
- filter,
- }
- const param: SearchRequest = {
- ...commonParams,
- from,
- size,
- sort: sortParam,
- isSaveHis: true,
- };
- searchStore.search(param)
- .then(() => spinning.value = false)
- .catch((err) => {
- spinning.value = false
- logError(err)
- });
- searchStore.aggYear(commonParams);
- searchStore.aggAuthor(commonParams);
- searchStore.aggUnit(commonParams);
- }
- /**
- * 执行搜索,同时修改url
- */
- function doSearch() {
- let params: SearchRouteParam = {
- type: searchType.value,
- }
- if (searchType.value == 'simple') {
- params['field'] = field.value;
- params['kw'] = keyword.value;
- } else {
- params['query'] = query.value;
- }
- const extras = {
- page: pagination.page,
- size: pagination.size,
- yearSelected: yearChecked.value,
- authorSelected: authorChecked.value,
- unitSelected: unitChecked.value,
- sort: sort.value,
- }
- routeToSearch(params, extras);
- const searchParams: SearchParams = {
- query: query.value,
- yearSelected: yearChecked.value,
- authorSelected: authorChecked.value,
- unitSelected: unitChecked.value,
- page: pagination.page,
- size: pagination.size,
- sort: sort.value,
- };
- performSearch(searchParams);
- }
- function onSimpleSearch() {
- routeToSearch({type: 'simple', field: field.value, kw: keyword.value});
- doSearch();
- }
- function onAdvancedSearch() {
- routeToSearch({ type: 'advanced', query: query.value })
- doSearch();
- }
- /**
- * 根据url包含的信息,初始化状态信息
- */
- function setupState() {
- const queryParam = route.query;
- if (queryParam.type == 'advanced') {
- searchType.value = 'advanced';
- query.value = queryParam.query as string;
- } else {
- searchType.value = 'simple';
- // 初始化关键词
- if (route.query.kw) {
- keyword.value = (route.query.kw as string).trim();
- }
- if (route.query.field) {
- field.value = (route.query.field as string).trim();
- }
- query.value = `${field.value}=(${keyword.value})`
- }
- if (queryParam.yearSelected) {
- let yearSelected: string[];
- if (Array.isArray(queryParam.yearSelected)) {
- yearSelected = queryParam.yearSelected as string[];
- } else {
- yearSelected = [queryParam.yearSelected];
- }
- yearChecked.value = yearSelected;
- }
- if (queryParam.authorSelected) {
- let authorSelected: string[];
- if (Array.isArray(queryParam.authorSelected)) {
- authorSelected = queryParam.authorSelected as string[];
- } else {
- authorSelected = [queryParam.authorSelected];
- }
- authorChecked.value = authorSelected;
- }
- if (queryParam.sort) {
- sort.value = queryParam.sort as Sort;
- }
- if (queryParam.page) {
- pagination.page = parseInt(queryParam.page as string);
- }
- if (queryParam.size) {
- pagination.size = parseInt(queryParam.size as string);
- }
- }
- onMounted(() => {
- // 收起左侧边栏
- sideBarStore.setCollapse(true);
- // 初始化状态
- setupState();
- // 搜索
- doSearch();
- });
- function changeField(value: string) {
- field.value = value;
- query.value = `${field.value}=(${keyword.value})`;
- }
- function changKeyword(value: string) {
- keyword.value = value;
- query.value = `${field.value}=(${keyword.value})`;
- }
- function changeSort(val: any) {
- sort.value = val;
- doSearch();
- }
- function onPaginationChange(page: any, pageSize: any) {
- pagination.page = page;
- pagination.size = pageSize;
- doSearch();
- }
- function onModeChange(mode: ResultMode) {
- resultMode.value = mode;
- }
- function onYearFilterChange(selected: string[]) {
- pagination.page = 1;
- yearChecked.value = selected
- doSearch();
- }
- function onAuthorFilterChange(selected: string[]) {
- pagination.page = 1;
- authorChecked.value = selected
- doSearch();
- }
- function onUnitFilterChange(selected: string[]) {
- pagination.page = 1;
- unitChecked.value = selected
- doSearch()
- }
- watch(field, (newValue) => {
- if (newValue == 'TI') {
- placeholder.value = "请输入文献标题"
- } else if (newValue == 'AU') {
- placeholder.value = "请输入文献作者"
- } else if (newValue == 'KW') {
- placeholder.value = "请输入文献关键词"
- } else if (newValue == 'AB') {
- placeholder.value = "请输入文献摘要"
- } else if (newValue == 'UN') {
- placeholder.value = "请输入文献机构"
- } else {
- placeholder.value = "请输入文献主题"
- }
- });
- onUnmounted(() => {
- sideBarStore.setCollapse(false);
- });
- </script>
- <template>
- <div class="search-result-wrap">
- <div class="search-box-wrap" v-if="searchType == 'simple'">
- <SearchBox
- v-model:keyword="keyword"
- v-model:field="field"
- :placeholder="placeholder"
- @search="onSimpleSearch"
- @update:field="changeField"
- @update:keyword="changKeyword"
- />
- </div>
- <div class="search-box-wrap" v-if="searchType == 'advanced'">
- <AdvancedSearchBox v-model:query="query" @search="onAdvancedSearch" />
- </div>
- <a-row type="flex" class="search-result-main" :gutter="10">
- <a-col :span="5">
- <div class="left-filter-header">
- 筛选
- </div>
- <a-space direction="vertical" style="width: 100%" v-if="searchResult">
- <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">
- <a-spin :spinning="spinning" :indicator="h(LoadingOutlined, { style: { fontSize: '24px', }, spin: true, })">
- <SearchResultToolbar
- v-if="searchResult"
- :data="searchResult"
- v-model:sort="sort"
- v-model:pagination="pagination"
- @update:sort="changeSort"
- @paginationChange="onPaginationChange"
- @modeChange="onModeChange"
- />
- <SearchResultList :data="searchResult" :mode="resultMode" v-if="searchResult" />
- </a-spin>
- </a-col>
- </a-row>
- </div>
- </template>
- <style scoped lang="scss">
- .search-result-wrap {
- margin-top: 20px;
- .search-box-wrap {
- padding: 0 120px;
- }
- .search-result-main {
- margin-top: 20px;
- :deep em {
- color: red;
- font-style: normal;
- }
- }
- @media (max-width: 1024px) {
- .search-box-wrap {
- padding: 0 20px;
- }
- }
- }
- </style>
|