| .. | .. |
|---|
| 14 | 14 | <view :style="{ height: marTop + 'px' }"></view> |
|---|
| 15 | 15 | <yueyangZone ref=yueyangZoneRef v-if="isYueyangZone" :zoneInfo="info" :careBeanRate="careBeanRate" |
|---|
| 16 | 16 | style="position: relative;z-index: 2;" @goLottery="goLottery" :relationKey="relationKey"></yueyangZone> |
|---|
| 17 | + <view v-if="isYueyangZone" class="detail-btn" @click="goDetail"> |
|---|
| 18 | + <text>消耗明细</text> |
|---|
| 19 | + </view> |
|---|
| 17 | 20 | <view v-else> |
|---|
| 18 | 21 | <view class="expireTime" v-if="expireTime && expireTime.length"> |
|---|
| 19 | 22 | <text>专区将在</text> |
|---|
| 20 | | - <text v-for="(val, index) in expireTime" :key="index"> |
|---|
| 21 | | - <text class="num">{{ val }}</text>{{ expireTimeUnit[index] }} |
|---|
| 23 | + <text v-for="(item, index) in expireTime" :key="index"> |
|---|
| 24 | + <text class="num"><text v-for="(char, ci) in item.digits" :key="ci" |
|---|
| 25 | + class="digit">{{ char }}</text></text>{{ item.unit }} |
|---|
| 22 | 26 | </text> |
|---|
| 23 | 27 | <text>{{ startOrEnd }}</text> |
|---|
| 24 | 28 | </view> |
|---|
| 25 | 29 | <view class="head_img"> |
|---|
| 26 | 30 | <image :src="info.image"></image> |
|---|
| 31 | + </view> |
|---|
| 32 | + <view v-if="info.zoneType == 8 && info.info" class="rich-content"> |
|---|
| 33 | + <rich-text :nodes="info.info"></rich-text> |
|---|
| 34 | + </view> |
|---|
| 35 | + <view v-if="info.zoneType == 8 && info.uploadVideo" class="video-wrap"> |
|---|
| 36 | + <view v-show="!videoControls" style="width:100%;height:750rpx"> |
|---|
| 37 | + <video id="zoneVideo" :src='info.uploadVideo' objectFit="contain" controls |
|---|
| 38 | + style="width:100%;height:100%" show-center-play-btn="true" show-mute-btn="true" muted="true" |
|---|
| 39 | + show-fullscreen-btn="true" auto-pause-if-navigate :custom-cache="false" |
|---|
| 40 | + :enable-progress-gesture="true" show-progress="false" |
|---|
| 41 | + :poster="info.uploadVideoImg || info.image" @pause="zoneVideoPause"></video> |
|---|
| 42 | + </view> |
|---|
| 43 | + <view class="video-poster" v-show="videoControls"> |
|---|
| 44 | + <image class="image" :src="info.uploadVideoImg || info.image"></image> |
|---|
| 45 | + </view> |
|---|
| 46 | + <view class="video-stop" v-show="videoControls" @tap="bindZoneVideoPlay"> |
|---|
| 47 | + <image class="image" src="https://ossacmall.bluedeer.com.cn/app/static/images/stop.png"></image> |
|---|
| 48 | + </view> |
|---|
| 27 | 49 | </view> |
|---|
| 28 | 50 | <view class="tag-wrap-container" :style="'top:' + (marTop) + 'px;'" v-if="info.zoneType == 7"> |
|---|
| 29 | 51 | <view class="tag-wrap"> |
|---|
| .. | .. |
|---|
| 67 | 89 | </view> |
|---|
| 68 | 90 | </view> |
|---|
| 69 | 91 | </view> |
|---|
| 70 | | - <view @click="goLottery" class="lottery_banner" v-if="info && info.isLottery"> |
|---|
| 71 | | - <image class="lottery_bannerImg" |
|---|
| 72 | | - src="https://ossacmall.bluedeer.com.cn/app/static/images/zone_lotteryBanner.gif" mode="widthFix"> |
|---|
| 92 | + <view @click="goLottery" class="lottery_banner" |
|---|
| 93 | + v-if="info && info.isLottery && info.lotteryBanner && lotteryBannerReady"> |
|---|
| 94 | + <image class="lottery_bannerImg" :src="info.lotteryBanner" mode="widthFix" |
|---|
| 95 | + :style="{ height: lotteryBannerHeight }"> |
|---|
| 73 | 96 | </image> |
|---|
| 74 | 97 | </view> |
|---|
| 75 | 98 | <view class="tag-img-container" v-if="info.zoneType == 7"> |
|---|
| .. | .. |
|---|
| 586 | 609 | showMenu: false, |
|---|
| 587 | 610 | selectedMenuArr: [], |
|---|
| 588 | 611 | expireTime: [], |
|---|
| 589 | | - expireTimeUnit: [], |
|---|
| 612 | + countdownToken: 0, |
|---|
| 590 | 613 | isPageShow: false, |
|---|
| 591 | 614 | loginBackFn: null, |
|---|
| 592 | 615 | errText: '', |
|---|
| .. | .. |
|---|
| 596 | 619 | isYueyangZone: false, |
|---|
| 597 | 620 | isOpen: false, // 默认收起,false收起/true展开 |
|---|
| 598 | 621 | currentIndex: -1, // 默认选中第一个【全部】 |
|---|
| 622 | + videoControls: true, // 专区活动视频是否显示海报+播放按钮 |
|---|
| 623 | + zoneVideoContext: '', // 活动视频播放上下文 |
|---|
| 599 | 624 | partitionList: [], |
|---|
| 600 | 625 | partitionProject: {}, |
|---|
| 601 | 626 | tagList: [], |
|---|
| .. | .. |
|---|
| 619 | 644 | stockEmpty: true, |
|---|
| 620 | 645 | urlOption: {}, |
|---|
| 621 | 646 | homeTop: '200', |
|---|
| 647 | + lotteryBannerHeight: '', //抽奖banner预计算高度(rpx),空字符串表示未取到,按原逻辑自适应 |
|---|
| 648 | + lotteryBannerReady: false, //是否已拿到banner尺寸(或已确认拿不到),未就绪前不渲染,避免首帧撑高 |
|---|
| 622 | 649 | hasNewPop: false, |
|---|
| 623 | 650 | leftCoupon: {}, |
|---|
| 624 | 651 | rightCoupon: {}, |
|---|
| .. | .. |
|---|
| 835 | 862 | } |
|---|
| 836 | 863 | }, |
|---|
| 837 | 864 | methods: { |
|---|
| 865 | + /** |
|---|
| 866 | + * 专区活动视频:点击海报播放按钮后播放 |
|---|
| 867 | + */ |
|---|
| 868 | + bindZoneVideoPlay() { |
|---|
| 869 | + if (!this.zoneVideoContext) { |
|---|
| 870 | + this.zoneVideoContext = uni.createVideoContext('zoneVideo', this); |
|---|
| 871 | + } |
|---|
| 872 | + this.$set(this, 'videoControls', false); |
|---|
| 873 | + this.zoneVideoContext.play(); |
|---|
| 874 | + }, |
|---|
| 875 | + zoneVideoPause() { }, |
|---|
| 838 | 876 | handleCouponRule() { |
|---|
| 839 | 877 | this.$refs.personalAndShareCouponRuleRef.show(this.info.ruleContentText) |
|---|
| 840 | 878 | }, |
|---|
| .. | .. |
|---|
| 1195 | 1233 | // that.myCareBean = res2.data.totalCareBeans; |
|---|
| 1196 | 1234 | }); |
|---|
| 1197 | 1235 | }, |
|---|
| 1236 | + goDetail() { |
|---|
| 1237 | + uni.navigateTo({ |
|---|
| 1238 | + url: '/pages/consumption/index?zoneId=' + this.info.id |
|---|
| 1239 | + }) |
|---|
| 1240 | + }, |
|---|
| 1198 | 1241 | goLottery() { |
|---|
| 1199 | 1242 | let that = this; |
|---|
| 1200 | 1243 | var data = { |
|---|
| .. | .. |
|---|
| 1288 | 1331 | }) |
|---|
| 1289 | 1332 | }, |
|---|
| 1290 | 1333 | validAlert(data) { |
|---|
| 1334 | + // 每次重新计算前作废旧的倒计时链,避免多条定时器同时刷新导致数字跳动 |
|---|
| 1335 | + this.countdownToken++ |
|---|
| 1336 | + const token = this.countdownToken |
|---|
| 1291 | 1337 | const { |
|---|
| 1292 | 1338 | startTime, |
|---|
| 1293 | 1339 | expireTime |
|---|
| .. | .. |
|---|
| 1306 | 1352 | let minutes = startTimetamp.getMinutes() |
|---|
| 1307 | 1353 | minutes = minutes < 10 ? '0' + minutes : minutes; |
|---|
| 1308 | 1354 | |
|---|
| 1309 | | - this.countdownTimer(startTime.split('-').join('/'), 'start') |
|---|
| 1355 | + this.countdownTimer(startTime.split('-').join('/'), 'start', token) |
|---|
| 1310 | 1356 | this.startOrEnd = "后开启" |
|---|
| 1311 | 1357 | return |
|---|
| 1312 | | - } |
|---|
| 1313 | | - } |
|---|
| 1314 | | - if (expireTime) { |
|---|
| 1315 | | - const expireTimetamp = new Date(expireTime.split('-').join('/')).getTime(); |
|---|
| 1316 | | - if (expireTimetamp < nowTimestamp) { |
|---|
| 1358 | + } |
|---|
| 1359 | + } |
|---|
| 1360 | + if (expireTime) { |
|---|
| 1361 | + const expireTimetamp = new Date(expireTime.split('-').join('/')).getTime(); |
|---|
| 1362 | + if (expireTimetamp < nowTimestamp) { |
|---|
| 1317 | 1363 | return |
|---|
| 1318 | | - } |
|---|
| 1319 | | - this.countdownTimer(expireTime.split('-').join('/'), 'end') |
|---|
| 1364 | + } |
|---|
| 1365 | + this.countdownTimer(expireTime.split('-').join('/'), 'end', token) |
|---|
| 1320 | 1366 | this.startOrEnd = "后结束" |
|---|
| 1321 | 1367 | } |
|---|
| 1322 | 1368 | }, |
|---|
| .. | .. |
|---|
| 1438 | 1484 | this.$refs.popNewuserRef.show() |
|---|
| 1439 | 1485 | } |
|---|
| 1440 | 1486 | }, |
|---|
| 1487 | + // 预取抽奖banner真实宽高,计算出高度后再渲染,避免加载前被组件默认高度(225px)撑大 |
|---|
| 1488 | + setLotteryBannerSize(info) { |
|---|
| 1489 | + let that = this |
|---|
| 1490 | + that.lotteryBannerHeight = '' |
|---|
| 1491 | + that.lotteryBannerReady = false |
|---|
| 1492 | + if (!info || !info.isLottery || !info.lotteryBanner) { |
|---|
| 1493 | + that.lotteryBannerReady = true |
|---|
| 1494 | + return |
|---|
| 1495 | + } |
|---|
| 1496 | + uni.getImageInfo({ |
|---|
| 1497 | + src: info.lotteryBanner, |
|---|
| 1498 | + success: (img) => { |
|---|
| 1499 | + if (img.width > 0 && img.height > 0) { |
|---|
| 1500 | + that.lotteryBannerHeight = (690 * img.height / img.width).toFixed(2) + 'rpx' |
|---|
| 1501 | + } |
|---|
| 1502 | + that.lotteryBannerReady = true |
|---|
| 1503 | + }, |
|---|
| 1504 | + fail: (err) => { |
|---|
| 1505 | + console.warn('抽奖banner尺寸预取失败,回退为自适应', err) |
|---|
| 1506 | + that.lotteryBannerReady = true |
|---|
| 1507 | + } |
|---|
| 1508 | + }) |
|---|
| 1509 | + }, |
|---|
| 1441 | 1510 | getZoneDetail: function () { |
|---|
| 1442 | 1511 | let that = this; |
|---|
| 1443 | 1512 | let belong = this.$store.getters.belong; |
|---|
| .. | .. |
|---|
| 1445 | 1514 | console.log('专区详情入参::', params) |
|---|
| 1446 | 1515 | getZoneDetail(that.id, params).then(res => { |
|---|
| 1447 | 1516 | that.info = res.data; |
|---|
| 1517 | + that.setLotteryBannerSize(res.data); |
|---|
| 1448 | 1518 | that.updateZoneShareMenu(); |
|---|
| 1449 | 1519 | if (res.data.zoneType == 6) { |
|---|
| 1450 | 1520 | that.setYueyangZone() |
|---|
| .. | .. |
|---|
| 1454 | 1524 | that.homeTop = that.getHomeTop(0.4) |
|---|
| 1455 | 1525 | } |
|---|
| 1456 | 1526 | that.expireTime = []; |
|---|
| 1457 | | - that.expireTimeUnit = []; |
|---|
| 1527 | + that.countdownToken++; |
|---|
| 1458 | 1528 | that.where.page = 1; |
|---|
| 1459 | 1529 | that.getGoodList() |
|---|
| 1460 | 1530 | that.validAlert(res.data) |
|---|
| .. | .. |
|---|
| 1480 | 1550 | } |
|---|
| 1481 | 1551 | }); |
|---|
| 1482 | 1552 | }, |
|---|
| 1483 | | - countdownTimer(expireTime, type) { |
|---|
| 1553 | + countdownTimer(expireTime, type, token) { |
|---|
| 1484 | 1554 | if (!expireTime) return |
|---|
| 1555 | + if (token !== undefined && token !== this.countdownToken) return |
|---|
| 1485 | 1556 | let that = this; |
|---|
| 1486 | 1557 | // 结束时间的时间戳(需传入一个有效的日期对象或时间戳) |
|---|
| 1487 | 1558 | const endTimestamp = new Date(expireTime).getTime(); |
|---|
| .. | .. |
|---|
| 1493 | 1564 | if (type == 'end') { |
|---|
| 1494 | 1565 | if (diff <= 0) { |
|---|
| 1495 | 1566 | this.expireTime = [] |
|---|
| 1496 | | - this.expireTimeUnit = [] |
|---|
| 1497 | 1567 | return |
|---|
| 1498 | 1568 | } else { } |
|---|
| 1499 | 1569 | } else if (type == 'start') { |
|---|
| 1500 | 1570 | if (diff <= 0) { |
|---|
| 1501 | 1571 | this.expireTime = [] |
|---|
| 1502 | | - this.expireTimeUnit = [] |
|---|
| 1503 | 1572 | const expireTime2 = that.info.expireTime |
|---|
| 1504 | 1573 | if (expireTime2) { |
|---|
| 1505 | 1574 | const expireTimetamp = new Date(expireTime2.split('-').join('/')).getTime(); |
|---|
| 1506 | 1575 | if (expireTimetamp < nowTimestamp) { |
|---|
| 1507 | 1576 | return |
|---|
| 1508 | 1577 | } |
|---|
| 1509 | | - this.countdownTimer(expireTime2.split('-').join('/'), 'end') |
|---|
| 1578 | + this.countdownTimer(expireTime2.split('-').join('/'), 'end', token) |
|---|
| 1510 | 1579 | this.startOrEnd = "后结束" |
|---|
| 1511 | 1580 | } |
|---|
| 1512 | 1581 | return |
|---|
| 1513 | 1582 | } |
|---|
| 1514 | 1583 | } |
|---|
| 1584 | + const pad = num => (num < 10 ? '0' + num : String(num)) |
|---|
| 1515 | 1585 | const res = [] |
|---|
| 1516 | | - const unit = [] |
|---|
| 1517 | 1586 | const days = Math.floor(diff / (1000 * 60 * 60 * 24)) |
|---|
| 1518 | 1587 | diff %= (1000 * 60 * 60 * 24) |
|---|
| 1519 | | - if (days > 0) { |
|---|
| 1520 | | - res.push(days); |
|---|
| 1521 | | - unit.push('日') |
|---|
| 1522 | | - } |
|---|
| 1523 | 1588 | // 转换为小时、分钟、秒 |
|---|
| 1524 | 1589 | const hours = Math.floor(diff / (1000 * 60 * 60)); |
|---|
| 1525 | 1590 | diff %= (1000 * 60 * 60); // 剩余毫秒数 |
|---|
| 1526 | | - if (hours > 0) { |
|---|
| 1527 | | - res.push(hours < 10 ? '0' + hours : hours); |
|---|
| 1528 | | - unit.push('时') |
|---|
| 1529 | | - } |
|---|
| 1530 | 1591 | const minutes = Math.floor(diff / (1000 * 60)); |
|---|
| 1531 | | - if (minutes > 0) { |
|---|
| 1532 | | - res.push(minutes < 10 ? '0' + minutes : minutes); |
|---|
| 1533 | | - unit.push('分') |
|---|
| 1534 | | - } |
|---|
| 1535 | 1592 | diff %= (1000 * 60); // 剩余毫秒数 |
|---|
| 1536 | 1593 | const seconds = Math.floor(diff / 1000); |
|---|
| 1537 | | - if (seconds > 0) { |
|---|
| 1538 | | - res.push(seconds < 10 ? '0' + seconds : seconds); |
|---|
| 1539 | | - unit.push('秒') |
|---|
| 1594 | + // 天数为 0 时不展示,时/分/秒始终展示(补 0),保证倒计时长度稳定 |
|---|
| 1595 | + if (days > 0) { |
|---|
| 1596 | + res.push({ |
|---|
| 1597 | + digits: pad(days).split(''), |
|---|
| 1598 | + unit: '日' |
|---|
| 1599 | + }) |
|---|
| 1540 | 1600 | } |
|---|
| 1601 | + res.push({ |
|---|
| 1602 | + digits: pad(hours).split(''), |
|---|
| 1603 | + unit: '时' |
|---|
| 1604 | + }) |
|---|
| 1605 | + res.push({ |
|---|
| 1606 | + digits: pad(minutes).split(''), |
|---|
| 1607 | + unit: '分' |
|---|
| 1608 | + }) |
|---|
| 1609 | + res.push({ |
|---|
| 1610 | + digits: pad(seconds).split(''), |
|---|
| 1611 | + unit: '秒' |
|---|
| 1612 | + }) |
|---|
| 1541 | 1613 | this.expireTime = res |
|---|
| 1542 | | - this.expireTimeUnit = unit |
|---|
| 1543 | 1614 | if (this.isPageShow) { |
|---|
| 1544 | 1615 | setTimeout(() => { |
|---|
| 1545 | | - that.countdownTimer(expireTime, type) |
|---|
| 1616 | + that.countdownTimer(expireTime, type, token) |
|---|
| 1546 | 1617 | }, 1000) |
|---|
| 1547 | 1618 | } |
|---|
| 1548 | 1619 | }, |
|---|
| .. | .. |
|---|
| 1629 | 1700 | .lottery_banner { |
|---|
| 1630 | 1701 | margin: 15rpx auto; |
|---|
| 1631 | 1702 | width: 690rpx; |
|---|
| 1632 | | - height: 120rpx; |
|---|
| 1633 | 1703 | text-align: center; |
|---|
| 1634 | 1704 | } |
|---|
| 1635 | 1705 | |
|---|
| 1636 | 1706 | .lottery_bannerImg { |
|---|
| 1637 | 1707 | width: 690rpx; |
|---|
| 1638 | | - height: 120rpx; |
|---|
| 1639 | 1708 | } |
|---|
| 1640 | 1709 | |
|---|
| 1641 | 1710 | .tag-wrap-container { |
|---|
| .. | .. |
|---|
| 1836 | 1905 | transform: translate(0, -50%); |
|---|
| 1837 | 1906 | } |
|---|
| 1838 | 1907 | |
|---|
| 1908 | +.detail-btn { |
|---|
| 1909 | + border: 2rpx solid #fff; |
|---|
| 1910 | + border-top-left-radius: 20rpx; |
|---|
| 1911 | + border-bottom-left-radius: 20rpx; |
|---|
| 1912 | + padding: 10rpx; |
|---|
| 1913 | + background-color: #daf2b2; |
|---|
| 1914 | + color: #1e984f; |
|---|
| 1915 | + width: 50rpx; |
|---|
| 1916 | + position: fixed; |
|---|
| 1917 | + top: 200rpx; |
|---|
| 1918 | + right: 0rpx; |
|---|
| 1919 | + line-height: 1rem; |
|---|
| 1920 | + z-index: 99; |
|---|
| 1921 | +} |
|---|
| 1922 | + |
|---|
| 1839 | 1923 | .head_img { |
|---|
| 1840 | 1924 | width: 750rpx; |
|---|
| 1841 | 1925 | height: 422rpx; |
|---|
| .. | .. |
|---|
| 1844 | 1928 | width: 750rpx; |
|---|
| 1845 | 1929 | height: 422rpx; |
|---|
| 1846 | 1930 | } |
|---|
| 1931 | +} |
|---|
| 1932 | + |
|---|
| 1933 | +.rich-content { |
|---|
| 1934 | + padding: 24rpx 30rpx; |
|---|
| 1935 | + background-color: #fff; |
|---|
| 1936 | +} |
|---|
| 1937 | + |
|---|
| 1938 | +.video-wrap { |
|---|
| 1939 | + position: relative; |
|---|
| 1940 | + width: 100%; |
|---|
| 1941 | + height: 750rpx; |
|---|
| 1942 | + background-color: #000; |
|---|
| 1943 | +} |
|---|
| 1944 | + |
|---|
| 1945 | +.video-wrap .video-poster { |
|---|
| 1946 | + position: absolute; |
|---|
| 1947 | + top: 0; |
|---|
| 1948 | + left: 0; |
|---|
| 1949 | + width: 100%; |
|---|
| 1950 | + height: 750rpx; |
|---|
| 1951 | + z-index: 9; |
|---|
| 1952 | +} |
|---|
| 1953 | + |
|---|
| 1954 | +.video-wrap .video-poster .image { |
|---|
| 1955 | + width: 100%; |
|---|
| 1956 | + height: 100%; |
|---|
| 1957 | +} |
|---|
| 1958 | + |
|---|
| 1959 | +.video-wrap .video-stop { |
|---|
| 1960 | + position: absolute; |
|---|
| 1961 | + top: 50%; |
|---|
| 1962 | + left: 50%; |
|---|
| 1963 | + width: 136rpx; |
|---|
| 1964 | + height: 136rpx; |
|---|
| 1965 | + margin-top: -68rpx; |
|---|
| 1966 | + margin-left: -68rpx; |
|---|
| 1967 | + z-index: 9; |
|---|
| 1968 | +} |
|---|
| 1969 | + |
|---|
| 1970 | +.video-wrap .video-stop .image { |
|---|
| 1971 | + width: 100%; |
|---|
| 1972 | + height: 100%; |
|---|
| 1847 | 1973 | } |
|---|
| 1848 | 1974 | |
|---|
| 1849 | 1975 | .toolbarList { |
|---|
| .. | .. |
|---|
| 2062 | 2188 | padding: 15rpx; |
|---|
| 2063 | 2189 | padding-left: 30rpx; |
|---|
| 2064 | 2190 | color: #979797; |
|---|
| 2191 | + font-size: 26rpx; |
|---|
| 2065 | 2192 | |
|---|
| 2066 | 2193 | .num { |
|---|
| 2194 | + display: inline-block; |
|---|
| 2067 | 2195 | color: #000000; |
|---|
| 2068 | 2196 | background: #FFE20E; |
|---|
| 2069 | | - padding: 0 10rpx; |
|---|
| 2197 | + padding: 0 6rpx; |
|---|
| 2198 | + margin: 0 4rpx; |
|---|
| 2199 | + vertical-align: middle; |
|---|
| 2200 | + } |
|---|
| 2201 | + |
|---|
| 2202 | + /* 每个数字固定宽度,避免倒计时跳动时宽度忽长忽短 */ |
|---|
| 2203 | + .digit { |
|---|
| 2204 | + display: inline-block; |
|---|
| 2205 | + width: 19rpx; |
|---|
| 2206 | + text-align: center; |
|---|
| 2070 | 2207 | } |
|---|
| 2071 | 2208 | } |
|---|
| 2072 | 2209 | </style> |
|---|