多租户商城-商户小程序端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

464 lines
12 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <!--
  2. * @Descripttion:
  3. * @version: 1.0.0
  4. * @Author: kahu
  5. * @Date: 2022-10-12 11:48:03
  6. * @LastEditors: kahu
  7. * @LastEditTime: 2023-03-08 14:41:56
  8. -->
  9. <template>
  10. <view class="live-box">
  11. <view class="live-ongoing" v-if="liveData.liveStatus === 101" @click="toLive">
  12. <image class="cover-img" :src="liveData.feedsImg" />
  13. <view class="status">
  14. <view class="status-state">
  15. <!-- #ifdef MP-WEIXIN -->
  16. <img class="img" src="../../../static/images/live/icon-live-num.png" mode="widthFix"/>
  17. <!-- #endif -->
  18. <!-- #ifdef H5 || APP-PLUS -->
  19. <image class="img" src="../../../static/images/live/icon-live-num.png" mode="widthFix"/>
  20. <!-- #endif -->
  21. 直播中
  22. </view>
  23. <!-- <view class="status-num">1000</view> -->
  24. </view>
  25. <view class="user">
  26. <view class="user-pic">
  27. <image class="img" :src="liveData.anchorHeadImg" />
  28. </view>
  29. <view class="user-name">{{ liveData.anchorNickName }}</view>
  30. </view>
  31. <view class="products">
  32. <view class="uni-padding-wrap">
  33. <view class="page-section swiper">
  34. <view class="page-section-spacing">
  35. <swiper class="swiper"
  36. :indicator-dots="indicatorDots"
  37. :autoplay="autoplay"
  38. :interval="interval"
  39. :duration="duration"
  40. :vertical="true"
  41. >
  42. <swiper-item
  43. v-for="item in liveData.goods"
  44. :key="item.goods_id"
  45. >
  46. <view class="swiper-item">{{ item.name }}</view>
  47. </swiper-item>
  48. </swiper>
  49. </view>
  50. </view>
  51. </view>
  52. </view>
  53. </view>
  54. <view class="live-other" v-else @click="toLive">
  55. <image class="cover-img" :src="liveData.feedsImg" />
  56. <div class="filter-box-warp">
  57. <div class="filter-box">
  58. <image class="cover-img" :src="liveData.feedsImg" />
  59. </div>
  60. </div>
  61. <view class="user">
  62. <view class="user-pic"><image class="img" :src="liveData.anchorHeadImg" /></view>
  63. <view class="user-name">{{ liveData.anchorNickName }}</view>
  64. </view>
  65. <view class="count-down" v-if="liveStatus === 102">
  66. <image v-if="isLate" class="img" src="@/static/images/live/live-late.png"/>
  67. <view class="text">{{ liveTimeTitle }}</view>
  68. <view v-if="!isLate" class="time">
  69. <view class="time-item">{{times[0]}}</view>
  70. <view class="dot">:</view>
  71. <view class="time-item">{{times[1]}}</view>
  72. <view class="dot">:</view>
  73. <view class="time-item">{{times[2]}}</view>
  74. </view>
  75. </view>
  76. <!-- #ifdef MP-WEIXIN -->
  77. <view
  78. v-if="liveStatus === 102 && !isLate"
  79. class="btn-subscribe"
  80. :class="{subscribed : subscribeLive === '已预约'}"
  81. @click.stop="onSubscribe"
  82. >{{ subscribeLive }}</view>
  83. <!-- #endif -->
  84. <view class="endContainer" v-if="liveStatus === 103">
  85. <view class="endBox">
  86. <view></view>
  87. <view></view>
  88. <view></view>
  89. <view></view>
  90. </view>
  91. <view>直播已结束</view>
  92. </view>
  93. </view>
  94. </view>
  95. </template>
  96. <script>
  97. const NET = require('@/utils/request')
  98. const API = require('@/config/api')
  99. import { startLiveTemplate } from '@/config/subscribe.js'
  100. import { liveAppid } from '@/config/live.js'
  101. // #ifdef MP-WEIXIN
  102. // const livePlayer = requirePlugin('live-player-plugin')
  103. // #endif
  104. export default {
  105. props: {
  106. liveData: {
  107. type: Object,
  108. default: () => ({
  109. roomId: 0,
  110. anchorNickName: '',
  111. feedsImg: '' // 官方收录封面
  112. })
  113. }
  114. },
  115. data () {
  116. return {
  117. background: ['color1', 'color2', 'color3'],
  118. indicatorDots: false,
  119. autoplay: true,
  120. interval: 2000, // 自动播放间隔时长
  121. duration: 500, // 幻灯片切换时长(ms)
  122. d: 0,
  123. m: 0,
  124. s: 0,
  125. times: [],
  126. liveStatus: 100,
  127. liveTimeTitle: '开播倒计时',
  128. subscribeLive: '立即预约',
  129. timer: null,
  130. isLate: false,
  131. }
  132. },
  133. created() {
  134. this.liveStatus = this.liveData.liveStatus
  135. this.subscribeLive = this.liveData.subscribeStatus === 0 ? '立即预约' : '已预约'
  136. this.getStatus()
  137. this.countTime()
  138. // this.getSubscribeStatus()
  139. },
  140. destroyed() {
  141. clearTimeout(this.timer)
  142. },
  143. methods: {
  144. getStatus() {
  145. if (!this.liveData.roomId) { return }
  146. let _this = this
  147. // #ifdef MP-WEIXIN
  148. livePlayer.getLiveStatus({ room_id: this.liveData.roomId })
  149. .then(res => {
  150. // 101: 直播中, 102: 未开始, 103: 已结束, 104: 禁播, 105: 暂停中, 106: 异常,107:已过期
  151. // _this.liveData.liveStatus = res.liveStatus
  152. _this.liveStatus = res.liveStatus
  153. })
  154. .catch(err => {
  155. })
  156. this.timer = setInterval(() => {
  157. livePlayer.getLiveStatus({ room_id: this.liveData.roomId })
  158. .then(res => {
  159. // 101: 直播中, 102: 未开始, 103: 已结束, 104: 禁播, 105: 暂停中, 106: 异常,107:已过期
  160. _this.liveStatus = res.liveStatus
  161. this.countTime()
  162. })
  163. .catch(err => {
  164. throw new Error(err)
  165. })
  166. }, 60000)
  167. // #endif
  168. },
  169. changeIndicatorDots(e) {
  170. this.indicatorDots = !this.indicatorDots
  171. },
  172. changeAutoplay(e) {
  173. this.autoplay = !this.autoplay
  174. },
  175. intervalChange(e) {
  176. this.interval = e.target.value
  177. },
  178. durationChange(e) {
  179. this.duration = e.target.value
  180. },
  181. countTime(){
  182. var nowtime = new Date().getTime() //获取当前时间
  183. const starttime = new Date(this.liveData.startTime).getTime()
  184. if(this.liveStatus === 102){
  185. if(starttime > nowtime){
  186. var lefttime = starttime - nowtime //距离结束时间的毫秒数
  187. var leftd = Math.floor(lefttime/(1000*60*60)), //计算小时数
  188. leftm = Math.floor(lefttime/(1000*60)%60), //计算分钟数
  189. lefts = Math.floor(lefttime/1000%60); //计算秒数
  190. this.times = [leftd < 10?'0'+ leftd:leftd,leftm < 10?'0'+ leftm:leftm,lefts < 10?'0'+ lefts:lefts]
  191. this.liveTimeTitle = '开播倒计时'
  192. setTimeout(() => {
  193. this.countTime()
  194. },1000)
  195. } else {
  196. this.times = ['00', '00', '00']
  197. this.isLate = true
  198. this.liveTimeTitle = '正在赶来的路上...'
  199. }
  200. }
  201. },
  202. toLive() {
  203. if (!liveAppid || !this.liveData) { return }
  204. // 跳转直播间携带路由参数
  205. // let customParams = encodeURIComponent(JSON.stringify({ path: 'livePage/index', pid: 1 }))
  206. // #ifdef MP-WEIXIN
  207. // wx.navigateTo({
  208. // url: `plugin-private://${liveAppid}/pages/live-player-plugin?room_id=${this.liveData.roomId}`
  209. // // url: `plugin-private://${liveAppid}/pages/live-player-plugin?room_id=${this.liveData.roomId}&custom_params=${customParams}`
  210. // })
  211. // #endif
  212. },
  213. onSubscribe() {
  214. if (this.subscribeLive === '立即预约') {
  215. const _this = this
  216. // #ifdef MP-WEIXIN
  217. uni.requestSubscribeMessage({
  218. tmplIds: [startLiveTemplate],
  219. success (res) {
  220. if (res[startLiveTemplate] === "accept") {
  221. NET.request(API.SubScribeLive, {id: _this.liveData.id }, 'post')
  222. .then(res => {
  223. if (res.data) {
  224. _this.subscribeLive = '已预约'
  225. } else {
  226. uni.showToast({
  227. title: res.message || '订阅失败,请稍后再试!',
  228. icon: "none"
  229. })
  230. }
  231. })
  232. .catch(err => {
  233. uni.showToast({
  234. title: res.message || '订阅失败,请稍后再试!',
  235. icon: "none"
  236. })
  237. })
  238. }
  239. }
  240. })
  241. // #endif
  242. }
  243. }
  244. }
  245. }
  246. </script>
  247. <style lang="scss" scoped>
  248. .live-box{
  249. position: relative;
  250. color: #fff;
  251. width: 100%;
  252. height: 100%;
  253. .cover-img{
  254. width: 100%;
  255. height: 100%;
  256. position: absolute;
  257. z-index: 0;
  258. }
  259. .user{
  260. display: flex;
  261. line-height: 60rpx;
  262. height: 64rpx;
  263. &-pic{
  264. .img{
  265. width: 60rpx;
  266. height: 60rpx;
  267. border: 2px solid rgba(255, 255, 255, 0.5019607843137255);
  268. border-radius: 50%;
  269. overflow: hidden;
  270. }
  271. }
  272. &-name{
  273. font-size: 28rpx;
  274. margin-left: 16rpx;
  275. overflow: hidden;
  276. text-overflow: ellipsis;
  277. white-space: nowrap;
  278. width: 245rpx;
  279. }
  280. }
  281. .live-ongoing{
  282. width: 100%;
  283. height: 100%;
  284. position: relative;
  285. .status{
  286. position: absolute;
  287. top: 22rpx;
  288. left: 22rpx;
  289. //width: 212upx;
  290. height: 48rpx;
  291. // background: rgba(0,0,0,0.3);
  292. // border: 2rpx solid rgba(255,255,255,0.3);
  293. border-radius: 24rpx;
  294. font-size: 20rpx;
  295. line-height: 44rpx;
  296. display: flex;
  297. // padding-right: 8rpx;
  298. &-state{
  299. width: 118rpx;
  300. height: 44rpx;
  301. background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
  302. opacity: 1;
  303. border-radius: 26rpx;
  304. display: flex;
  305. align-items: center;
  306. justify-content: center;
  307. .img{
  308. width: 20rpx;
  309. height: 20rpx;
  310. margin-right: 6rpx;
  311. }
  312. }
  313. &-num{
  314. min-width: 80rpx;
  315. padding: 0 8rpx;
  316. }
  317. }
  318. .user{
  319. position: absolute;
  320. bottom: 62rpx;
  321. left: 20rpx;
  322. }
  323. .products{
  324. position: absolute;
  325. left: 0rpx;
  326. bottom: 20rpx;
  327. width: 100%;
  328. padding:0 20rpx;
  329. .swiper{
  330. height: 34rpx;
  331. line-height: 34rpx;
  332. font-size: 24rpx;
  333. overflow: hidden;
  334. text-overflow:ellipsis;
  335. white-space: nowrap;
  336. }
  337. }
  338. }
  339. .live-other{
  340. position: relative;
  341. height: 100%;
  342. display: flex;
  343. align-items: center;
  344. justify-content: center;
  345. .filter-box-warp{
  346. background-color: #000000;
  347. position: absolute;
  348. top: 0;
  349. left: 0;
  350. width: 100%;
  351. height: 100%;
  352. .filter-box{
  353. position: absolute;
  354. top: -30rpx;
  355. left: -30rpx;
  356. width: 348rpx;
  357. height: 464rpx;
  358. display: flex;
  359. align-items: center;
  360. justify-content: center;
  361. -webkit-filter: blur(20px);
  362. -moz-filter: blur(21px);
  363. -ms-filter: blur(20px);
  364. -o-filter: blur(20px);
  365. padding: 30rpx;
  366. box-sizing: content-box;
  367. }
  368. }
  369. .user{
  370. position: absolute;
  371. top: 20rpx;
  372. left: 20rpx;
  373. }
  374. .count-down{
  375. position: relative;
  376. .text{
  377. font-size: 26rpx;
  378. line-height: 36rpx;
  379. margin-bottom: 16rpx;
  380. opacity: 0.5;
  381. text-align: center;
  382. }
  383. .img{
  384. display: block;
  385. width: 80rpx;
  386. height: 80rpx;
  387. margin: 16rpx auto;
  388. }
  389. .time{
  390. display: flex;
  391. justify-content: space-around;
  392. align-items: center;
  393. &-item{
  394. min-width: 52rpx;
  395. padding: 0 5rpx;
  396. height: 52rpx;
  397. line-height: 52rpx;
  398. background: #FFFFFF;
  399. opacity: 1;
  400. border-radius: 6rpx;
  401. font-size: 26rpx;
  402. color: #C83732;
  403. text-align: center;
  404. .dot{
  405. line-height: 52rpx;
  406. }
  407. }
  408. }
  409. }
  410. .btn-subscribe{
  411. width: 200rpx;
  412. height: 64rpx;
  413. line-height: 64rpx;
  414. background: linear-gradient(90deg, #C83732 0%, #E25C44 100%);
  415. box-shadow: 0rpx 6rpx 12rpx rgba(233, 0, 0, 0.3);
  416. opacity: 1;
  417. border-radius: 6rpx;
  418. color: #fff;
  419. font-size: 24rpx;
  420. text-align: center;
  421. position: absolute;
  422. bottom: 60rpx;
  423. left: 50%;
  424. margin-left: -100rpx;
  425. &.subscribed{
  426. background: #FFFFFF;
  427. color: #999999;
  428. box-shadow: none;
  429. }
  430. }
  431. .endContainer{
  432. position: relative;
  433. .endBox{
  434. width: 40%;
  435. height: 60rpx;
  436. margin: 20rpx auto;
  437. display: flex;
  438. justify-content: space-between;
  439. align-items: flex-end;
  440. view{
  441. width: 0;
  442. border: 2rpx solid #FFF;
  443. }
  444. view:nth-of-type(1){
  445. height: 20%;
  446. }
  447. view:nth-of-type(2){
  448. height: 50%;
  449. }
  450. view:nth-of-type(3){
  451. height: 30%;
  452. }
  453. view:nth-of-type(4){
  454. height: 70%;
  455. }
  456. }
  457. }
  458. }
  459. }
  460. </style>