123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- <template>
- <div class="pages--search">
- <div class="j-header">
- <search id="mySearch" key="search-page" :defalultValue="listState.value" @input="onInput" @submit="doSearch"></search>
- <van-tabs v-model="docsTypeConf.active"
- v-if="docsTypeConf.list.length"
- title-active-color="#2ABED1"
- title-inactive-color="#5F5E64"
- color="#2ABED1"
- @change="docTypeChange"
- >
- <van-tab v-for="(item, index) in docsTypeConf.list" :key="index" :title="item.label" :name="item.type"></van-tab>
- </van-tabs>
- <div class="sort-list flex-r-c center" v-if="listState.loaded">
- <div
- class="sort-list-item flex-r-c center flex"
- :class="{
- active: item.active,
- reverse: item.sort
- }"
- v-for="(item, index) in sortTypeList"
- :key="index"
- @click="sortAndSearch(item, index)"
- >
- <span class="s-i-label">{{ item.label }}</span>
- <van-icon name="down" class="s-i-icon" />
- </div>
- </div>
- </div>
- <div class="j-main" ref="scrollWrap">
- <van-list
- v-model="listState.loading"
- :finished="listState.finished"
- :offset="listState.offset"
- @load="getList"
- class="more-list calc-height-1px"
- ref="vanList"
- >
- <div>
- <Card
- v-for="(item, index) in listState.list"
- :key="index"
- :title="item.docName"
- :desc="item.docSummary"
- :docType="item.docFileType"
- :highlightKey="highlightKey"
- :price="item.price"
- :subInfo="calcSubInfo(item)"
- @onClick="toDocDetail(item)"
- />
- </div>
- <Empty v-if="listState.list.length === 0 && listState.loaded">暂无数据</Empty>
- </van-list>
- </div>
- </div>
- </template>
- <script lang="ts">
- import { Component, Vue } from 'vue-property-decorator'
- import { Tabs, Tab, Icon, List } from 'vant'
- import Search from '@/components/Search.vue'
- import Card from '@/components/docs-card/Card.vue'
- import Empty from '@/components/common/Empty.vue'
- import { mapState, mapMutations, mapActions } from 'vuex'
- import { dateFormatter } from '@/utils/globalFunctions'
- @Component({
- name: 'search-page',
- components: {
- [Tab.name]: Tab,
- [Tabs.name]: Tabs,
- [List.name]: List,
- [Icon.name]: Icon,
- Search,
- Card,
- Empty
- },
- computed: {
- ...mapState('main', {
- searchState: (state: any) => state.searchPageData
- })
- },
- methods: {
- ...mapMutations({
- saveSearchState: 'main/saveSearchPageState',
- clearSearchState: 'main/clearSearchPageState'
- }),
- ...mapActions({
- doSearchRquesst: 'main/doSearchDocs',
- getIndexTags: 'main/getIndexTags'
- })
- }
- })
- export default class extends Vue {
- protected searchState: any
- protected saveSearchState: any
- protected clearSearchState: any
- protected doSearchRquesst: any
- protected getIndexTags: any
- docsTypeConf = {
- active: '',
- list: []
- }
- sortTypeList = [
- {
- type: 'tSort',
- label: '上传时间',
- sort: 0,
- active: true
- },
- {
- type: 'dSort',
- label: '下载次数',
- sort: 0,
- active: false
- },
- {
- type: 'vSort',
- label: '浏览人数',
- sort: 0,
- active: false
- }
- ]
- listState ={
- value: '',
- loaded: false, // 是否首次加载完成
- loading: false,
- finished: true,
- pageNum: 1,
- pageSize: 10,
- offset: 80,
- scrollTop: 0,
- total: 0,
- list: []
- }
- restored = false // 当前数据是否走过缓存
- get activeSortType () {
- return this.sortTypeList.find(item => {
- return item.active
- })
- }
- get highlightKey () {
- return this.listState.value.split(/\s+/)
- }
- created () {
- this.restored = this.reStoreState()
- if (!this.restored) {
- this.getTags()
- }
- }
- mounted () {
- if (!this.restored) {
- this.onFocus()
- }
- }
- onFocus () {
- console.log('fffff')
- const dom = document.querySelector('#mySearch input') as HTMLInputElement
- if (dom) {
- this.$nextTick(() => {
- setTimeout(() => {
- dom.focus()
- }, 200)
- })
- }
- }
- // 恢复数据至第一次请求的状态(页码等)
- resetListState () {
- const state = {
- loading: false,
- finished: true,
- pageNum: 1,
- total: 0,
- scrollTop: 0,
- list: []
- }
- Object.assign(this.listState, state)
- }
- onInput (search: string) {
- this.listState.value = search
- }
- docTypeChange () {
- if (!this.listState.value) return
- this.resetListState()
- this.setScrollTop()
- this.listState.finished = false
- this.getList()
- }
- sortAndSearch (item: any) {
- if (item.active) {
- // 改变sort
- // item.sort = item.sort ? 0 : 1
- } else {
- this.sortTypeList.forEach(s => {
- s.active = false
- })
- item.active = true
- }
- if (!this.listState.value) return
- this.resetListState()
- this.setScrollTop()
- this.listState.finished = false
- this.getList()
- }
- doSearch () {
- if (!this.listState.value) return
- this.resetListState()
- this.setScrollTop()
- this.listState.finished = false
- this.getList()
- }
- toDocDetail (item: any) {
- const { docId: id } = item
- this.saveState()
- this.$router.push({
- name: 'details',
- params: { id }
- })
- }
- async getTags () {
- const { data } = await this.getIndexTags()
- if (Array.isArray(data)) {
- const list: any = data.map(item => {
- return {
- type: item,
- label: item
- }
- })
- this.docsTypeConf.list = list
- if (data.length) {
- const i: any = this.docsTypeConf.list[0]
- this.docsTypeConf.active = i.type
- }
- }
- return data
- }
- async getList () {
- if (!this.listState.value) return
- const query = {
- keyWord: this.listState.value,
- tag: this.docsTypeConf.active === '全部' ? '' : this.docsTypeConf.active,
- sort: this.activeSortType?.type,
- num: this.listState.pageNum,
- size: this.listState.pageSize
- }
- console.log('搜索参数:', query)
- this.listState.loading = true
- const { data } = await this.doSearchRquesst(query)
- this.listState.loading = false
- this.listState.loaded = true
- this.$toast.clear()
- if (data && Array.isArray(data.list)) {
- this.listState.pageNum += 1
- this.listState.total = data.total
- this.listState.list = this.listState.list.concat(data.list)
- } else {
- this.listState.finished = true
- }
- // 数据请求完成(根据页码计算,当前页是否是最后一页)
- // 请求完成后,页码就变为了下一页的页面,所以这里要-1
- const isLastPage = (this.listState.pageNum - 1) * this.listState.pageSize >= this.listState.total
- if (isLastPage) {
- this.listState.finished = true
- }
- }
- calcSubInfo (item: any) {
- const { uploadDate, downTimes } = item
- const subInfoArr = []
- if (uploadDate !== undefined) {
- subInfoArr.push(dateFormatter(uploadDate, 'yyyy/MM/dd'))
- }
- if (downTimes !== undefined) {
- subInfoArr.push(`${downTimes}次下载`)
- }
- return subInfoArr
- }
- setScrollTop () {
- this.$nextTick(() => {
- const wrapper: any = this.$refs.scrollWrap
- wrapper.scrollTop = this.listState.scrollTop
- })
- }
- reStoreState () {
- const listInfo = this.searchState
- if (!listInfo || Object.keys(listInfo).length === 0) {
- return false
- } else {
- for (const key in listInfo) {
- this.$data[key] = listInfo[key]
- }
- setTimeout(() => {
- this.setScrollTop()
- this.clearSearchState()
- }, 50)
- return true
- }
- }
- saveState () {
- const wrapper: any = this.$refs.scrollWrap
- this.listState.scrollTop = wrapper.scrollTop
- const d = {
- docsTypeConf: this.docsTypeConf,
- sortTypeList: this.sortTypeList,
- listState: this.listState
- }
- this.saveSearchState(d)
- }
- }
- </script>
- <style scoped lang="scss">
- .pages--search {
- background-color: #F5F6F7;
- box-sizing: border-box;
- ::v-deep .van-tabs {
- width: 100%;
- font-size: 14px;
- line-height: 20px;
- }
- .j-header {
- flex-direction: column;
- }
- .sort-list {
- width: 100%;
- font-size: 14px;
- line-height: 20px;
- .sort-list-item {
- padding: 12px 16px;
- &.active {
- color: #2ABED1;
- }
- &.reverse {
- .s-i-icon {
- transform: rotate(180deg);
- }
- }
- .s-i-label {
- margin-right: 4px;
- }
- .s-i-icon {
- font-weight: bold;
- transition: transform .2 ease;
- }
- }
- }
- }
- </style>
|