LiveList.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <template><page-meta :root-font-size="fontSize+'px'"></page-meta>
  2. <member-base :show="false"><view style="position: absolute;top:0;right:0;left:0;bottom:0" class="scroll-view-wrapper div container">
  3. <view class="div common-header-wrap">
  4. <view class="status-holder"></view>
  5. <view :style="'height:'+navHeight+'px'"></view>
  6. <view class="common-header-holder"></view>
  7. <view class="common-header-fixed">
  8. <title-header />
  9. <uni-nav-bar title="直播" class="common-header" left-icon="back" @clickLeft="goBack()">
  10. </uni-nav-bar>
  11. </view>
  12. </view>
  13. <view class="div header-back">
  14. <view class="div header-search">
  15. <text class="i iconfont">&#xe629;</text><input v-model="keyword" placeholder="试试搜商品/主播" @confirm="confirm" />
  16. </view>
  17. <view v-if="gc_list" class="div header-class">
  18. <view class="div gc-item" :class="{'active':gc_id==0}" @click="setGoodsClassId(0)">全部</view>
  19. <view v-bind:key="gc.gc_id" v-for="gc in gc_list" :class="{'active':gc_id==gc.gc_id}" @click="setGoodsClassId(gc.gc_id)" class="div gc-item">{{gc.gc_name}}</view>
  20. </view>
  21. </view>
  22. <view class="div header-back2"></view>
  23. <view class="div header-holder"></view>
  24. <view class="scroll-view div" style="position:relative">
  25. <scroll-view style="position: absolute;top:0;right:0;left:0;bottom:0" class="div flex-wrapper" @scrolltolower="loadMore" scroll-y="true">
  26. <view class="div live-list" v-if="liveList && liveList.length">
  27. <view class="div live-item" v-for='(item,index) in liveList' @click="goLiveDetail(item)" v-bind:key="index">
  28. <view class="div live-cover" v-if="config.live_type == 1">
  29. <image mode="aspectFit" class="img" :style="getBannerStyle" :src="item.minipro_live_image_url">
  30. </view>
  31. <view class="div live-cover" v-else>
  32. <video :style="getBannerStyle" v-if="item.live_apply_cover_video" :src="item.live_apply_cover_video_url" muted="muted" autoplay="autoplay" loop="loop" />
  33. <image mode="aspectFit" class="img" :style="getBannerStyle" v-else :src="item.live_apply_cover_image_url">
  34. </view>
  35. <view class="div live-info">
  36. <view class="div live-name" v-if="config.live_type == 1">{{item.minipro_live_name}}</view>
  37. <view class="div live-name" v-else>{{item.live_apply_name}}</view>
  38. <view class="div store-info">
  39. <view class="div left">
  40. <image mode="aspectFit" class="img store-avatar" :src="item.store_avatar">
  41. </view>
  42. <view class="div right">
  43. <view class="div store-name">{{item.store_name}}</view>
  44. <view class="div area-info">{{item.area_info}}</view>
  45. </view>
  46. </view>
  47. <view class="div goods-list" v-if="item.goods_list">
  48. <view class="div goods-item goods-item-1">
  49. <view class="div goods-back" v-if="item.goods_list[0]">
  50. <image mode="aspectFit" class="img" :src="item.goods_list[0].goods_image"/>
  51. <view class="div goods-price">¥{{item.goods_list[0].goods_price}}</view>
  52. </view>
  53. </view>
  54. <view class="div goods-item goods-item-2">
  55. <view class="div goods-back" v-if="item.goods_list[1]">
  56. <image mode="aspectFit" class="img" :src="item.goods_list[1].goods_image"/>
  57. <view v-if="item.goods_count<=2" class="div goods-price">¥{{item.goods_list[1].goods_price}}</view>
  58. <view v-else class="div goods-more">
  59. <view class="div goods-text-list">
  60. <view class="div goods-text">{{item.goods_count-1}}</view>
  61. <view class="div goods-text">宝贝</view>
  62. </view>
  63. </view>
  64. </view>
  65. </view>
  66. </view>
  67. <view class="div goods-class" v-if="item.gc_name"><view class="div goods-class-item">#{{item.gc_name}}</view></view>
  68. </view>
  69. </view>
  70. </view>
  71. <empty-record v-if='liveList && !liveList.length'></empty-record>
  72. </scroll-view>
  73. </view>
  74. </view></member-base>
  75. </template>
  76. <script>
  77. import {getFontSize} from '@/util/common'
  78. import TitleHeader from '../../TitleHeader'
  79. import { urlencode } from '@/util/common'
  80. import MemberBase from '../MemberBase'
  81. import EmptyRecord from '../../EmptyRecord'
  82. import { mapState, mapActions } from 'vuex'
  83. import { getLiveList, getMiniproLiveList } from '../../../api/memberLive'
  84. export default {
  85. name: 'LiveList',
  86. components:{
  87. TitleHeader,
  88. MemberBase,
  89. EmptyRecord
  90. },
  91. mounted(){
  92. // #ifdef MP-WEIXIN
  93. this.navHeight = uni.getMenuButtonBoundingClientRect().top
  94. // #endif
  95. },
  96. data(){
  97. return {
  98. navHeight: 0,
  99. gc_list: false,
  100. keyword: '',
  101. gc_id: '', // 文章分类ID
  102. liveList: false,
  103. params: { 'page': 0, 'per_page': 10 },
  104. loading: false, // 是否加载更多
  105. isMore: true, // 是否有更多
  106. }
  107. },
  108. computed:{
  109. fontSize(){
  110. return getFontSize()
  111. },
  112. ...mapState({
  113. config: state => state.config.config
  114. }),
  115. getBannerStyle: function () {
  116. const res = uni.getSystemInfoSync()
  117. var width = res.windowWidth
  118. var height = res.windowHeight
  119. let itemWidth = width / 2
  120. return "width:"+itemWidth +"px;height:"+itemWidth +"px"
  121. }
  122. },
  123. onLoad: function (option) {
  124. this.gc_id=option.gc_id ? option.gc_id : ''
  125. this.fetchConfig()
  126. this.loadMore()
  127. },
  128. methods:{
  129. goBack(){uni.navigateBack({delta:1})},
  130. ...mapActions({
  131. fetchConfig: 'fetchConfig'
  132. }),
  133. loadMore () {
  134. if (this.loading) {
  135. return
  136. }
  137. this.loading = true
  138. this.params.page = ++this.params.page
  139. if (this.isMore) {
  140. this.getLiveList(true)
  141. }
  142. },
  143. setGoodsClassId (gc_id) {
  144. this.gc_id = gc_id
  145. this.reload()
  146. },
  147. confirm () {
  148. this.reload()
  149. },
  150. reload () {
  151. // 重新加载数据
  152. this.params.page = 0
  153. this.isMore = true
  154. this.loading = false
  155. this.liveList = []
  156. this.loadMore()
  157. },
  158. getLiveList () {
  159. uni.showLoading({ title: '加载中' })
  160. if (this.config.live_type == 1) {
  161. getMiniproLiveList(Object.assign({ gc_id: this.gc_id, keyword: this.keyword }, this.params)).then(res => {
  162. uni.hideLoading()
  163. if (res.result.hasmore) {
  164. this.isMore = true
  165. } else {
  166. this.isMore = false
  167. }
  168. if (this.liveList) {
  169. this.liveList = this.liveList.concat(res.result.minipro_live_list)
  170. } else {
  171. this.liveList = res.result.minipro_live_list
  172. }
  173. if (!this.gc_list) {
  174. this.gc_list = res.result.goodsclass_list
  175. }
  176. }).catch(error => {
  177. uni.hideLoading()
  178. uni.showToast({icon:'none',title: error.message})
  179. })
  180. } else {
  181. getLiveList(Object.assign({ gc_id: this.gc_id, keyword: this.keyword }, this.params)).then(res => {
  182. uni.hideLoading()
  183. if (res.result.hasmore) {
  184. this.isMore = true
  185. } else {
  186. this.isMore = false
  187. }
  188. if (this.liveList) {
  189. this.liveList = this.liveList.concat(res.result.live_apply_list)
  190. } else {
  191. this.liveList = res.result.live_apply_list
  192. }
  193. if (!this.gc_list) {
  194. this.gc_list = res.result.goodsclass_list
  195. }
  196. }).catch(error => {
  197. uni.hideLoading()
  198. uni.showToast({icon:'none',title: error.message})
  199. })
  200. }
  201. },
  202. goLiveDetail (item) {
  203. if (this.config.live_type == 1) {
  204. // #ifndef MP-WEIXIN
  205. uni.showToast({icon:'none',title: '请在小程序中打开'})
  206. return
  207. // #endif
  208. wx.navigateTo({ url: 'plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=' + item.minipro_live_room_id })
  209. } else {
  210. uni.navigateTo({ url: '/pages/member/live/LiveDetail'+'?'+urlencode( { 'live_apply_id': item.live_apply_id } )})
  211. }
  212. }
  213. }
  214. }
  215. </script>
  216. <style lang="scss" scoped>
  217. .scroll-view-wrapper{display: flex;flex-direction: column;}
  218. .scroll-view{flex:1}
  219. .common-header-wrap .common-header{border-bottom: 0;background: $primaryColor;color:#fff;box-shadow: unset}
  220. .header-back2{
  221. height: 5rem;background:$primaryColor;position: fixed;z-index: 1;width: 100%;top:5rem;
  222. }
  223. .header-holder{height: 4.5rem;}
  224. .header-back{
  225. height: 4.5rem;
  226. background:$primaryColor;
  227. position: fixed;
  228. width: 100%;
  229. z-index: 3;
  230. }
  231. .header-search{margin:0 0.8rem;position: relative;
  232. input{width: 100%;height: 1.5rem;line-height: 1.5rem;background: rgba(255,255,255,.2);border-radius:1.5rem;text-indent: 1.5rem;border:0;color:#fff;font-size:$subFontSize;}
  233. input::-webkit-input-placeholder{color: #f7d8d8}
  234. .i{position: absolute;color:#f7d8d8;display:block;width:1.5rem;line-height: 1.5rem;text-align: center;}
  235. }
  236. .header-class{position:relative;height:1.5rem;white-space: nowrap;overflow: hidden;overflow-x: auto;margin-top:.8rem;font-size:$subFontSize;color:#f7d8d8;padding:0 .4rem;
  237. .gc-item{display: inline-block;margin:0 .4rem;}
  238. .gc-item.active{color:#fff;position: relative;
  239. &::after{content:' ';position: absolute;bottom: -.4rem;width:1rem;height: 3px;background: #fff;border-radius: 3px;left:50%;margin-left:-.5rem;}
  240. }
  241. }
  242. .flex-wrapper{margin:0 .8rem;position: relative;z-index: 2;
  243. .live-item{border-radius:1rem;background: #fff;margin-bottom:.8rem;overflow:hidden;
  244. display: flex;
  245. .live-cover{
  246. background: #000;font-size: 0;
  247. }
  248. .live-info{flex:1;
  249. .live-name{padding:0 .4rem;font-size:$h2;margin:.8rem 0;font-weight: 700}
  250. .store-info{padding:0 .4rem;display: flex;
  251. .store-avatar{width:1.5rem;height: 1.5rem;border-radius: 1.5rem}
  252. .right{flex:1;
  253. .store-name{font-size:$subFontSize;white-space: nowrap;overflow: hidden;text-overflow: ellipsis}
  254. .area-info{font-size:$fontSize;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;color:#666}
  255. }
  256. }
  257. }
  258. .goods-list{padding:0 .4rem;overflow: hidden}
  259. .goods-item{width:50%;height: 0;padding-bottom:50%;float: left;position: relative;
  260. .goods-back{position: absolute;top:0.2rem;left:0.2rem;right:0.2rem;bottom:0.2rem;border-radius: .2rem;overflow: hidden;
  261. .img{position: absolute;width:100%;height: 100%;}
  262. }
  263. .goods-price{position: absolute;bottom:0;let:.4rem;color:#fff;font-size:$subFontSize}
  264. .goods-more{width:100%;height: 100%;background: rgba(0,0,0,.5);font-size:$subFontSize;color:#fff;position: absolute;text-align: center}
  265. .goods-text{line-height: 1rem}
  266. .goods-text-list{position: relative;top:50%;margin-top:-1rem;}
  267. }
  268. .goods-item-1{}
  269. .goods-item-2{}
  270. .goods-class{padding:0 .4rem}
  271. .goods-class-item{font-size:$fontSize;line-height: 1rem;padding:0 .4rem;background: #fff2e2;display: inline-block;border-radius: .2rem;color:#ce7303}
  272. }
  273. }
  274. </style>