You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
5.5 KiB
225 lines
5.5 KiB
<template>
|
|
<div class="search-mask" @click="onClose"></div>
|
|
<div class="search-container" :class="{'max-search-container': showType === 'max'}">
|
|
<div class="search">
|
|
<img class="icon-search" src="@/assets/icon/search.svg" alt="">
|
|
<input
|
|
class="search-input"
|
|
type="text"
|
|
v-model="searchText"
|
|
@keydown.enter="toSearch"
|
|
placeholder="Search research titles, authors & description"
|
|
>
|
|
<img class="icon-close" src="@/assets/icon/close.svg" @click="onClear" alt="">
|
|
<div v-if="showType === 'max'" class="cancel-btn" @click="onClose">Cancel</div>
|
|
</div>
|
|
<div class="result" v-if="result.research.length > 0 || result.author.length > 0">
|
|
<div class="result-content" v-if="result.research.length > 0">
|
|
<div class="result-title">Research</div>
|
|
<ul class="result-list">
|
|
<li v-for="item in result.research" class="result-item" @click="toDetails(item, 'research')">
|
|
<p v-html="item.title"></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="result-content" v-if="result.author.length > 0">
|
|
<div class="result-title">Author</div>
|
|
<ul class="result-list">
|
|
<li v-for="item in result.author" class="result-item" @click="toDetails(item, 'author')">
|
|
<p v-html="item.name"></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="result-empty" v-if="isSearchEnter && result.research.length == 0 && result.author.length === 0">
|
|
<img class="icon-search" src="@/assets/icon/search.svg" alt="">
|
|
<div class="not-search">No results for '{{ searchText }}'</div>
|
|
<div class="not-tips">We couldn't find anything matching your search.<br />Try again with a different term.</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import {searchTitleApi} from "@/api/research.js";
|
|
|
|
const router = useRouter()
|
|
|
|
const props = defineProps({
|
|
showType: {
|
|
type: String,
|
|
default: 'min'
|
|
}
|
|
})
|
|
|
|
const result = reactive({
|
|
research: [],
|
|
author: []
|
|
})
|
|
|
|
const isSearchEnter = ref(false)
|
|
const searchText = ref('')
|
|
|
|
const toSearch = async () => {
|
|
const { code, data } = await searchTitleApi({
|
|
keyword: searchText.value,
|
|
page: 1,
|
|
limit: 10000,
|
|
})
|
|
if (code === 1) {
|
|
result.research = data.research.data.map(item => ({ ...item, title: htmlRegroup(item.title) }))
|
|
result.author = data.author.data.map(item => ({ ...item, name: htmlRegroup(item.name) }))
|
|
isSearchEnter.value = true
|
|
}
|
|
}
|
|
|
|
const htmlRegroup = (str) => {
|
|
const reg = new RegExp(searchText.value, 'gi');
|
|
return str.replace(reg, `<span style="color: #f00">${searchText.value}</span>`)
|
|
}
|
|
|
|
const onClear = () => {
|
|
searchText.value = ''
|
|
isSearchEnter.value = false
|
|
result.research = []
|
|
result.author = []
|
|
}
|
|
|
|
const toDetails = (item, type) => {
|
|
if (type === 'research') {
|
|
router.push({ path: '/ContentPages', query: { contentId: item.id } })
|
|
} else {
|
|
router.push({ path: '/research', query: { authorId: item.id } })
|
|
}
|
|
emit('close')
|
|
}
|
|
|
|
const emit = defineEmits(['close'])
|
|
|
|
const onClose = () => {
|
|
emit('close')
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.search-container {
|
|
position: relative;
|
|
z-index: 9999;
|
|
width: 100%;
|
|
padding: 18px 20px;
|
|
background: #fff;
|
|
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.15);
|
|
box-sizing: border-box;
|
|
.search {
|
|
height: 28px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
.icon-search {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
.search-input {
|
|
flex: 1;
|
|
margin-left: 16px;
|
|
border: none;
|
|
background-color: transparent;
|
|
font-size: 13px;
|
|
font-family: Raleway;
|
|
}
|
|
.icon-close {
|
|
width: 22px;
|
|
height: 22px;
|
|
cursor: pointer;
|
|
padding: 10px;
|
|
}
|
|
.cancel-btn {
|
|
margin-left: 16px;
|
|
width: 96px;
|
|
height: 38px;
|
|
background: #EFEFEF;
|
|
color: #000;
|
|
font-family: Raleway;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
.result {
|
|
margin-top: 18px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
max-height: calc(100vh - 128px);
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
|
|
.result-title {
|
|
font-family: Raleway;
|
|
font-size: 12px;
|
|
color: rgba(0, 0, 0, .25);
|
|
margin-bottom: 16px;
|
|
}
|
|
.result-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-bottom: 20px;
|
|
.result-item {
|
|
height: 36px;
|
|
padding: 0 20px;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
align-items: center;
|
|
font-family: Libre Bodoni;
|
|
font-size: 12px;
|
|
color: #000;
|
|
cursor: pointer;
|
|
&:hover {
|
|
background-color: #EFEFEF;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@media (max-width: 1280Px) {
|
|
.result {
|
|
max-height: calc(100vh - 82px);
|
|
}
|
|
}
|
|
.result-empty {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
.icon-search {
|
|
width: 32px;
|
|
height: 32px;
|
|
}
|
|
.not-search {
|
|
color: #000;
|
|
font-family: Raleway;
|
|
font-size: 16px;
|
|
margin-top: 13px;
|
|
margin-bottom: 13px;
|
|
}
|
|
.not-tips {
|
|
color: rgba(0, 0, 0, .5);
|
|
font-family: Raleway;
|
|
font-size: 14px;
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
.search-container.max-search-container {
|
|
min-height: 100%;
|
|
}
|
|
.search-mask {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100vh;
|
|
width: 100vw;
|
|
z-index: 999;
|
|
}
|
|
</style> |