wenmenghao 1 년 전
부모
커밋
424c1b4766

+ 1 - 1
jydocs-mobile/src/api/ajax.ts

@@ -15,7 +15,7 @@ $ajax.interceptors.request.use(config => {
   // 在请求发送之前做一些事
   // console.log('--发送之前--', config)
   if (config.method === 'post' || config.method === 'POST') {
-    if (typeof config.data !== 'string') {
+    if (typeof config.data !== 'string' && !config.url?.includes('getJyAdList')) {
       config.data = qs.stringify(config.data)
     }
   }

+ 8 - 1
jydocs-mobile/src/api/index.ts

@@ -13,5 +13,12 @@ export function getWxSdkSign (data: any) {
     data
   })
 }
-
+export function getJyAdList (data: any) {
+  return request({
+    baseURL: '',
+    url: '/publicapply/free/getJyAdList',
+    method: 'post',
+    data
+  })
+}
 export default request

+ 4 - 4
jydocs-mobile/src/api/main.ts

@@ -25,12 +25,12 @@ export function getIndexTags () {
   })
 }
 
-export function doSearchDocs (data: any) {
-  data = qs.stringify(data)
+export function doSearchDocs (params: any) {
+  // data = qs.stringify(data)
   return $request({
     url: '/search',
-    method: 'POST',
-    data
+    method: 'GET',
+    params
   })
 }
 

BIN
jydocs-mobile/src/assets/icon/clear.png


BIN
jydocs-mobile/src/assets/icon/fright.png


BIN
jydocs-mobile/src/assets/icon/zhedie.png


BIN
jydocs-mobile/src/assets/image/sw-img.png


+ 52 - 11
jydocs-mobile/src/components/Ad.vue

@@ -1,26 +1,60 @@
 <template>
-  <div class="Ad" @click="openLink">
-    <img :src="imgUrl" alt="">
+  <div class="Ad">
+    <van-swipe
+      class="my-swipe"
+      :loop="loop"
+      :show-indicators="indicators"
+      ref="swipe"
+      :width="width_"
+    >
+      <van-swipe-item
+        v-for="(item, index) in list"
+        :key="index"
+      >
+        <div class="item" @click="openLink(item.s_link)" :class="{'Ad-mr-8':width < 300 && width!== 0}" >
+          <img :class="{'item-img':true, 'completelyfill':width === 0}" :src="item.s_pic" alt="">
+        </div>
+      </van-swipe-item>
+    </van-swipe>
   </div>
 </template>
 <script lang="ts">
+import { px2px } from '@/utils/view'
+import { getJyAdList } from '@/api'
+import { Swipe, SwipeItem } from 'vant'
 import { Component, Vue, Prop } from 'vue-property-decorator'
 // @ is an alias to /src
   @Component({
     name: 'Ad',
     components: {
+      [Swipe.name]: Swipe,
+      [SwipeItem.name]: SwipeItem
     }
   })
 export default class Ad extends Vue {
-    @Prop({ default: '' }) code?: string | undefined;
-    imgUrl = ''
-    link = ''
-    getData () {
-      this.imgUrl = ''
+    @Prop({ default: '' }) code?: string;
+    @Prop({ default: 142 }) width?: number;
+    @Prop({ default: false }) loop?: boolean;
+    @Prop({ default: false }) indicators?: boolean;
+    list = []
+    async getData () {
+      // this.imgUrl = require('@/assets/image/guanggao.png')
+      const { data } = await getJyAdList({ codes: [this.code] })
+      this.list = data.data[this.code as string]
+      if (this.list.length === 0) {
+        this.$emit('noData')
+      }
     }
 
-    openLink () {
-      window.location.href = this.link
+    get width_ () {
+      return Number(px2px(this.width as number).replace('px', ''))
+    }
+
+    openLink (link: string) {
+      if (!link) {
+        return
+      }
+      window.location.href = link
     }
 
     created () {
@@ -31,9 +65,16 @@ export default class Ad extends Vue {
 
 <style scoped lang="scss">
 .Ad{
-  img{
+  .completelyfill{
     width: 100%;
   }
+  .Ad-mr-8{
+    margin-right: 8px;
+  }
+::v-deep{
+  .van-swipe__indicator--active{
+    background-color: #fff;
+  }
+}
 }
-
 </style>

+ 10 - 2
jydocs-mobile/src/components/Search.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="search-container van-fade-an">
       <div class="click-pop" v-if="type === 'click'"  @click="onClick"></div>
-      <van-search @input="$emit('input', $event)" @search="onSearch" class="my-search" left-icon="diy-search" v-model="input" placeholder="搜索文档" />
+      <van-search @input="$emit('input', $event)" @search="onSearch" class="my-search" :class="{'isfocus' : isfocus}" left-icon="diy-search" @focus="isfocus = true" @blur="isfocus = false" v-model="input" placeholder="搜索文档" />
   </div>
 </template>
 
@@ -21,6 +21,7 @@ export default class Empty extends Vue {
     @Prop({ default: 'input' }) type?: string | undefined;
     @Prop({ default: '' }) defalultValue?: string | undefined;
     input = ''
+    isfocus = false
 
     created () {
       this.setSearchContent(this.defalultValue || '')
@@ -64,6 +65,13 @@ export default class Empty extends Vue {
 .search-container {
   width: 100%;
 }
+.isfocus.my-search{
+  &::v-deep.van-search {
+    .van-search__content{
+      border: 1px solid #2ABED1;
+    }
+  }
+}
 .my-search {
   &::v-deep.van-search {
     padding: 7px 16px;
@@ -72,7 +80,7 @@ export default class Empty extends Vue {
       border-radius: 8px;
       background: #F5F6F7;
       border: 1px solid rgba(0, 0, 0, 0.05);
-      box-shadow: 0px 4px 4px 0px #0000000D;
+      // box-shadow: 0px 4px 4px 0px #0000000D;
 
     }
     .van-cell {

+ 13 - 2
jydocs-mobile/src/components/docs-card/Card.vue

@@ -46,7 +46,7 @@
             v-for="(item, index) in subInfo"
             :key="index"
           >{{ item }}</span>
-          <slot name="leftEnd"></slot>
+          <slot name="leftEnd"><div class="jydocs_vip" v-if="isVip">会员免费</div></slot>
         </div>
         <div class="c-f-right flex-r-c">
           <slot name="price"><Price :price="price" v-if="price !== -1" /></slot>
@@ -77,7 +77,7 @@ export default class DocsCard extends Vue {
   @Prop({ default: '' }) imageSrc?: string | undefined;
   @Prop({ default: '' }) uploader?: string | undefined;
   @Prop({ default: -1 }) price?: string | number;
-
+  @Prop({ default: false }) isVip?: boolean;
   @Prop({
     type: Array,
     default () {
@@ -121,6 +121,17 @@ export default class DocsCard extends Vue {
   padding: 16px;
   box-sizing: border-box;
   background-color: #fff;
+  .jydocs_vip{
+    background: linear-gradient(98deg, #FFA674 0%, #F01212 100%);
+    width: 50px;
+    height: 18px;
+    border-radius: 4px;
+    display: inline-flex;
+    justify-content: center;
+    align-items: center;
+    color: #fff;
+    font-size: 10px;
+  }
   &.oneline {
     padding: 8px 16px;
     .docs-header {

+ 49 - 0
jydocs-mobile/src/components/filters/DropdownLayout.vue

@@ -0,0 +1,49 @@
+<template>
+  <div
+    class="j-container layout-card"
+    ref="layoutCard"
+    :style="{ 'max-height': maxHeight }"
+  >
+    <div class="j-main">
+      <slot name="default"></slot>
+      <slot name="main"></slot>
+    </div>
+    <div class="j-footer">
+      <slot name="footer">
+        <div class="j-button-group height40">
+          <button class="j-button-cancel" @click="$emit('cancel')">
+            {{ cancelText }}
+          </button>
+          <button class="j-button-confirm" @click="$emit('confirm')">
+            {{ confirmText }}
+          </button>
+        </div>
+      </slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+export default {
+  name: 'DropdownLayout',
+  props: {
+    maxHeight: {
+      type: [String, Number],
+      default: '60vh'
+    },
+    cancelText: {
+      type: String,
+      default: '重置'
+    },
+    confirmText: {
+      type: String,
+      default: '确认'
+    }
+  }
+}
+</script>
+<style lang="scss">
+.j-button-cancel,.j-button-confirm{
+  border-radius: 4px;
+}
+</style>

+ 60 - 0
jydocs-mobile/src/components/filters/Fselect.vue

@@ -0,0 +1,60 @@
+<template>
+  <div class="f-select">
+    <div class="select_item" @click="choose(item)" v-for="(item, index) in list" :key="index">
+     <div class="label" :class="{active:value === item.value}">{{item.label}}</div>
+     <van-icon :name="'diy-fright'" v-show="value === item.value" />
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue, Prop } from 'vue-property-decorator'
+import { Icon } from 'vant'
+// @ is an alias to /src
+@Component({
+  name: 'Fselect',
+  components: {
+    [Icon.name]: Icon
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  }
+
+})
+export default class extends Vue {
+  @Prop({ default: [] }) list?: any;
+  @Prop({ default: 0 }) value?: number;
+  choose (item: any) {
+    this.$emit('change', item.value)
+  }
+}
+
+</script>
+
+<style lang="scss" scoped>
+@include diy-icon('fright', 24, 24);
+
+.f-select{
+  padding-left:16px;
+  .select_item{
+    height: 44px;
+    background-color: #fff;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    border-bottom: 0.5px solid #0000000D;
+    padding-right: 10px;
+    box-sizing: border-box;
+    .label{
+      font-size: 14px;
+      color: #5F5E64;
+    }
+    .label.active{
+      color: #2ABED1;
+    }
+
+  }
+
+}
+</style>

+ 142 - 0
jydocs-mobile/src/components/filters/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <van-dropdown-menu ref="dropdownMenu" class="dropdown-menu-arrow" :close-on-click-outside="false">
+    <van-dropdown-item ref="formatDropdown" title-class="format" :title="chooseFormat | f_format" get-container="body"
+      @open="doOpen('format')" @opened="openedDropDown('format')">
+      <DropdownLayout maxHeight="50vh" @cancel="onReset('format')" @confirm="onConfirm('format')">
+        <Fselect v-model="chooseFormat" :list="formatList"></fselect>
+      </DropdownLayout>
+    </van-dropdown-item>
+    <van-dropdown-item ref="typeDropdown" title-class="type" :title="chooseType | f_type" get-container="type"
+      @open="doOpen('type')" @opened="openedDropDown('type')">
+      <DropdownLayout maxHeight="50vh" @cancel="onReset('type')" @confirm="onConfirm('type')">
+        <Fselect v-model="chooseType" :list="typeList"></fselect>
+      </DropdownLayout>
+    </van-dropdown-item>
+  </van-dropdown-menu>
+</template>
+
+<script lang="ts">
+import { Component, Vue, Prop } from 'vue-property-decorator'
+import { DropdownMenu, DropdownItem } from 'vant'
+import DropdownLayout from './DropdownLayout.vue'
+import Fselect from './Fselect.vue'
+// @ is an alias to /src
+@Component({
+  name: 'filters',
+  components: {
+    [DropdownMenu.name]: DropdownMenu,
+    [DropdownItem.name]: DropdownItem,
+    DropdownLayout,
+    Fselect
+  },
+  filters: {
+    f_format (value: number) {
+      if (value === 0) {
+        return '全部格式'
+      } else if (value === 1) {
+        return 'doc'
+      } else if (value === 2) {
+        return 'pdf'
+      } else if (value === 3) {
+        return 'xls'
+      } else if (value === 4) {
+        return 'ppt'
+      } else if (value === 5) {
+        return 'txt'
+      }
+    },
+    f_type (value: number) {
+      if (value === 0) {
+        return '全部类型'
+      } else if (value === 1) {
+        return '会员免费'
+      } else if (value === 2) {
+        return '精品'
+      } else if (value === 3) {
+        return '免费'
+      }
+    }
+  }
+
+})
+export default class extends Vue {
+  // @Prop({ default: [] }) list?: any;
+  @Prop({ default: '' }) value?: any;
+  formatList = [
+    { label: '全部格式', value: 0 },
+    { label: 'doc', value: 1 },
+    { label: 'pdf', value: 2 },
+    { label: 'xls', value: 3 },
+    { label: 'ppt', value: 4 },
+    { label: 'txt', value: 5 }
+  ]
+
+  typeList = [
+    { label: '全部类型', value: 0 },
+    { label: '精品', value: 2 },
+    { label: '会员免费', value: 1 }
+    // { label: '免费', value: 3 }
+  ]
+
+  chooseFormat = 0
+  chooseType = 0
+  doOpen () {
+    console.log('展开')
+  }
+
+  openedDropDown () {
+    console.log('展开后')
+  }
+
+  onReset (type: string) {
+    console.log('重置')
+    if (type === 'format') {
+      this.chooseFormat = 0
+    } else {
+      this.chooseType = 0
+    }
+    // this.chooseFormat = 0
+    // this.chooseType = 0
+    this.$emit('onReset', { format: this.chooseFormat, type: this.chooseType })
+    const Dropdown = this.$refs[`${type}Dropdown`] as any
+    Dropdown.toggle(false)
+  }
+
+  onConfirm (type: string) {
+    console.log('确定')
+    this.$emit('confirm', { format: this.chooseFormat, type: this.chooseType })
+    const Dropdown = this.$refs[`${type}Dropdown`] as any
+    Dropdown.toggle(false)
+  }
+}
+
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+  .van-dropdown-menu__title--active.van-dropdown-menu__title {
+    color: #2CB7CA;
+  }
+  .van-dropdown-menu__bar{
+    height: 44px;
+    box-shadow: none;
+  }
+  .van-dropdown-menu__title{
+    color: #5F5E64;
+    font-size: 14px;
+  }
+  .van-dropdown-menu__title::after{
+    border-color: transparent transparent #C0C4CC #C0C4CC;
+
+  }
+  .van-dropdown-menu__title--active.van-dropdown-menu__title::after{
+    border-color: transparent transparent #2CB7CA #2CB7CA;
+
+  }
+  .van-dropdown-menu__item{
+    justify-content: left;
+    padding-left: 8px;
+  }
+}
+
+</style>

+ 110 - 0
jydocs-mobile/src/components/popupbox/index.vue

@@ -0,0 +1,110 @@
+<template>
+  <div class="popupbox">
+    <van-popup v-model="value">
+      <div class="pop_content">
+        <div class="head">{{ title }}</div>
+        <div class="content">
+          <div class="text" v-html="text"></div>
+          <div v-if="type === 'download'">
+            <div class="downbtn" @click="$emit('downLoad')">下载文档</div>
+             <div class="btnUnder"><slot></slot></div>
+          </div>
+        </div>
+        <div class="foot" v-if="showFoot">
+          <div class="left_btn" v-if="leftbtnShow" @click="$emit('leftBtn')">{{ leftbtn }}</div>
+          <div class="right_btn hightlight" v-if="rightbtnShow" @click="$emit('rightBtn')">{{ rightbtn }}</div>
+        </div>
+      </div>
+    </van-popup>
+  </div>
+</template>
+
+<script lang="ts">
+import { Popup } from 'vant'
+import { Component, Vue, Prop } from 'vue-property-decorator'
+
+// @ is an alias to /src
+@Component({
+  name: 'popupbox',
+  components: {
+    [Popup.name]: Popup
+  }
+})
+export default class extends Vue {
+  @Prop({ default: '' }) type?: string
+  @Prop({ default: '' }) title?: string
+  @Prop({ default: '' }) leftbtn?: string
+  @Prop({ default: '' }) rightbtn?: string
+  @Prop({ default: '' }) text?: any
+  @Prop({ default: true }) leftbtnShow?: boolean
+  @Prop({ default: true }) rightbtnShow?: boolean
+  @Prop({ default: true }) showFoot?: boolean
+  value = true
+}
+</script>
+
+<style lang="scss" scoped>
+.popupbox {
+  ::v-deep.van-popup {
+    border-radius: 8px;
+  }
+
+  .pop_content {
+    padding-top: 24px;
+    width: 333px;
+    background-color: #fff;
+    border-radius: 8px;
+
+    .head {
+      font-size: 18px;
+      font-weight: 400;
+      line-height: 26px;
+      text-align: center;
+      color: #171826;
+    }
+    .content{
+      padding: 8px 24px 24px 24px;
+      font-size: 15px;
+      line-height: 22px;
+      color: #5F5E64;
+      .downbtn{
+        width: 124px;
+        height: 32px;
+        background-color: #2ABED1;
+        color: #fff;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        border-radius: 4px;
+        margin: 8px;
+      }
+      .btnUnder{
+        margin-top: 8px;
+        font-size: 15px;
+        line-height: 22px;
+        color: #5F5E64;
+        text-align: center;
+      }
+    }
+    .foot{
+      height: 46px;
+      display: flex;
+      border-top: 0.5px solid #0000001A;
+      div{
+        flex: 1;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 18px;
+        color: #171826;
+      }
+      .left_btn{
+        border-right: 0.5px solid #0000001A;
+      }
+    }
+  }
+  .hightlight{
+        color:#2ABED1;
+      }
+}
+</style>

+ 112 - 0
jydocs-mobile/src/components/screenPopup.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="screenPopup">
+    <van-popup class="popup-con" v-model="show" position="right">
+      <div class="content">
+        <div class="head">
+          <div class="title-group">
+            <div class="title-line"></div>
+            <div class="title">请选择分类</div>
+          </div>
+          <van-icon class="rotate" :name="'diy-zhedie'" @click="show = false" />
+        </div>
+        <div class="chooseBox">
+          <div :class="{ chooseItem: true, active: value === item.type }" v-for="( item, index ) in list" :key="index" @click = "choose(item)">{{item.label}}</div>
+        </div>
+      </div>
+    </van-popup>
+  </div>
+</template>
+<script lang="ts">
+import { Popup, Icon } from 'vant'
+import { Component, Vue, Prop } from 'vue-property-decorator'
+// @ is an alias to /src
+@Component({
+  name: 'screenPopup',
+  components: {
+    [Popup.name]: Popup,
+    [Icon.name]: Icon
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  }
+})
+export default class extends Vue {
+  @Prop({ default: [] }) list?: any;
+  @Prop({ default: '' }) value?: any;
+  show = false
+  choose (item: any) {
+    this.$emit('change', item.type)
+    this.show = false
+  }
+}
+</script>
+
+<style scoped lang="scss">
+ @include diy-icon('zhedie', 20, 20);
+.screenPopup{
+  .content{
+    width: 280px;
+    height: 100vh;
+    background-color: #F5F6F7;
+    .head{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      box-sizing: border-box;
+      height: 54px;
+      padding: 0 16px;
+      border-bottom: 1px solid  #0000000D;
+      .title-group{
+        display: flex;
+        align-items: center;
+        .title{
+        font-size: 18px;
+        line-height: 26px;
+        font-weight: 400;
+        color: #171826;
+      }
+      .title-line{
+        width: 3px;
+        height: 16px;
+        border-radius: 11px;
+        background-color: #2ABED1;
+        margin-right: 8px;
+      }
+
+      }
+      .rotate{
+        transform: rotate(180deg);
+      }
+    }
+    .chooseBox{
+      box-sizing: border-box;
+      padding: 12px 0 12px 12px;
+      overflow: hidden;
+      .chooseItem{
+        float: left;
+        margin-right: 12px;
+        margin-bottom: 10px;
+        width: 122px;
+        height: 44px;
+        border-radius: 4px;
+        background-color: #fff;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        box-sizing: border-box;
+        padding: 0 12px;
+        font-size: 14px;
+        color: #171826;
+        line-height: 20px;
+        border: 0.5px solid #0000001A;
+      }
+      .active.chooseItem{
+        background-color: #2ABED1;
+        color: #fff;
+        border: 0.5px solid #2ABED1;
+      }
+    }
+  }
+}
+</style>

+ 69 - 0
jydocs-mobile/src/utils/view.ts

@@ -0,0 +1,69 @@
+/**
+ * 该函数用于将Px换算为Vw
+ * @param {string | number} px 设计图中元素尺寸
+ * @param {string} viewportUnit 转换后单位,默认vw
+ * @param {object} config  px2viewport配置项
+ * @param {number} config.viewportWidth 设计图尺寸
+ * @param {number} config.unitPrecision 转换后保留位数
+ * @returns {string} 转换后结果
+ */
+export function px2viewport (
+  px: string | number,
+  viewportUnit = 'vw',
+  config: { viewportWidth: number; unitPrecision: number } = {
+    viewportWidth: 375,
+    unitPrecision: 3
+  }
+): string {
+  try {
+    return (
+      ((Number(String(px).replace('px', '')) / config.viewportWidth) * 100).toFixed(
+        config.unitPrecision
+      ) + viewportUnit
+    )
+  } catch (e) {
+    return ''
+  }
+}
+
+/**
+ * 该函数用于将Vw换算为Px
+ * @param {string | number} vw 元素vw尺寸
+ * @param {string} viewportUnit 转换后单位,默认px
+ * @param {object} config  px2viewport配置项
+ * @param {number} config.viewportWidth 屏幕尺寸
+ * @param {number} config.unitPrecision 转换后保留位数
+ * @returns {string} 转换后结果
+ */
+export function vw2px (
+  vw: string | number,
+  viewportUnit = 'px',
+  config: { viewportWidth: number; unitPrecision: number } = {
+    viewportWidth: document.body.clientWidth || 375,
+    unitPrecision: 3
+  }
+): string {
+  try {
+    return (
+      ((Number(String(vw).replace('vw', '')) * config.viewportWidth) / 100).toFixed(
+        config.unitPrecision
+      ) + viewportUnit
+    )
+  } catch (e) {
+    return ''
+  }
+}
+
+/**
+ * 该函数用于将设计图Px换算为实际渲染Px
+ * @param {string | number} px 设计图px
+ * @param {string} viewportUnit 转换后单位,默认px
+ * @returns {string} 转换后结果
+ */
+export function px2px (px: string | number, viewportUnit = 'px'): string {
+  try {
+    return vw2px(px2viewport(px), viewportUnit)
+  } catch (e) {
+    return ''
+  }
+}

+ 359 - 111
jydocs-mobile/src/views/Home.vue

@@ -2,9 +2,9 @@
   <div class="pages--home">
     <div class="home-header">
       <p class="home-title">· 剑鱼文库<span style="margin: 0 14px;">|</span>上亿级文档资料库 ·</p>
-      <search type="click" @click="goSearch"></search>
+      <search class="homeSeach" type="click" @click="goSearch"></search>
       <div class="Ad-box">
-        <Ad></Ad>
+        <Ad :width="0" :loop="true" :code="$envs.inWX ? 'jy-wx-docmember' : 'jy-app-docmember'"></Ad>
       </div>
     </div>
     <!-- <div class="new-group base-group">
@@ -51,123 +51,248 @@
         </van-skeleton>
       </div>
     </div> -->
-    <div class="selectedLibrary">
+    <div class="selectedLibrary" v-show="LibraryShow">
       <h1>精选文库</h1>
-      <van-swipe
-      class="my-swipe"
-      :loop="false"
-      :show-indicators="false"
-      ref="swipe"
-      :width="150"
-    >
-      <van-swipe-item
-        :style="{ width: 'auto' }"
-      >
-        <div>
-
-        </div>
-      </van-swipe-item>
-    </van-swipe>
-
+      <div class="ad-box">
+        <Ad :code="$envs.inWX ? 'jy-wx-doc-recommend' : 'jy-app-doc-recommend'" @noData="LibraryShow = false"></Ad>
+      </div>
+    </div>
+    <div class="group-title">
+      热门推荐
     </div>
+    <van-sticky :offset-top="Offset">
+      <div class="tabs">
+        <van-tabs title-active-color="#2ABED1" background="#F5F6F7" title-inactive-color="#5F5E64" :line-width="24"
+          :line-height="2" color="#2ABED1" v-model="tabsActive" @change="tabChange">
+          <van-tab v-for="(item, index) in tabslist" :name="item.type" :title="item.label" :key="index" />
+        </van-tabs>
+        <div class="btn-right">
+          <van-icon :name="'diy-zhedie'" @click="openScreen" />
+        </div>
+        <div class="left"></div>
+      </div>
+    </van-sticky>
     <div class="keep-group base-group">
-      <div class="title-group flex-r-c center left">
+      <!-- <div class="title-group flex-r-c center left">
         <span></span>
-        <h5 class="module-title">精选推荐</h5>
-      </div>
-      <div class="list-group card-group flex-c-c">
-        <van-skeleton avatar avatar-shape="square" class="van-loading-skeleton card-style"
-            :row="4"
-            :row-width="rowWidth"
-            :loading="showLoading.keep">
-          <div class="card-item flex-r-c"  v-for="item in pageData.keep" :key="item.id" @click="goContent(item)">
-          <div class="mini-img-group">
-            <img :src="item.img" alt="">
-            <van-icon :name="'diy-' + item.type" />
-          </div>
-          <div class="flex-c-c">
-            <div class="flex">
-              <div class="title-text van-multi-ellipsis--l2">{{item.title}}</div>
-            </div>
-            <div class="flex-c-c info-text">
-              <span v-if="item.contribution">贡献者: {{item.contribution}}</span>
-              <div class="info-text-group flex-r-c center left">
-                <span v-if="item.down">{{item.down}}次下载</span>
-                <span v-if="item.page">共{{item.page}}页</span>
-                <span v-if="item.size">{{item.size | sizeFormatter}}</span>
-              </div>
-            </div>
-            <div class="money-group flex-r-c center left">
+        <h5 class="module-title">热门推荐</h5>
+      </div> -->
+      <van-list v-model="hotListState.loading" :finished="hotListState.finished" :offset="hotListState.offset"
+        @load="onLoad" class="more-list" ref="vanList">
+        <div>
+          <div class="list-group card-group flex-c-c" v-for="item in hotListState.list" :key="item.docId"
+            @click="goContent(item)">
+            <van-skeleton avatar avatar-shape="square" class="van-loading-skeleton card-style" :row="4"
+              :row-width="rowWidth" :loading="showLoading">
+              <div class="card-item flex-r-c">
+                <div class="mini-img-group">
+                  <img :src="item.previewImgId" alt="">
+                  <van-icon :name="docTypeIcon(item.docFileType) " />
+                  <div class="vip-ic" v-if="item.productType === 1">会员免费</div>
+                </div>
+                <div class="flex-c-c">
+                  <div class="flex">
+                    <div class="title-text van-multi-ellipsis--l2">{{ item.docName }}</div>
+                  </div>
+                  <div class="flex-c-c info-text">
+                    <span v-if="item.docTags">{{ item.docTags }}</span>
+                    <div class="info-text-group flex-r-c center left">
+                      <span v-if="item.viewTimes">{{ item.viewTimes }}次浏览</span>
+                      <span v-if="item.docPageSize">共{{ item.docPageSize }}页</span>
+                      <span v-if="item.docFileSize">{{ item.docFileSize | sizeFormatter }}</span>
+                    </div>
+                  </div>
+                  <!-- <div class="money-group flex-r-c center left">
               <van-icon class="s20" name="diy-iconJianYu" />
               <span class="red-text">{{item.money}}</span>
-            </div>
+            </div> -->
+                </div>
+              </div>
+            </van-skeleton>
           </div>
         </div>
-        </van-skeleton>
-      </div>
+      </van-list>
     </div>
+    <screenPopup ref="screenPopup" v-model="tabsActive" :list="tabslist"></screenPopup>
   </div>
 </template>
 <script lang="ts">
 import { Component, Vue } from 'vue-property-decorator'
+import { docTypeConvert } from '@/utils/globalFunctions'
 import Search from '@/components/Search.vue'
 import Ad from '@/components/Ad.vue'
-import { Icon, Skeleton, Swipe, SwipeItem } from 'vant'
-import { mapActions, mapState } from 'vuex'
-  @Component({
-    name: 'home',
-    components: {
-      [Icon.name]: Icon,
-      [Skeleton.name]: Skeleton,
-      [Swipe.name]: Swipe,
-      [SwipeItem.name]: SwipeItem,
-      Search,
-      Ad
-    },
-    computed: {
-      ...mapState('main', {
-        pageData: (state: any) => state.homePageData
-      })
-    },
-    methods: {
-      ...mapActions({
-        ajaxData: 'main/getHome'
-      })
-    }
-  })
+import screenPopup from '@/components/screenPopup.vue'
+import { Icon, Skeleton, Tabs, Tab, Sticky, List } from 'vant'
+import { mapActions } from 'vuex'
+@Component({
+  name: 'home',
+  components: {
+    [Icon.name]: Icon,
+    [Skeleton.name]: Skeleton,
+    [Tab.name]: Tab,
+    [Tabs.name]: Tabs,
+    [Sticky.name]: Sticky,
+    [List.name]: List,
+    Search,
+    Ad,
+    screenPopup
+  },
+  computed: {
+    // ...mapState('main', {
+    //   pageData: (state: any) => state.homePageData
+    // })
+  },
+  methods: {
+    ...mapActions({
+      doSearchRquesst: 'main/doSearchDocs',
+      getIndexTags: 'main/getIndexTags'
+    })
+    // ...mapActions({
+    //   ajaxData: 'main/getHome'
+    // })
+  }
+})
 
 export default class extends Vue {
-    ajaxData: any
-    pageData: any
-    rowWidth = ['100%', '20%', '40%', '15%']
+  doSearchRquesst: any
+  getIndexTags: any
+  $envs: any
+  rowWidth = ['100%', '20%', '40%', '15%']
+  tabslist = []
+  tabsActive = ''
+  LibraryShow = true
+  hotListState = {
+    loaded: false,
+    loading: false,
+    finished: false,
+    pageNum: 1,
+    pageSize: 20,
+    offset: 80,
+    list: [],
+    total: 0
+  }
 
-    created () {
-      this.ajaxData()
+  created () {
+    // this.ajaxData()
+  }
+
+  // get showLoading () {
+  //   const s = this.pageData
+  //   return {
+  //     new: !s?.new,
+  //     hot: !s?.hot,
+  //     keep: !s?.keep
+  //   }
+  // }
+  get showLoading () {
+    return this.hotListState.list.length === 0
+  }
+
+  get Offset () {
+    const tempN = document.querySelector('.j-header.jy-app-header') as HTMLDivElement
+    if (tempN) {
+      return tempN.offsetHeight - 1
+    } else {
+      return 0
     }
+  }
+
+  docTypeIcon (type: string) {
+    return `diy-${docTypeConvert(type)}`
+  }
 
-    get showLoading () {
-      const s = this.pageData
-      return {
-        new: !s?.new,
-        hot: !s?.hot,
-        keep: !s?.keep
+  async onLoad () {
+    if (this.tabslist.length === 0) {
+      const { data } = await this.getIndexTags()
+      if (Array.isArray(data)) {
+        const list: any = data.map(item => {
+          return {
+            type: item,
+            label: item
+          }
+        })
+        this.tabslist = list
+        if (data.length) {
+          const i: any = this.tabslist[0]
+          this.tabsActive = i.type
+        }
       }
     }
+    await this.getList()
+  }
 
-    goSearch () {
-      this.$router.push({
-        name: 'search'
+  onTabClick (name: string) {
+    this.tabsActive = name
+    this.hotListState.pageNum = 1
+    this.hotListState.list = []
+    this.hotListState.loaded = false
+    this.hotListState.finished = false
+    this.onLoad()
+  }
+
+  async getList () {
+    // if (!this.hotListState.value) return
+    if (this.hotListState.pageNum === 1) {
+      this.$toast.loading({
+        forbidClick: true,
+        duration: 0
       })
     }
+    const query = {
+      keyWord: '123',
+      tag: this.tabsActive === '全部' ? '' : this.tabsActive,
+      sort: 'vSort',
+      num: this.hotListState.pageNum,
+      size: this.hotListState.pageSize
+    }
+    console.log('搜索参数:', query)
+    this.hotListState.loading = true
+    const { data } = await this.doSearchRquesst(query)
+    this.hotListState.loading = false
+    this.hotListState.loaded = true
+    this.$toast.clear()
+    if (data && Array.isArray(data.list)) {
+      this.hotListState.pageNum += 1
+      this.hotListState.total = data.total
+      this.hotListState.list = this.hotListState.list.concat(data.list)
+    } else {
+      this.hotListState.finished = true
+    }
 
-    goContent (item: any) {
-      this.$router.push({
-        name: 'details',
-        params: {
-          id: item.id
-        }
-      })
+    // 数据请求完成(根据页码计算,当前页是否是最后一页)
+    // 请求完成后,页码就变为了下一页的页面,所以这里要-1
+    const isLastPage = (this.hotListState.pageNum - 1) * this.hotListState.pageSize >= this.hotListState.total
+    if (isLastPage) {
+      this.hotListState.finished = true
     }
+  }
+
+  goSearch () {
+    this.$router.push({
+      name: 'search'
+    })
+  }
+
+  goContent (item: any) {
+    this.$router.push({
+      name: 'details',
+      params: {
+        id: item.docId
+      }
+    })
+  }
+
+  async tabChange (item: any) {
+    // 分类切换
+    console.log(item)
+    this.hotListState.list = []
+    this.hotListState.pageNum = 1
+    await this.getList()
+  }
+
+  openScreen () {
+    (this.$refs.screenPopup as any).show = true
+  }
 }
 </script>
 <style scoped lang="scss">
@@ -175,14 +300,25 @@ export default class extends Vue {
   background: #F5F6F7;
   padding-bottom: 40px;
   box-sizing: border-box;
-  .home-header{
+  .homeSeach{
+    ::v-deep{
+      .van-search__content {
+      box-shadow: 0px 4px 4px 0px #0000000D;
+    }
+    }
+  }
+
+  .home-header {
     background: linear-gradient(180deg, #00AEE6 0%, #05B6CD 38%, #87DFEA 100%);
     width: 100%;
-    height:152px ;
+    height: 152px;
+    min-height: 152px;
+    display: block;
     box-sizing: border-box;
     padding-top: 16px;
     position: relative;
-    .home-title{
+
+    .home-title {
       //styleName: 常规/16;
       font-size: 16px;
       font-weight: 400;
@@ -191,15 +327,84 @@ export default class extends Vue {
       color: #FFFFFF;
       margin-bottom: 5px;
     }
-    .Ad-box{
+
+    .Ad-box {
       width: 359px;
       // height: 88px;
       position: absolute;
       top: 100%;
       left: 50%;
-      transform: translate(-50%,-50%);
+      transform: translate(-50%, -50%);
+    }
+  }
+
+  .group-title {
+    padding: 16px 0 6px 12px;
+    font-size: 18px;
+    font-weight: 400;
+    line-height: 26px;
+    text-align: left;
+    color: #171826;
+  }
+
+  .selectedLibrary {
+    padding-top: 60px;
+    h1 {
+      font-size: 18px;
+      line-height: 26px;
+      color: #171826;
+      font-weight: 400;
+      padding-left: 12px;
+      margin-bottom: 6px;
+    }
+    .ad-box{
+      padding-left: 8px;
+    }
+  }
+
+  .tabs {
+    margin-bottom: 8px;
+    position: relative;
+
+    ::v-deep {
+      .van-tabs--line .van-tabs__wrap {
+        height: 30px;
+      }
+
+      .van-tabs__nav--complete {
+        padding-left: 6px;
+      }
+
+      .van-tabs__wrap--scrollable .van-tab {
+        padding: 0 6px;
+      }
+    }
+
+    .left {
+      position: absolute;
+      top: 0;
+      left: -3px;
+      width: 12px;
+      height: 30px;
+      background-color: #F5F6F7;
+    }
+
+    .btn-right {
+      position: absolute;
+      top: 0;
+      right: -3px;
+      width: 64px;
+      height: 30px;
+      background: linear-gradient(90deg, rgba(245, 246, 247, 0) 0%, #F5F6F7 50%, #F5F6F7);
+      display: flex;
+      justify-content: flex-end;
+      align-items: center;
+      box-sizing: border-box;
+      padding-right: 10px;
+      z-index: 10;
     }
   }
+
   .module-title {
     font-size: 18px;
     font-weight: normal;
@@ -212,6 +417,7 @@ export default class extends Vue {
     line-height: 20px;
     color: #171826;
   }
+
   .price-text {
     font-size: 13px;
     line-height: 28px;
@@ -225,6 +431,7 @@ export default class extends Vue {
         height: 28px;
       }
     }
+
     &.card-style {
       .van-skeleton__avatar {
         width: 100px !important;
@@ -240,90 +447,123 @@ export default class extends Vue {
     height: 20px;
   }
 
-  @include diy-icon('pdf', 24);
-  @include diy-icon('word', 24);
-  @include diy-icon('excel', 24);
-  @include diy-icon('ppt', 24);
+  @include diy-icon('pdf', 18, 18);
+  @include diy-icon('word', 18, 18);
+  @include diy-icon('excel', 18, 18);
+  @include diy-icon('ppt', 18, 18);
+  @include diy-icon('zhedie', 20, 20);
 
   .base-group {
-    padding: 4px 19px 4px 16px;
+    // padding: 4px 19px 4px 16px;
     box-sizing: border-box;
+
     .list-group {
-      border-radius: 8px;
+      border-radius: 12px;
       background: #FFFFFF;
       box-sizing: border-box;
       padding: 8px 0;
+      margin: 0 8px 8px 8px;
+
       &.card-group {
         padding-left: 12px;
       }
+
       .list-item {
         padding: 6px 12px;
         box-sizing: border-box;
+
         i {
           flex-shrink: 0;
           margin-right: 4px;
         }
+
         .flex {
           min-width: 0;
         }
+
         .right-info {
           margin-left: 4px;
           flex-shrink: 0;
         }
       }
+
       .card-item {
         justify-content: flex-start;
-        padding: 8px 16px 12px 0;
+        // padding: 8px 16px 12px 0;
         box-sizing: border-box;
         border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+
         &:nth-last-child(1) {
           border-bottom-color: transparent;
-          padding-bottom: 8px;
+          // padding-bottom: 8px;
         }
+
         .money-group {
           margin-top: 8px;
         }
+
         .mini-img-group {
           flex-shrink: 0;
           position: relative;
           border-radius: 4px;
-          border: 1px solid rgba(0, 0, 0, 0.1);
-          width: 100px;
-          height: 124px;
+          border: 0.5px solid #0000001A;
+          width: 75px;
+          height: 93px;
           margin-right: 12px;
           overflow: hidden;
+
           img {
             width: 100%;
             height: 100%;
           }
+          .vip-ic{
+            position: absolute;
+            left: 0;
+            top: 0;
+            background: linear-gradient(98deg, #FFA674 0%, #F01212 100%);
+            width: 50px;
+            height: 18px;
+            border-radius: 4px 0px 4px 0px;
+            color: #fff;
+            font-size: 10px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+          }
+
           i {
             position: absolute;
             right: 0;
             bottom: 0;
           }
         }
+
         .info-text-group {
           span {
             display: inline-block;
+
             &:last-child {
               &::after {
                 content: unset;
               }
             }
+
             &::after {
               content: "|";
               padding: 0 8px;
             }
           }
         }
+
         .info-text {
           color: #9B9CA3;
           font-family: PingFang SC;
           font-size: 12px;
-          line-height: 18px;
+          line-height: 22px;
           letter-spacing: 0px;
           text-align: left;
         }
+
         .red-text {
           color: #FB483D;
           font-family: PingFang SC;
@@ -332,20 +572,28 @@ export default class extends Vue {
           letter-spacing: 0px;
           text-align: left;
         }
+
         .title-text {
           color: #171826;
           font-family: PingFang SC;
           font-weight: bold;
           font-size: 14px;
-          line-height: 20px;
+          line-height: 22px;
           letter-spacing: 0px;
           text-align: left;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-line-clamp: 2;
+          -webkit-box-orient: vertical;
+          padding-right: 8px;
+          box-sizing: border-box;
         }
       }
     }
 
     .title-group {
-      padding: 16px 0 6px 0;
+      padding: 16px 0 6px 12px;
       margin-bottom: 4px;
       box-sizing: border-box;
       color: #171826;

+ 116 - 41
jydocs-mobile/src/views/Search.vue

@@ -1,8 +1,9 @@
 <template>
   <div class="pages--search">
     <div class="j-header">
-      <search id="mySearch" ref="input" key="search-page" :defalultValue="listState.value" @input="onInput" @submit="doSearch"></search>
-      <van-tabs v-model="docsTypeConf.active"
+      <search id="mySearch" ref="input" 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"
@@ -10,45 +11,37 @@
         @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="'diy-down-' + (item.active ? 'blue' : 'grey')" class="s-i-icon" />
+      </van-tabs> -->
+      <div class="filter-box" v-if="listState.loaded">
+        <Filters @onReset="filtersReset" @confirm="filtersConfirm"></Filters>
+        <div class="sort-list flex-r-c">
+          <div class="sort-list-item flex-r-c left 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="'diy-down-' + (item.active ? 'blue' : 'grey')" class="s-i-icon" />
+          </div>
         </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 class="historySearch" v-if="!listState.loaded && historykeyList.length>0">
+        <div class="his_head">
+          <div class="his_title">历史搜索</div>
+          <van-icon :name="'diy-clear'" @click="clearHistory"/>
+        </div>
+        <div class="his_content">
+          <div class="his_item" v-for="item in historykeyList" :key="item" @click="historykeySearch(item)">{{item}}</div>
+        </div>
+      </div>
+      <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"
-            :price="item.price"
-            :subInfo="calcSubInfo(item)"
-            @onClick="toDocDetail(item)"
-          />
+          <Card v-for="(item, index) in listState.list" :key="index" :title="item.docName" :desc="item.docSummary"
+            :docType="item.docFileType" :isVip="item.productType === 1" :subInfo="calcSubInfo(item)" @onClick="toDocDetail(item)" />
         </div>
-        <Empty v-if="listState.list.length === 0 && listState.loaded">暂无数据</Empty>
+        <Empty v-if="listState.list.length === 0 && listState.loaded" style="background: #fff;">暂无数据</Empty>
       </van-list>
     </div>
   </div>
@@ -58,6 +51,7 @@
 import { Component, Vue } from 'vue-property-decorator'
 import { Tabs, Tab, Icon, List } from 'vant'
 import Search from '@/components/Search.vue'
+import Filters from '@/components/filters/index.vue'
 import Card from '@/components/docs-card/Card.vue'
 import Empty from '@/components/common/Empty.vue'
 import { mapState, mapMutations, mapActions } from 'vuex'
@@ -72,7 +66,8 @@ import { dateFormatter } from '@/utils/globalFunctions'
     [Icon.name]: Icon,
     Search,
     Card,
-    Empty
+    Empty,
+    Filters
   },
   computed: {
     ...mapState('main', {
@@ -98,7 +93,7 @@ export default class extends Vue {
 
   protected doSearchRquesst: any
   protected getIndexTags: any
-
+  historykeyList: string[] = []
   docsTypeConf = {
     active: '',
     list: []
@@ -125,7 +120,9 @@ export default class extends Vue {
     }
   ]
 
-  listState ={
+  listState = {
+    docFileType: 0,
+    productType: 0,
     value: '',
     loaded: false, // 是否首次加载完成
     loading: false,
@@ -157,6 +154,9 @@ export default class extends Vue {
     if (!this.restored) {
       this.onFocus()
     }
+    if (localStorage.getItem('jydocs-searchHistory')) {
+      this.historykeyList = JSON.parse(localStorage.getItem('jydocs-searchHistory') || '[]')
+    }
   }
 
   onFocus () {
@@ -187,6 +187,24 @@ export default class extends Vue {
     this.listState.value = search.trim().replace(/\s+/g, ' ')
   }
 
+  historykeySearch (val: any) {
+    this.listState.value = val
+    this.doSearch()
+  }
+
+  savesearchHistory () {
+    const key: string = this.listState.value + ''
+    if (key && !this.historykeyList.includes(key)) {
+      this.historykeyList.push(key)
+      localStorage.setItem('jydocs-searchHistory', JSON.stringify(this.historykeyList))
+    }
+  }
+
+  clearHistory () {
+    this.historykeyList = []
+    localStorage.removeItem('jydocs-searchHistory')
+  }
+
   docTypeChange () {
     if (!this.listState.value) return
     this.resetListState()
@@ -212,9 +230,21 @@ export default class extends Vue {
     this.getList()
   }
 
+  filtersReset (val: any) {
+    this.listState.productType = val.type
+    this.listState.docFileType = val.format
+    this.doSearch()
+  }
+
+  filtersConfirm (val: any) {
+    this.listState.productType = val.type
+    this.listState.docFileType = val.format
+    this.doSearch()
+  }
+
   doSearch () {
     if (!this.listState.value) return
-
+    this.savesearchHistory()
     const inputComponent = this.$refs.input as any
     inputComponent.setSearchContent(this.listState.value)
 
@@ -260,6 +290,9 @@ export default class extends Vue {
       })
     }
     const query = {
+      docFileType: this.listState.docFileType,
+      productType: this.listState.productType,
+      // 搜索关键字
       keyWord: this.listState.value,
       tag: this.docsTypeConf.active === '全部' ? '' : this.docsTypeConf.active,
       sort: this.activeSortType?.type,
@@ -338,10 +371,11 @@ export default class extends Vue {
 <style scoped lang="scss">
 @include diy-icon('down-grey', 16, 16);
 @include diy-icon('down-blue', 16, 16);
-
+@include diy-icon('clear', 20, 20);
 .pages--search {
-  background-color: #F5F6F7;
+  background-color: #fff;
   box-sizing: border-box;
+
   ::v-deep .van-tabs {
     width: 100%;
     font-size: 14px;
@@ -352,28 +386,69 @@ export default class extends Vue {
     flex-direction: column;
   }
 
+  .j-header:after {
+    height: 0;
+  }
+
+  .filter-box{
+    width: 100%;
+  }
   .sort-list {
     width: 100%;
     font-size: 14px;
     line-height: 20px;
+    border-bottom: 0.5px solid #0000000D;
     .sort-list-item {
+      max-width: 108px;
+      box-sizing: border-box;
       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;
       }
     }
   }
+  .historySearch{
+    padding: 0 16px;
+    .his_head{
+      height: 54px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .his_title{
+        font-size: 16px;
+        color: #171826;
+      }
+    }
+    .his_content{
+      overflow: hidden;
+      .his_item{
+        float: left;
+        margin-right: 8px;
+        margin-bottom: 12px;
+        padding: 4px 12px;
+        line-height: 22px;
+        font-size: 13px;
+        color: #5F5E64;
+        border-radius: 4px;
+        background-color: #F7F9FA;
+      }
+    }
+  }
 }
 </style>

+ 7 - 0
jydocs-mobile/src/views/details/details.vue

@@ -42,6 +42,11 @@
         <recharge ref="charge" :detailData="detailData" :coins="coins"></recharge>
         <!-- 分享 -->
         <share-pop ref="shares" :detailData="detailData" :links="links"></share-pop>
+        <popupbox ref="pop"></popupbox>
+        <popupbox ref="popDown">
+          <span>- 会员免费文档下载特权 -</span>
+          <span>消耗 <span></span> 篇 | 今日还剩余 <span></span> 篇</span>
+        </popupbox>
     </div>
 </template>
 
@@ -51,6 +56,7 @@ import { mapActions, mapMutations } from 'vuex'
 import { Icon, Toast, GoodsAction, GoodsActionIcon, GoodsActionButton, Sticky } from 'vant'
 import Recharge from '@/components/Recharge.vue'
 import sharePop from '@/components/SharePopup.vue'
+import popupbox from '@/components/popupbox/index.vue'
 import { MixinTop } from '@/utils/mixin-top'
 import { weChatShare } from '@/utils/wxShare'
 import { formatSize } from '@/utils/globalFunctions'
@@ -67,6 +73,7 @@ import pdf from 'vue-pdf'
     [GoodsActionButton.name]: GoodsActionButton,
     Recharge,
     sharePop,
+    popupbox,
     pdf
   },
   methods: {

+ 101 - 44
jydocs-mobile/src/views/user/Library.vue

@@ -32,35 +32,36 @@
         <Empty v-if="myLibListState.list.length === 0 && myLibListState.loaded">暂无我的文库</Empty>
         <div class="keep-group base-group">
           <div class="title-group flex-r-c center left">
-            <span></span>
-            <h5 class="module-title">精选推荐</h5>
+            <!-- <span></span> -->
+            <h5 class="group-title">精选推荐</h5>
           </div>
-          <div class="list-group card-group flex-c-c">
+          <div class="list-group card-group flex-c-c"  v-for="item in selectedListState.list" :key="item.docId" @click="goContent(item)">
             <van-skeleton avatar avatar-shape="square" class="van-loading-skeleton card-style"
                 :row="4"
                 :row-width="rowWidth"
-                :loading="showLoading.keep">
-              <div class="card-item flex-r-c"  v-for="item in pageData.keep" :key="item.id" @click="goContent(item)">
+                :loading="showLoading">
+              <div class="card-item flex-r-c">
               <div class="mini-img-group">
-                <img :src="item.img" alt="">
-                <van-icon :name="'diy-' + item.type" />
+                <img :src="item.previewImgId" alt="">
+                <van-icon :name="docTypeIcon(item.docFileType) " />
+                <div class="vip-ic" v-if="item.productType === 1">会员免费</div>
               </div>
               <div class="flex-c-c">
                 <div class="flex">
-                  <div class="title-text van-multi-ellipsis--l2">{{item.title}}</div>
+                  <div class="title-text van-multi-ellipsis--l2">{{item.docName}}</div>
                 </div>
                 <div class="flex-c-c info-text">
-                  <span v-if="item.contribution">贡献者: {{item.contribution}}</span>
+                  <span v-if="item.docTags">{{item.docTags}}</span>
                   <div class="info-text-group flex-r-c center left">
-                    <span v-if="item.down">{{item.down}}次下载</span>
-                    <span v-if="item.page">共{{item.page}}页</span>
-                    <span v-if="item.size">{{item.size | sizeFormatter}}</span>
+                    <span v-if="item.viewTimes">{{item.viewTimes}}次浏览</span>
+                    <span v-if="item.docPageSize">共{{item.docPageSize}}页</span>
+                    <span v-if="item.docFileSize">{{item.docFileSize | sizeFormatter}}</span>
                   </div>
                 </div>
-                <div class="money-group flex-r-c center left">
-                  <!-- <van-icon class="s20" name="diy-iconJianYu" />
-                  <span class="red-text">{{item.money}}</span> -->
-                </div>
+                <!-- <div class="money-group flex-r-c center left">
+                  <van-icon class="s20" name="diy-iconJianYu" />
+                  <span class="red-text">{{item.money}}</span>
+                </div> -->
               </div>
             </div>
             </van-skeleton>
@@ -92,12 +93,10 @@
               :title="item.DocName"
               :desc="item.DocSummary"
               :docType="item.DocFileType"
+              :isVip="item.productType === 1"
               :subInfo="calcSubInfoForColl(item)"
               @onClick="toDocDetail(item)"
             >
-            <template #leftEnd>
-              <div class="freevip">会员免费</div>
-            </template>
             </Card>
           </div>
         </van-list>
@@ -115,7 +114,7 @@ import { Tabs, Tab, List, NoticeBar, Icon, Skeleton } from 'vant'
 import { mapState, mapMutations, mapActions } from 'vuex'
 import Card from '@/components/docs-card/Card.vue'
 import Empty from '@/components/common/Empty.vue'
-import { dateFormatter, formatSize } from '@/utils/globalFunctions'
+import { dateFormatter, formatSize, docTypeConvert } from '@/utils/globalFunctions'
 
 @Component({
   name: 'user-library',
@@ -145,7 +144,8 @@ import { dateFormatter, formatSize } from '@/utils/globalFunctions'
     }),
     ...mapActions({
       getMyLibList: 'main/getMyLibList',
-      getRecommendList: 'main/getRecommendList'
+      getRecommendList: 'main/getRecommendList',
+      doSearchRquesst: 'main/doSearchDocs'
     })
   }
 })
@@ -157,6 +157,7 @@ export default class UserLibrary extends Vue {
 
   protected getMyLibList: any
   protected getRecommendList: any
+  protected doSearchRquesst: any
   pageData: any
   rowWidth = ['100%', '20%', '40%', '15%']
 
@@ -169,6 +170,10 @@ export default class UserLibrary extends Vue {
     color: '#2ABED1'
   }
 
+  selectedListState = {
+    list: []
+  }
+
   myLibListState = {
     loaded: false,
     loading: false,
@@ -208,7 +213,12 @@ export default class UserLibrary extends Vue {
   created () {
     this.tabActive = this.$route.query.tab as string
     this.reStoreState()
-    this.getRecommendList()
+    // this.getRecommendList()
+    this.getselectedList()
+  }
+
+  docTypeIcon (type: string) {
+    return `diy-${docTypeConvert(type)}`
   }
 
   beforeTabChange () {
@@ -249,6 +259,19 @@ export default class UserLibrary extends Vue {
     return subInfoArr
   }
 
+  async getselectedList () {
+    const query = {
+      productType: 2,
+      sort: 'vSort',
+      num: 1,
+      size: 10
+    }
+    const { data } = await this.doSearchRquesst(query)
+    if (data) {
+      this.selectedListState.list = data.list
+    }
+  }
+
   async onLoad () {
     const t: any = this.$data[this.keyForList]
     const query = {
@@ -316,20 +339,23 @@ export default class UserLibrary extends Vue {
     this.saveLibState(d)
   }
 
+  // get showLoading () {
+  //   const s = this.pageData
+  //   return {
+  //     new: !s?.new,
+  //     hot: !s?.hot,
+  //     keep: !s?.keep
+  //   }
+  // }
   get showLoading () {
-    const s = this.pageData
-    return {
-      new: !s?.new,
-      hot: !s?.hot,
-      keep: !s?.keep
-    }
+    return this.selectedListState.list.length === 0
   }
 
   goContent (item: any) {
     this.$router.push({
       name: 'details',
       params: {
-        id: item.id
+        id: item.docId
       }
     })
   }
@@ -342,6 +368,14 @@ export default class UserLibrary extends Vue {
 
 <style lang="scss" scoped>
 .user-library {
+  .group-title {
+    padding: 8px 0 0px 4px;
+    font-size: 18px;
+    font-weight: 400;
+    line-height: 26px;
+    text-align: left;
+    color: #171826;
+  }
   .freevip{
     width: 50px;
     height: 18px;
@@ -398,24 +432,26 @@ export default class UserLibrary extends Vue {
     height: 20px;
   }
 
-  @include diy-icon('pdf', 24);
-  @include diy-icon('word', 24);
-  @include diy-icon('excel', 24);
-  @include diy-icon('ppt', 24);
+  @include diy-icon('pdf', 18, 18);
+  @include diy-icon('word', 18, 18);
+  @include diy-icon('excel', 18, 18);
+  @include diy-icon('ppt', 18, 18);
 
   .base-group {
-    padding: 4px 19px 4px 16px;
+    // padding: 4px 19px 4px 16px;
+    padding: 0 8px;
     box-sizing: border-box;
     .list-group {
-      border-radius: 8px;
+      border-radius: 4px;
       background: #FFFFFF;
       box-sizing: border-box;
-      padding: 8px 0;
+      padding: 8px;
+      margin-bottom: 8px;
       &.card-group {
-        padding-left: 12px;
+        // padding-left: 12px;
       }
       .list-item {
-        padding: 6px 12px;
+        // padding: 6px 12px;
         box-sizing: border-box;
         i {
           flex-shrink: 0;
@@ -431,12 +467,12 @@ export default class UserLibrary extends Vue {
       }
       .card-item {
         justify-content: flex-start;
-        padding: 8px 16px 12px 0;
+        // padding: 8px 16px 12px 0;
         box-sizing: border-box;
         border-bottom: 1px solid rgba(0, 0, 0, 0.05);
         &:nth-last-child(1) {
           border-bottom-color: transparent;
-          padding-bottom: 8px;
+          // padding-bottom: 8px;
         }
         .money-group {
           margin-top: 8px;
@@ -446,14 +482,28 @@ export default class UserLibrary extends Vue {
           position: relative;
           border-radius: 4px;
           border: 1px solid rgba(0, 0, 0, 0.1);
-          width: 100px;
-          height: 124px;
-          margin-right: 12px;
+          width: 75px;
+          height: 93px;
+          margin-right: 8px;
           overflow: hidden;
           img {
             width: 100%;
             height: 100%;
           }
+          .vip-ic{
+            position: absolute;
+            left: 0;
+            top: 0;
+            background: linear-gradient(98deg, #FFA674 0%, #F01212 100%);
+            width: 50px;
+            height: 18px;
+            border-radius: 4px 0px 4px 0px;
+            color: #fff;
+            font-size: 10px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+          }
           i {
             position: absolute;
             right: 0;
@@ -478,7 +528,7 @@ export default class UserLibrary extends Vue {
           color: #9B9CA3;
           font-family: PingFang SC;
           font-size: 12px;
-          line-height: 18px;
+          line-height: 22px;
           letter-spacing: 0px;
           text-align: left;
         }
@@ -498,6 +548,13 @@ export default class UserLibrary extends Vue {
           line-height: 20px;
           letter-spacing: 0px;
           text-align: left;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-line-clamp: 2;
+          -webkit-box-orient: vertical;
+          padding-right: 8px;
+          box-sizing: border-box;
         }
       }
     }