function Point (x, y) { this.x = x this.y = y } function Map (w, h) { this.width = w this.height = h } // 画布中生成随机不重叠的坐标 // 坐标点以左上角为中心 function RandomCoordinate (conf) { conf = conf || {} this.el = conf.el || '' // 画布选择器或者dom this.pointSize = conf.pointSize || new Map(1, 1) // 坐标点半径(最大) this.total = conf.total || 1 // 生成多少个随机不重叠坐标 this.pointCoordList = [] // 生成坐标点数组 this.init = function () { if (!this.el) return console.warn('画布选择器必传') // 获取画布宽高 this.map = this.getMapSize() this.getPointCoordLimits() this.create() } this.getMapSize = function () { this.$el = $(this.el) var w = this.$el.width() var h = this.$el.height() return new Map(w, h) } this.getPointCoordLimits = function () { var xMax = this.map.width - this.pointSize.width var yMax = this.map.height - this.pointSize.height if (xMax <= 0) { xMax = 1 } if (yMax <= 0) { yMax = 1 } this.coordLimits = new Point(xMax, yMax) } // this.check // 检查是否和已创建的有重叠 this.checkListOverlap = function (p) { if (this.pointCoordList.length <= 0) return true var pass = true // pass,所有都不重叠 for (var i = 0; i < this.pointCoordList.length; i++) { var overlap = this.checkOverlap(p, this.pointCoordList[i]) if (overlap) { pass = false break } } return pass }, // point为矩形左上的碰撞检测:碰撞返回true // 利用两圆相切,圆心距离小于2r表示两圆相交(r圆半径)。把矩形对角线看作圆的直径 // 如果两个矩形左上角的点间距离大于矩形对角线长度,则认为两矩形无碰撞(无重叠) // 参考:https://segmentfault.com/a/1190000017463616 this.checkOverlap = function (nPoint, oPoint) { // 两矩形左上角坐标距离(三角函数) // https://www.qttc.net/171-javascript-get-two-points-distance.html var dx = Math.abs(nPoint.x - oPoint.x) var dy = Math.abs(nPoint.y - oPoint.y) var distance = Math.sqrt(dx * dx + dy * dy) // 矩形对角线长度 var w = this.pointSize.width var h = this.pointSize.height var diagonal = Math.sqrt(w * w + h * h) return distance <= diagonal } // 创建一个坐标 this.createOne = function () { var createTimes = 0 var createFailTimes = 0 var maxCreateFailTime = 200 var x,y while (createFailTimes < maxCreateFailTime) { createTimes++ x = Math.floor(Math.random() * this.coordLimits.x) y = Math.floor(Math.random() * this.coordLimits.y) var point = new Point(x, y) var pass = this.checkListOverlap(point) if (pass) { this.pointCoordList.push(point) break } else { createFailTimes++ } } if (createFailTimes >= maxCreateFailTime) { console.log('随机生成坐标%s次失败,停止随机生成', maxCreateFailTime) } else { console.log('随机生成坐标次数:%s,\n随机生成坐标失败次数:%s\n获得坐标:', createTimes, createFailTimes, JSON.stringify(point)) } } this.create = function () { for (var i = 0; i < this.total; i++) { this.createOne() } this.pointCoordList = this.pointCoordList.sort(function (a, b) { return a.x - b.x }) } this.init() } // 判断活动是否结束 var initPageTime = new Date().getTime() var initActiveOverCheck = -1 function activeOverCheck (endTime, callback) { if (initPageTime >= endTime) { return callback() } clearTimeout(initActiveOverCheck) var reloadTime = endTime - new Date().getTime() if (reloadTime <= (10 * 60 * 1000) ) { initActiveOverCheck = setTimeout(function () { callback && callback() }, reloadTime) } } // toast上限提示 function toastFn (text, duration) { if (!duration) { duration = 1000 } var _html = "" _html+='
' _html+='' + text + '
' $('body').append(_html) setTimeout(function(){ $(".custom-toast").fadeOut().remove(); },duration) } // 展示弹窗 function showDialogOfType (type) { $('#active-tip-modal').attr('data-modal-type', 'success').modal('show') $('#active-tip-modal').attr('data-modal-type', 'over').modal('show') $('#active-tip-modal').attr('data-modal-type', 'code').modal('show') var modal = $('#active-tip-modal') modal.attr('data-modal-type', type).modal('show') if (type === 'over') { modal.off('click') } else { modal.off('click').on('click', function () { modal.modal('hide') }) } } // 固定事件 $(function () { // 弹窗按钮事件 $('#dialog-button--over').on('click', function () { window.open('/swordfish/frontPage/share/sess/index') }) $('#dialog-button--success').on('click', function () {}) }) var task = new Vue({ el: '#main-app', delimiters: ['${', '}'], data: { conf: { before: 0, // 单位: s clock: '10:00:00', end: 0, // 单位: s now: 0, // 单位: s start: 0 // 单位: s }, activeState: '', lastTimestamp: 0, // 单位: ms yureConf: { total: 0, got: false }, yureInfo: { timerId: null, tipText: '', buttonText: '点击免费领', buttonDisabled: false }, couponList: [], progress: { min: 0, max: 1500, current: 0, // 当前剑鱼币 pointImgMap: { unreceived: '/frontRouter/pc/activity/image/unreceived@2x.png', received: '/frontRouter/pc/activity/image/received@2x.png', wait: '/frontRouter/pc/activity/image/received@2x.png' }, anchorList: [ { id: '', className: 'first', rate: 0, // 进度,单位%,最大为100 pointImg: '', // ''/unreceived/received anchorText: '0剑鱼币' }, { id: '800', className: 'unreceived', rate: 80, pointImg: 'unreceived', anchorText: '800剑鱼币', tipText: '1个月超级订阅' }, { id: '1500', className: 'unreceived', rate: 100, pointImg: 'unreceived', anchorText: '1500剑鱼币', tipText: '1个月超级订阅' } ], }, // 任务球 missionsList: [ { id: 'buyvip', className: '', x: 190, y: 120, num: 800, unit: '剑鱼币', complete: false, hide: true, name: '购买超级订阅' // 任务描述 }, { id: 'invite', className: 'delay-100', x: 380, y: 0, num: 500, unit: '剑鱼币', complete: false, hide: true, name: '邀请领好礼' }, { id: 'share', className: 'delay-300', x: 900, y: 80, num: 200, unit: '剑鱼币', complete: false, hide: true, name: '分享活动' } ], copyLinkText: location.href, rewardList: [], dialog: { myReward: false }, rulesList: [ { text: '活动时间:预热期:7.25-7.31 、活动期:8.1-8.14。' }, { text: '预热福利:预热期内用户每天10点开始领取,每天限量500份,每天0点数量更新,每人仅限领取一次,数量有限,先到先得。' }, { text: '福利一:官方补贴限时抢 购买超级订阅立减:活动期间内新购、续费、升级用户均可参加,通过活动页领取优惠券后购买超级订阅可享受满减,不同额度优惠券一人仅限领取1张,优惠券仅限领取后活动期内使用,过期无效。' }, { text: '福利二:做任务 得2个月超级订阅:活动期内,用户分别完成各任务即可获得相对应的剑鱼币,达到1000剑鱼币领1个月超级订阅,达到1500剑鱼币领1个月超级订阅,领取后在原有购买时间上延长所领取奖励的时长,在订单支付期间,完成【购买超级订阅】可获得800剑鱼币,用户新购、续费、升级皆可获得剑鱼币奖励,完成【邀请领好礼】可获得500剑鱼币,完成【分享活动】可获得200剑鱼币;完成购买超级订阅、邀请领好礼、分享活动三个任务且活动页剑鱼币累计达到1000剑鱼币或1500剑鱼币即可领取超级订阅,累计可领2个月,通过其他形式获取的剑鱼币将不作为领取奖励的依据,领取后在【我的奖励】中查看。' }, { text: '福利三:大会员最高立减7999元 送6个月使用时长:活动期内商机版2.0最高立减3199元,购买赠送6个月使用时长,专家版2.0最高立减7999元,购买赠送6个月使用时长,点击【了解更多】可详细了解大会员服务内容,详情请致电咨询:400-108-6670,线下购买享优惠。' }, { text: '本次活动不支持作弊行为,涉嫌违法、违规参与活动的用户,剑鱼标讯将有权取消您的活动参与资格,并回收已获得的相关奖励,由于不可抗力因素等情况导致活动异常,剑鱼标讯将有权采取调整等措施。' }, { text: '法律许可范围内本次活动解释权归北京剑鱼信息技术有限公司所有。' } ] }, computed: { rate: function () { var calcRate = (this.progress.current / this.progress.max) * 100 if (calcRate > 100) { calcRate = 100 } if (calcRate < 0) { calcRate = 0 } return calcRate }, blinkTextShow: function () { var anchorList = this.progress.anchorList var rate = this.rate var exist = false for (var i = 0; i < anchorList.length; i++) { if (rate === anchorList[i].rate) { exist = true break } } return !exist }, progressAnchorList: function () { return this.progress.anchorList }, lastTimeText: function () { if (this.lastTimestamp > 0) { var lastTimeConf = this.calcLastTimeDiff(this.lastTimestamp) var days = lastTimeConf.days var hours = lastTimeConf.hours var minutes = lastTimeConf.minutes var seconds = lastTimeConf.seconds var hms = [this.add0(hours), this.add0(minutes), this.add0(seconds)].join(':') if (days > 0) { return days + '天 ' + hms } else { return hms } // return days + '天 ' + hms } else { return '' } }, yureSectionShow: function () { return this.activeState === 'waiting' || this.activeState === 'yureing' }, yureButtonShow: function () { var lastTimeConf = this.calcLastTimeDiff(this.lastTimestamp) var days = lastTimeConf.days if (this.yureInfo.buttonText) { return !(days < 1 && this.yureConf.total <= 0) } else { return false } } }, created: function () { this.ajaxActiveStatus() this.ajaxProgress() this.ajaxList() }, mounted: function () { // this.calcPointList() this.stickyTopEvents() }, methods: { add0: function (t) { return t < 10 ? ('0' + t) : t }, ajaxActiveStatus: function () { var _this = this $.ajax({ url: '/jyActivity/membershipDay/period', type: 'post', success: function (res) { if (res.data) { for (var key in _this.conf) { _this.conf[key] = res.data[key] } if (Math.abs(initPageTime - res.data.now * 1000) > 5000) { initPageTime = res.data.now } activeOverCheck(res.data.end * 1000, function () { showDialogOfType('over') }) _this.initPageState() } }, complete: function () { _this.getYuReCouponCount() _this.getFuLi2CouponList() } }) }, initPageState: function () { var state = this.checkActiveState() var yureTextDOM = $('.timeline-item.yure .t-r-b-r') if (state === 'yureing') { this.startTopTimer() yureTextDOM.text('进行中') } else { yureTextDOM.text('已结束') if (state === 'activating') { // 活动进行中 } else { } } }, // 检查状态 checkActiveState: function (now) { if (!now) { now = Date.now() } var before = this.conf.before * 1000 var start = this.conf.start * 1000 var end = this.conf.end * 1000 var stateArr = ['waiting', 'yureing', 'activating', 'ended'] var state = 'waiting' if (now < before) { state = stateArr[0] // 预热未开始 } else if (before <= now && now < start) { state = stateArr[1] // 预热中 } else if (start <= now && now < end) { state = stateArr[2] // 活动进行中 } else { state = stateArr[3] // 活动已结束 } this.activeState = state return state }, // type=yure判断预热是否开始 // type=active 判断活动是否开始 activeNotStartToast: function (type) { var state = this.checkActiveState() type = type || 'active' if (state === 'ended') { toastFn('活动已结束') } else if (state === 'waiting') { toastFn('活动尚未开始,敬请期待') } else { if (type === 'yure') { if (state === 'activating') { // 预热已结束 toastFn('预热已结束') } } else { if (state === 'yureing') { toastFn('活动尚未开始,敬请期待') } } } }, startTopTimer: function () { var _this = this var start = this.conf.start * 1000 var timerId = setInterval(function () { var current = Date.now() if (_this.lastTimestamp < 0) { clearInterval(timerId) } _this.lastTimestamp = start - current }, 1000) }, calcYuReText: function () { var _this = this var buttonText = '' var tipText = '' var buttonDisabled = true if (this.yureInfo.timerId) { clearInterval(this.yureInfo.timerId) } if (this.activeState === 'yureing') { // 当天时间 var todayString = new Date().pattern('yyyy/MM/dd') // 当领券开始时间 var yureCouponStartTime = [todayString, this.conf.clock].join(' ') var yureCouponStartStamp = +new Date(yureCouponStartTime) // 计算倒计时 var diff = yureCouponStartStamp - Date.now() if (diff > 0) { // 预热当天未开始抢券 buttonDisabled = true buttonText = '今日10点开抢' // 创建定时器刷新倒计时 this.yureInfo.timerId = setInterval(function () { var d = yureCouponStartStamp - Date.now() var obj = _this.calcLastTimeDiff(d) if (d <= 0) { clearInterval(_this.yureInfo.timerId) _this.calcYuReText() } else { // 计算倒计时 tipText = [_this.add0(obj.hours), _this.add0(obj.minutes), _this.add0(obj.seconds)].join(':') _this.yureInfo.tipText = tipText } }, 1000) } else { if (this.yureConf.got) { // 已领取过 buttonDisabled = false buttonText = '去查看' tipText = '已领取成功' } else { buttonDisabled = this.yureConf.total <= 0 // 券是否有剩余 if (this.yureConf.total > 0) { buttonText = '点击免费领' tipText = '今日还剩' + this.yureConf.total + '份' } else { // 今日券领完了 buttonText = '今天已抢完' tipText = '今天已经抢完啦~明天再来吧' } } } } else { // 预热未开始或者预热结束 } this.yureInfo.buttonDisabled = buttonDisabled this.yureInfo.buttonText = buttonText this.yureInfo.tipText = tipText }, calcLastTimeDiff: function (timestamp) { var diff = moment.duration(Math.abs(timestamp)) var days = diff.days() var hours = diff.hours() var minutes = diff.minutes() var seconds = diff.seconds() return { days: days, hours: hours, minutes: minutes, seconds: seconds } }, // 预热优惠券数量查询 getYuReCouponCount: function () { var _this = this $.ajax({ url: '/jyActivity/membershipDay/getDailyBoonDetail', type: 'post', success: function (res) { if (res.data) { _this.yureConf.got = res.data.got || false _this.yureConf.total = res.data.total || 0 _this.calcYuReText() } } }) }, receiveYuReCoupon: function () { if (this.yureInfo.buttonDisabled) { toastFn('活动尚未开始,敬请期待') } else if (this.yureInfo.buttonText === '去查看') { // 领过了 this.toBuyVip() } else { // 没领过 this.receiveYuReCouponAjax() } }, // 领取预热优惠券 receiveYuReCouponAjax: function () { var _this = this $.ajax({ url: '/jyActivity/membershipDay/getDailyBoonSVip', type: 'post', success: function (res) { if (res.data) { _this.getYuReCouponCount() // 刷新我的奖励列表 _this.ajaxList() } } }) }, receiveActiveButtonText: function (item) { if (item.IsReceive) { return '立即领取' } else { if (item.IsUser) { return '去使用' } else { return '已使用' } } }, receiveActiveCoupon: function (coupons) { if (this.activeState !== 'activating') { return this.activeNotStartToast() } if (coupons.length === 0) return if (coupons.length === 1) { var item = coupons[0] if (!item.IsReceive && item.IsUser) { return this.toBuyVip() } } var idArr = [] coupons.forEach(function (item) { if (item.IsReceive) { idArr.push(item.LotteryIdStr) } }) this.receiveActiveCouponAjax(idArr) }, // 领取活动优惠券 receiveActiveCouponAjax: function (ids) { if (ids.length === 0) return var _this = this $.ajax({ url: '/jyActivity/membershipDay/getLottery', type: 'post', contentType: 'application/json', data: JSON.stringify({ lotteryIds: ids.join(',') }), success: function (res) { if (res.data) { _this.couponList.forEach(function (item) { if (ids.indexOf(item.LotteryIdStr) !== -1) { item.IsReceive = false } }) // 刷新我的奖励列表 _this.ajaxList() } } }) }, addTipText: function (list) { var prefix = '超级订阅' var priceArr = [ { price: 38, text: '1个月+1个省' }, { price: 99, text: '1个季+1个省' }, { price: 380, text: '1年+1个省' }, { price: 599, text: '1个月+全国' }, ] var arr = list.sort(function (a, b) { return a.Reduce - b.Reduce }) list.forEach(function (item) { var reduce = item.Reduce var full = item.Full for (var i = 0; i < priceArr.length; i++) { if (priceArr[i].price - full >= 0) { var pay = priceArr[i].price - reduce item.tipText = prefix + priceArr[i].text + ':券后' + pay + '元' break } } }) return arr }, // 获取福利2优惠券列表 getFuLi2CouponList: function () { var _this = this $.ajax({ url: '/jyActivity/membershipDay/lotteryList', type: 'post', success: function (res) { if (res.data) { _this.couponList = _this.addTipText(res.data) || [] // 刷新我的奖励列表 _this.ajaxList() } } }) }, calcPointList: function () { var dom = this.$refs.missions window.points = new RandomCoordinate({ el: dom, total: this.missionsList.length, pointSize: new Map(142, 160) }) var pointList = points.pointCoordList for (var i = 0; i < this.missionsList.length; i++) { this.missionsList[i].x = pointList[i].x this.missionsList[i].y = pointList[i].y } }, leaveCanvas: function (item) { var dom = $('.mission-list-item.' + item.id) dom.removeClass('floating') var baseX = 84 var baseY = 34 // 终点坐标 var current = { x: baseX + 1000 * this.rate / 100, y: baseY + $('.mission-list').height() - $('.blink-point').height() / 2 } item.x = current.x item.y = current.y this.$nextTick(function () { dom.addClass('exit') }) }, onClickListItem: function (item) { if (item.icon === 'jy-svip') { window.open('/front/swordfish/toMyOrder') } else if (item.icon === 'jy-coin') { window.open('/swordfish/integral/index/detail') } else { // 跳转我的奖券 window.open('/swordfish/coupon/') // this.toBuyVip() } }, onClickReceive: function (type, item) { if (this.activeState !== 'activating') return toastFn('活动尚未开始,敬请期待') if (item.className === 'received') return var status = false if (type === 'schedule') { if (item.className === 'wait') { status = true } else { var text = '尚未达到领取条件,无法领取' switch (item.id) { // 800 case this.progressAnchorList[1].id: { text = '尚未达到'+ this.progressAnchorList[1].id +'剑鱼币,无法领取' break } // 1500 case this.progressAnchorList[2].id: { text = '尚未达到'+ this.progressAnchorList[2].id +'剑鱼币,无法领取' break } } return toastFn(text, 1500) } } else if (type === 'mission' && item.complete) { status = true } if (!status) { var _this = this switch (item.id) { case 'buyvip': { this.toBuyVip() break } case 'invite': { window.open('/swordfish/frontPage/share/sess/index') break } case 'share': { // 分享 _this.scrollTo('.copy-share-container') break } } return } var _this = this if (type === 'mission') { this.leaveCanvas(item) } this.ajaxReceive({ type: type, value: item.id }, function (result, msg) { if (result) { switch (item.id) { case 'buyvip': case 'invite': case 'share': { toastFn('已成功领取' + item.num + '剑鱼币', 1500) break } case '800': { $('.active-tip--success .text-give-day').text('7天') showDialogOfType('success') break } case '1500': { $('.active-tip--success .text-give-day').text('1个月') showDialogOfType('success') break } } _this.ajaxActiveStatus() _this.ajaxProgress() _this.ajaxList() } else { toastFn(msg, 1500) } }) }, ajaxReceive: function (data, callback) { var _this = this $.ajax({ url: '/jyActivity/membershipDay/receive', type: 'post', contentType: 'application/json', data: JSON.stringify(data), success: function (res) { callback(res.data, res.error_msg) // 刷新我的奖励列表 _this.ajaxList() } }) }, ajaxProgress: function () { var _this = this $.ajax({ url: '/jyActivity/membershipDay/schedule', type: 'post', success: function (res) { if (res.error_code === 0 && res.data) { _this.progress.current = res.data.nowNum _this.missionsList[0].complete = res.data.missions.buyvip !== 0 _this.missionsList[1].complete = res.data.missions.invite !== 0 _this.missionsList[2].complete = res.data.missions.share !== 0 _this.missionsList[0].hide = res.data.missions.buyvip === -1 _this.missionsList[1].hide = res.data.missions.invite === -1 _this.missionsList[2].hide = res.data.missions.share === -1 var anchorStatus = { 1: 'wait', 0: 'unreceived', '-1': 'received', } var imgStatus = { 1: 'unreceived', 0: 'unreceived', '-1': 'received', } _this.progress.anchorList[1].className = anchorStatus[res.data.schedule['800']] _this.progress.anchorList[2].className = anchorStatus[res.data.schedule['1500']] _this.progress.anchorList[1].pointImg = imgStatus[res.data.schedule['800']] _this.progress.anchorList[2].pointImg = imgStatus[res.data.schedule['1500']] } } }) }, ajaxList: function () { var _this = this $.ajax({ url: '/jyActivity/myAward/awardlist', type: 'post', contentType: 'application/json', data: JSON.stringify({ code: 'membershipDay', pageSize: 10, pageNum: 0 }), success: function (res) { if (res.error_code === 0 && res.data) { if (res.data.list && typeof res.data.list.map === 'function') { _this.rewardList = res.data.list.map(function (v) { var icon = '' if (v.award.indexOf('剑鱼币') > -1) { icon = 'jy-coin' } else if (v.award.indexOf('订阅') > -1) { icon = 'jy-svip' } else { icon = 'jy-coupon' } return { id: v._id, icon: icon, rewardText: v.award, receiveTime: new Date(v.date * 1000).pattern('yyyy-MM-dd HH:mm:ss'), receiveFrom: v.getway } }) } } } }) }, receiveFuli3: function () { if (this.activeState !== 'activating') { return this.activeNotStartToast() } vm.isNeedSubmit('super_membership_day',function(){ vm.showSuccess = true }) }, doCopy: function () { if (this.activeState === 'activating') { var _this = this $.ajax({ url: '/jyActivity/membershipDay/doShare', type: 'post', success: function (res) { if (res.data) { _this.$toast('复制成功') _this.ajaxProgress() } } }) } else { // toastFn('活动尚未开始,敬请期待') this.activeNotStartToast() } this.copyText('快来和我一起参与吧!剑鱼超级会员节,百万补贴限量抢,快速获取商机信息》\n' + this.copyLinkText) }, copyText: function (text) { const input = document.createElement('textarea') // js创建一个input输入框 input.value = text // 将需要复制的文本赋值到创建的input输入框中 document.body.appendChild(input) // 将输入框暂时创建到实例里面 input.select() // 选中输入框中的内容 document.execCommand('copy') // 执行复制操作 document.body.removeChild(input) // 最后删除实例中临时创建的input输入框,完成复制操作 }, scrollTo: function (className) { setTimeout(function () { var offsetTop = $(className)[0].offsetTop - 64 * 2 $(window).scrollTop(offsetTop) }, 100) }, stickyTopEvents: function () { var _this = this var fixedTop = $('.fixed-top.top-timeline') var showHide = function () { var scrollTop = $(window).scrollTop() if (scrollTop > 600) { fixedTop.show() } else { fixedTop.hide() } } showHide() $(window).on('scroll', function () { showHide() }) fixedTop.on('click', '.timeline-item', function (e) { $(e.currentTarget).addClass('active').siblings().removeClass('active') var className = $(e.currentTarget).attr('data-s-class') _this.scrollTo('.' + className) }) }, toMemberPage: function () { window.open('/big/page/index') }, toBuyVip: function () { if (window.vipStatus > 0) { window.open('/swordfish/page_big_pc/free/svip/buy?type=upgrade') } else { // 去购买 window.open('/swordfish/page_big_pc/free/svip/buy?type=buy') } } } })