Home.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. <template>
  2. <div class="pages--home">
  3. <div class="home-header" :style="{ paddingBottom: headerAd ? '60px' : '16px', marginBottom: headerAd ? '60px' : '0px' }">
  4. <p class="home-title">· 剑鱼文库<span style="margin: 0 14px;">|</span>上亿级文档资料库 ·</p>
  5. <search class="homeSeach" type="click" @click="goSearch"></search>
  6. <div class="Ad-box">
  7. <Ad :width="0" :loop="true" :code="$envs.inWX ? 'jy-wx-docmember' : 'jy-app-docmember'" :borderRadius="true"
  8. @noData="headerAd = false"></Ad>
  9. </div>
  10. </div>
  11. <!-- <div class="new-group base-group">
  12. <div class="title-group flex-r-c center left">
  13. <span></span>
  14. <h5 class="module-title">最新文档</h5>
  15. </div>
  16. <div class="list-group flex-c-c">
  17. <van-skeleton class="van-loading-skeleton line-style" :row="5" :loading="showLoading.new">
  18. <div class="list-item flex-r-c" v-for="item in pageData.new" :key="item.id" @click="goContent(item)">
  19. <div class="flex flex-r-c center left">
  20. <van-icon :name="'diy-' + item.type" />
  21. <div class="flex">
  22. <div class="van-ellipsis d-title">{{item.title}}</div>
  23. </div>
  24. </div>
  25. <div class="right-info flex-r-c center right">
  26. <van-icon name="diy-iconJianYu" />
  27. <span class="price-text">{{item.money}}</span>
  28. </div>
  29. </div>
  30. </van-skeleton>
  31. </div>
  32. </div> -->
  33. <!-- <div class="hot-group base-group">
  34. <div class="title-group flex-r-c center left">
  35. <span></span>
  36. <h5 class="module-title">热门下载</h5>
  37. </div>
  38. <div class="list-group flex-c-c">
  39. <van-skeleton class="van-loading-skeleton line-style" :row="5" :loading="showLoading.hot">
  40. <div class="list-item flex-r-c" v-for="item in pageData.hot" :key="item.id" @click="goContent(item)">
  41. <div class="flex flex-r-c center left">
  42. <van-icon :name="'diy-' + item.type" />
  43. <div class="flex">
  44. <div class="van-ellipsis d-title">{{item.title}}</div>
  45. </div>
  46. </div>
  47. <div class="right-info flex-r-c center right">
  48. <van-icon name="diy-iconJianYu" />
  49. <span class="price-text">{{item.money}}</span>
  50. </div>
  51. </div>
  52. </van-skeleton>
  53. </div>
  54. </div> -->
  55. <div class="selectedLibrary" v-show="LibraryShow">
  56. <h1>精选文库</h1>
  57. <div class="ad-box">
  58. <Ad :code="$envs.inWX ? 'jy-wx-doc-recommend' : 'jy-app-doc-recommend'" :borderRadius="true"
  59. @noData="LibraryShow = false"></Ad>
  60. </div>
  61. </div>
  62. <div class="group-title">
  63. 热门推荐
  64. </div>
  65. <van-sticky @scroll="onscroll">
  66. </van-sticky>
  67. <div class="tabs fixedTab" v-if="fixedTab" :style="{ top: Offset + 'px' }">
  68. <van-tabs title-active-color="#2ABED1" background="#fff" title-inactive-color="#5F5E64" :line-width="24"
  69. :line-height="2" color="#2ABED1" v-model="tabsActive" @change="tabChange">
  70. <van-tab v-for="(item, index) in tabslist" :name="item.type" :title="item.label" :key="index" />
  71. </van-tabs>
  72. <div class="btn-right">
  73. <van-icon :name="'diy-zhedie'" @click="openScreen" />
  74. </div>
  75. <div class="left"></div>
  76. </div>
  77. <div class="tabs" v-else>
  78. <van-tabs title-active-color="#2ABED1" background="#F5F6F7" title-inactive-color="#5F5E64" :line-width="24"
  79. :line-height="2" color="#2ABED1" v-model="tabsActive" @change="tabChange">
  80. <van-tab v-for="(item, index) in tabslist" :name="item.type" :title="item.label" :key="index" />
  81. </van-tabs>
  82. <div class="btn-right">
  83. <van-icon :name="'diy-zhedie'" @click="openScreen" />
  84. </div>
  85. <div class="left"></div>
  86. </div>
  87. <div class="keep-group base-group">
  88. <!-- <div class="title-group flex-r-c center left">
  89. <span></span>
  90. <h5 class="module-title">热门推荐</h5>
  91. </div> -->
  92. <van-list v-model="hotListState.loading" :finished="hotListState.finished" :offset="hotListState.offset"
  93. @load="onLoad" class="more-list" ref="vanList">
  94. <div>
  95. <div class="list-group card-group flex-c-c" v-for="(item, index) in hotListState.list" :key="index"
  96. @click="goContent(item)">
  97. <van-skeleton avatar avatar-shape="square" class="van-loading-skeleton card-style" :row="4"
  98. :row-width="rowWidth" :loading="showLoading">
  99. <div class="card-item flex-r-c">
  100. <div class="mini-img-group">
  101. <img :src="item.previewImgId || mr_image" alt="">
  102. <van-icon :name="docTypeIcon(item.docFileType)" />
  103. <span class="type-tag"
  104. :class="item.productType === 2 ? 'boutique' : 'free'">
  105. {{ item.productType === 2 ? '付费精品' : '会员免费' }}
  106. </span>
  107. </div>
  108. <div class="flex-c-c">
  109. <div class="flex">
  110. <div class="title-text van-multi-ellipsis--l2">{{ item.docName }}</div>
  111. </div>
  112. <div class="flex-c-c info-text">
  113. <span v-if="item.docTags">{{ item.docTags }}</span>
  114. <div class="info-text-group flex-r-c center left">
  115. <span v-if="item.viewTimes">{{ item.viewTimes }}次浏览</span>
  116. <span v-if="item.docPageSize">共{{ item.docPageSize }}页</span>
  117. <span v-if="item.docFileSize">{{ item.docFileSize | sizeFormatter }}</span>
  118. </div>
  119. </div>
  120. <!-- <div class="money-group flex-r-c center left">
  121. <van-icon class="s20" name="diy-iconJianYu" />
  122. <span class="red-text">{{item.money}}</span>
  123. </div> -->
  124. </div>
  125. </div>
  126. </van-skeleton>
  127. </div>
  128. <Empty v-if="hotListState.list.length === 0 && !hotListState.loading">暂无数据</Empty>
  129. </div>
  130. </van-list>
  131. </div>
  132. <screenPopup ref="screenPopup" v-model="tabsActive" :list="tabslist" @change="popChange"></screenPopup>
  133. </div>
  134. </template>
  135. <script lang="ts">
  136. import { Component, Vue } from 'vue-property-decorator'
  137. import { docTypeConvert } from '@/utils/globalFunctions'
  138. import Search from '@/components/Search.vue'
  139. import Ad from '@/components/Ad.vue'
  140. import screenPopup from '@/components/screenPopup.vue'
  141. import Empty from '@/components/common/Empty.vue'
  142. import { Icon, Skeleton, Tabs, Tab, Sticky, List } from 'vant'
  143. import { mapActions } from 'vuex'
  144. @Component({
  145. name: 'home',
  146. components: {
  147. [Icon.name]: Icon,
  148. [Skeleton.name]: Skeleton,
  149. [Tab.name]: Tab,
  150. [Tabs.name]: Tabs,
  151. [Sticky.name]: Sticky,
  152. [List.name]: List,
  153. Search,
  154. Ad,
  155. Empty,
  156. screenPopup
  157. },
  158. computed: {
  159. // ...mapState('main', {
  160. // pageData: (state: any) => state.homePageData
  161. // })
  162. },
  163. methods: {
  164. ...mapActions({
  165. doSearchRquesst: 'main/doGetRecommend',
  166. getIndexTags: 'main/getIndexTags'
  167. })
  168. // ...mapActions({
  169. // ajaxData: 'main/getHome'
  170. // })
  171. }
  172. })
  173. export default class extends Vue {
  174. doSearchRquesst: any
  175. getIndexTags: any
  176. $envs: any
  177. rowWidth = ['100%', '20%', '40%', '15%']
  178. fixedTab = false
  179. tabslist = []
  180. tabsActive = ''
  181. LibraryShow = true
  182. headerAd = true
  183. hotListState = {
  184. loaded: false,
  185. loading: false,
  186. finished: false,
  187. pageNum: 1,
  188. pageSize: 20,
  189. offset: 80,
  190. list: [],
  191. total: 0
  192. }
  193. mr_image = require('@/assets/image/mr.png')
  194. created () {
  195. // this.ajaxData()
  196. }
  197. mounted () {
  198. const tempH = document.querySelector('.j-header') as HTMLDivElement
  199. if (tempH) {
  200. tempH.style.zIndex = '9999'
  201. }
  202. }
  203. // get showLoading () {
  204. // const s = this.pageData
  205. // return {
  206. // new: !s?.new,
  207. // hot: !s?.hot,
  208. // keep: !s?.keep
  209. // }
  210. // }
  211. get showLoading () { // 骨架占位显示
  212. return this.hotListState.list.length === 0
  213. }
  214. get Offset () {
  215. const tempN = document.querySelector('.j-header.jy-app-header') as HTMLDivElement
  216. if (tempN) {
  217. return tempN.offsetHeight - 1
  218. } else {
  219. return 0
  220. }
  221. }
  222. docTypeIcon (type: string) {
  223. return `diy-${docTypeConvert(type)}`
  224. }
  225. async onLoad () {
  226. if (this.tabslist.length === 0) {
  227. const { data } = await this.getIndexTags()
  228. if (Array.isArray(data)) {
  229. const list: any = data.map(item => {
  230. return {
  231. type: item,
  232. label: item
  233. }
  234. })
  235. this.tabslist = list
  236. if (data.length) {
  237. const i: any = this.tabslist[0]
  238. this.tabsActive = i.type
  239. }
  240. }
  241. }
  242. await this.getList()
  243. }
  244. // onTabClick (name: string) {
  245. // this.tabsActive = name
  246. // this.hotListState.pageNum = 1
  247. // this.hotListState.list = []
  248. // this.hotListState.loaded = false
  249. // this.hotListState.finished = false
  250. // this.onLoad()
  251. // }
  252. onscroll (obj: any) {
  253. if (obj.isFixed) {
  254. this.fixedTab = true
  255. } else {
  256. this.fixedTab = false
  257. }
  258. }
  259. async getList () {
  260. // if (!this.hotListState.value) return
  261. // if (this.hotListState.pageNum === 1) {
  262. // this.$toast.loading({
  263. // forbidClick: true,
  264. // duration: 0
  265. // })
  266. // }
  267. const query = {
  268. tag: this.tabsActive === '全部' ? '' : this.tabsActive,
  269. sort: 'vSort',
  270. num: this.hotListState.pageNum,
  271. size: this.hotListState.pageSize
  272. }
  273. console.log('搜索参数:', query)
  274. this.hotListState.loading = true
  275. const { data } = await this.doSearchRquesst(query)
  276. this.hotListState.loading = false
  277. this.hotListState.loaded = true
  278. // this.$toast.clear()
  279. if (data && Array.isArray(data.list)) {
  280. this.hotListState.pageNum += 1
  281. // this.hotListState.total = data.total
  282. this.hotListState.total = 20 // 目前不支持分页,所以这里写死20条
  283. this.hotListState.list = this.hotListState.list.concat(data.list)
  284. } else {
  285. this.hotListState.finished = true
  286. }
  287. // 数据请求完成(根据页码计算,当前页是否是最后一页)
  288. // 请求完成后,页码就变为了下一页的页面,所以这里要-1
  289. const isLastPage = (this.hotListState.pageNum - 1) * this.hotListState.pageSize >= this.hotListState.total
  290. if (isLastPage) {
  291. this.hotListState.finished = true
  292. }
  293. }
  294. goSearch () {
  295. // this.$router.push({
  296. // name: 'search'
  297. // })
  298. // P572将搜索页移至剑鱼统一搜索入口
  299. location.href = '/jy_mobile/search/middle/docs'
  300. }
  301. goContent (item: any) {
  302. this.$router.push({
  303. name: 'details',
  304. params: {
  305. id: item.docId
  306. }
  307. })
  308. }
  309. async tabChange (item: any) {
  310. // 分类切换
  311. console.log(item)
  312. this.hotListState.list = []
  313. this.hotListState.pageNum = 1
  314. this.hotListState.loaded = false
  315. this.hotListState.finished = false
  316. await this.getList()
  317. }
  318. popChange (val: any) {
  319. this.$nextTick(() => {
  320. this.tabChange(val)
  321. })
  322. }
  323. openScreen () {
  324. (this.$refs.screenPopup as any).show = true
  325. }
  326. }
  327. </script>
  328. <style scoped lang="scss">
  329. .pages--home {
  330. position: relative;
  331. background: #F5F6F7;
  332. padding-bottom: 40px;
  333. box-sizing: border-box;
  334. ::v-deep {
  335. .empty-content-position {
  336. margin-top: 0;
  337. }
  338. }
  339. .homeSeach {
  340. ::v-deep {
  341. .van-search__content {
  342. box-shadow: 0px 4px 4px 0px #0000000D;
  343. }
  344. }
  345. }
  346. .home-header {
  347. background: linear-gradient(180deg, #00AEE6 0%, #05B6CD 38%, #87DFEA 100%);
  348. width: 100%;
  349. // height: 152px;
  350. // min-height: 152px;
  351. padding-bottom: 60px;
  352. display: block;
  353. box-sizing: border-box;
  354. padding-top: 16px;
  355. position: relative;
  356. margin-bottom: 60px;
  357. .home-title {
  358. //styleName: 常规/16;
  359. font-size: 16px;
  360. font-weight: 400;
  361. line-height: 24px;
  362. text-align: center;
  363. color: #FFFFFF;
  364. margin-bottom: 5px;
  365. }
  366. .Ad-box {
  367. width: 359px;
  368. height: 88px;
  369. position: absolute;
  370. top: 100%;
  371. left: 50%;
  372. transform: translate(-50%, -50%);
  373. }
  374. }
  375. .group-title {
  376. padding: 16px 0 6px 12px;
  377. font-size: 18px;
  378. font-weight: 400;
  379. line-height: 26px;
  380. text-align: left;
  381. color: #171826;
  382. }
  383. .selectedLibrary {
  384. h1 {
  385. font-size: 18px;
  386. line-height: 26px;
  387. color: #171826;
  388. font-weight: 400;
  389. padding-left: 12px;
  390. margin-bottom: 6px;
  391. }
  392. .ad-box {
  393. padding-left: 8px;
  394. }
  395. }
  396. .tabs {
  397. margin-bottom: 8px;
  398. padding-right: 30px;
  399. box-sizing: border-box;
  400. position: relative;
  401. ::v-deep {
  402. .van-tabs--line .van-tabs__wrap {
  403. height: 30px;
  404. }
  405. .van-tabs__nav--complete {
  406. padding-left: 6px;
  407. }
  408. .van-tabs__wrap--scrollable .van-tab {
  409. padding: 0 6px;
  410. }
  411. }
  412. .left {
  413. position: absolute;
  414. top: 0;
  415. left: -3px;
  416. width: 12px;
  417. height: 30px;
  418. background-color: #F5F6F7;
  419. }
  420. .btn-right {
  421. position: absolute;
  422. top: 0;
  423. right: -3px;
  424. width: 55px;
  425. height: 30px;
  426. background: linear-gradient(90deg, rgba(245, 246, 247, 0) 0%, #F5F6F7 50%, #F5F6F7);
  427. display: flex;
  428. justify-content: flex-end;
  429. align-items: center;
  430. box-sizing: border-box;
  431. padding-right: 10px;
  432. z-index: 10;
  433. }
  434. }
  435. .fixedTab.tabs {
  436. width: 100%;
  437. position: fixed;
  438. padding-right: 30px;
  439. box-sizing: border-box;
  440. left: 0;
  441. // top: 40px;
  442. z-index: 99;
  443. // padding: 4px 0;
  444. background-color: #fff;
  445. border-bottom: 1px solid #0000000D;
  446. box-shadow: 0px 2px 8px 0px #3693B30D;
  447. ::v-deep {
  448. .van-tabs--line .van-tabs__wrap {
  449. height: 38px;
  450. }
  451. .van-tabs__nav--complete {
  452. padding-left: 6px;
  453. }
  454. .van-tabs__wrap--scrollable .van-tab {
  455. padding: 0 6px;
  456. }
  457. }
  458. .left {
  459. position: absolute;
  460. top: 0;
  461. left: -3px;
  462. width: 12px;
  463. height: 38px;
  464. background-color: #fff;
  465. }
  466. .btn-right {
  467. position: absolute;
  468. top: 0;
  469. right: -3px;
  470. width: 55px;
  471. height: 38px;
  472. background: linear-gradient(90deg, rgba(245, 246, 247, 0) 0%, #F5F6F7 50%);
  473. display: flex;
  474. justify-content: flex-end;
  475. align-items: center;
  476. box-sizing: border-box;
  477. padding-right: 10px;
  478. z-index: 10;
  479. }
  480. }
  481. .module-title {
  482. font-size: 18px;
  483. font-weight: normal;
  484. line-height: 26px;
  485. color: #171826;
  486. }
  487. .d-title {
  488. font-size: 14px;
  489. line-height: 20px;
  490. color: #171826;
  491. }
  492. .price-text {
  493. font-size: 13px;
  494. line-height: 28px;
  495. color: #5F5E64;
  496. }
  497. ::v-deep .van-loading-skeleton {
  498. &.line-style {
  499. .van-skeleton__row {
  500. width: 100% !important;
  501. height: 28px;
  502. }
  503. }
  504. &.card-style {
  505. .van-skeleton__avatar {
  506. width: 100px !important;
  507. height: 124px !important;
  508. }
  509. }
  510. }
  511. @include diy-icon('iconJianYu', 16, 16);
  512. .van-icon-diy-iconJianYu.s20 {
  513. width: 20px;
  514. height: 20px;
  515. }
  516. @include diy-icon('pdf', 18, 18);
  517. @include diy-icon('word', 18, 18);
  518. @include diy-icon('excel', 18, 18);
  519. @include diy-icon('ppt', 18, 18);
  520. @include diy-icon('txt', 18, 18);
  521. @include diy-icon('zhedie', 20, 20);
  522. .base-group {
  523. // padding: 4px 19px 4px 16px;
  524. box-sizing: border-box;
  525. .list-group {
  526. border-radius: 12px;
  527. background: #FFFFFF;
  528. box-sizing: border-box;
  529. padding: 8px 0;
  530. margin: 0 8px 8px 8px;
  531. &.card-group {
  532. padding-left: 12px;
  533. }
  534. .list-item {
  535. padding: 6px 12px;
  536. box-sizing: border-box;
  537. i {
  538. flex-shrink: 0;
  539. margin-right: 4px;
  540. }
  541. .flex {
  542. min-width: 0;
  543. }
  544. .right-info {
  545. margin-left: 4px;
  546. flex-shrink: 0;
  547. }
  548. }
  549. .card-item {
  550. justify-content: flex-start;
  551. // padding: 8px 16px 12px 0;
  552. box-sizing: border-box;
  553. border-bottom: 1px solid rgba(0, 0, 0, 0.05);
  554. &:nth-last-child(1) {
  555. border-bottom-color: transparent;
  556. // padding-bottom: 8px;
  557. }
  558. .money-group {
  559. margin-top: 8px;
  560. }
  561. .mini-img-group {
  562. flex-shrink: 0;
  563. position: relative;
  564. border-radius: 4px;
  565. border: 0.5px solid #0000001A;
  566. width: 75px;
  567. height: 93px;
  568. margin-right: 12px;
  569. overflow: hidden;
  570. img {
  571. width: 100%;
  572. height: 100%;
  573. }
  574. .type-tag {
  575. position: absolute;
  576. left: 0;
  577. top: 0;
  578. border-radius: 4px 0 4px 0;
  579. font-size: 10px;
  580. height: 18px;
  581. display: flex;
  582. align-items: center;
  583. padding: 0 5px;
  584. &.free {
  585. background: linear-gradient(98deg, #FFA674 0%, #F01212 100%);
  586. color: #fff;
  587. }
  588. &.boutique{
  589. background: linear-gradient(270deg, #F1D090 0%, #FAE7CA 100%);
  590. color: #C26F33;
  591. }
  592. }
  593. i {
  594. position: absolute;
  595. right: 0;
  596. bottom: 0;
  597. }
  598. }
  599. .info-text-group {
  600. span {
  601. display: inline-block;
  602. &:last-child {
  603. &::after {
  604. content: unset;
  605. }
  606. }
  607. &::after {
  608. content: "|";
  609. padding: 0 8px;
  610. }
  611. }
  612. }
  613. .info-text {
  614. color: #9B9CA3;
  615. font-family: PingFang SC;
  616. font-size: 12px;
  617. line-height: 22px;
  618. letter-spacing: 0px;
  619. text-align: left;
  620. }
  621. .red-text {
  622. color: #FB483D;
  623. font-family: PingFang SC;
  624. font-size: 14px;
  625. line-height: 20px;
  626. letter-spacing: 0px;
  627. text-align: left;
  628. }
  629. .title-text {
  630. color: #171826;
  631. font-family: PingFang SC;
  632. font-weight: bold;
  633. font-size: 14px;
  634. line-height: 22px;
  635. letter-spacing: 0px;
  636. text-align: left;
  637. overflow: hidden;
  638. text-overflow: ellipsis;
  639. display: -webkit-box;
  640. -webkit-line-clamp: 2;
  641. -webkit-box-orient: vertical;
  642. padding-right: 8px;
  643. box-sizing: border-box;
  644. }
  645. }
  646. }
  647. .title-group {
  648. padding: 16px 0 6px 12px;
  649. margin-bottom: 4px;
  650. box-sizing: border-box;
  651. color: #171826;
  652. font-size: 18px;
  653. line-height: 26px;
  654. letter-spacing: 0px;
  655. text-align: left;
  656. h5 {
  657. color: #171826;
  658. font-size: 18px;
  659. line-height: 26px;
  660. letter-spacing: 0px;
  661. }
  662. span {
  663. display: inline-block;
  664. width: 3px;
  665. height: 16px;
  666. border-radius: 11px;
  667. background: #2ABED1;
  668. margin-right: 8px;
  669. }
  670. }
  671. }
  672. }
  673. </style>