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

<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>