| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 | const ADType = {  RewardedVideo: 'RewardedVideo',  FullScreenVideo: 'FullScreenVideo',  Interstitial: 'Interstitial'}const EventType = {  Load: 'load',  Close: 'close',  Error: 'error'}const EXPIRED_TIME = 1000 * 60 * 30const ProviderType = {  CSJ: 'csj',  GDT: 'gdt'}const RETRY_COUNT = 1class AdBase {  constructor (adInstance, options = {}) {    this._isLoad = false    this._isLoading = false    this._isPlaying = false    this._lastLoadTime = 0    this._lastError = null    this._retryCount = 0    if (options.retry !== undefined) {      this._retry = options.retry    } else {      this._retry = true    }    this._loadCallback = null    this._closeCallback = null    this._errorCallback = null    const ad = this._ad = adInstance    ad.onLoad((e) => {      this._isLoading = false      this._isLoad = true      this._lastLoadTime = Date.now()      this.onLoad()    })    ad.onClose((e) => {      this._isLoad = false      this._isPlaying = false      this.onClose(e)    })    ad.onVerify && ad.onVerify((e) => {      // e.isValid    })    ad.onError(({      code,      message    }) => {      this._isLoading = false      const data = {        code: code,        errMsg: message      }      if (this._retry && code === -5008) {        this._loadAd()        return      }      if (this._retry && this._retryCount < RETRY_COUNT) {        this._retryCount += 1        this._loadAd()        return      }      this._lastError = data      this.onError(data)    })  }  get isExpired () {    return (this._lastLoadTime !== 0 && (Math.abs(Date.now() - this._lastLoadTime) > EXPIRED_TIME))  }  get isLoad () {    return this._isLoad  }  get isLoading () {    return this._isLoading  }  getProvider () {    return this._ad.getProvider()  }  load (onload, onerror) {    this._loadCallback = onload    this._errorCallback = onerror    if (this._isPlaying) {      onerror && onerror()      return    }    if (this._isLoading) {      return    }    if (this._isLoad) {      this.onLoad()      return    }    this._retryCount = 0    this._loadAd()  }  show (onclose, onshow) {    this._closeCallback = onclose    if (this._isLoading || this._isPlaying || !this._isLoad) {      return    }    if (this._lastError !== null) {      this.onError(this._lastError)      return    }    const provider = this.getProvider()    if (provider === ProviderType.CSJ && this.isExpired) {      if (this._retry) {        this._loadAd()      } else {        this.onError(this._lastError)      }      return    }    this._isPlaying = true    this._ad.show()    onshow && onshow()  }  onLoad (e) {    if (this._loadCallback != null) {      this._loadCallback()    }  }  onClose (e) {    if (this._closeCallback != null) {      this._closeCallback({        isEnded: e.isEnded      })    }  }  onError (e) {    if (this._errorCallback != null) {      this._errorCallback(e)    }  }  destroy () {    this._ad.destroy()  }  _loadAd () {    this._isLoad = false    this._isLoading = true    this._lastError = null    this._ad.load()  }}class RewardedVideo extends AdBase {  constructor (options = {}) {    super(plus.ad.createRewardedVideoAd(options), options)  }}class FullScreenVideo extends AdBase {  constructor (options = {}) {    super(plus.ad.createFullScreenVideoAd(options), options)  }}class Interstitial extends AdBase {  constructor (options = {}) {    super(plus.ad.createInterstitialAd(options), options)  }}class AdHelper {  constructor (adType) {    this._ads = {}    this._adType = adType    this._lastWaterfallIndex = -1  }  load (options, onload, onerror) {    if (!options.adpid || this.isBusy(options.adpid)) {      return    }    this.get(options).load(onload, onerror)  }  show (options, onload, onerror, onclose, onshow) {    const ad = this.get(options)    if (ad.isLoad) {      this._lastWaterfallIndex = -1      ad.show((e) => {        onclose && onclose(e)      }, () => {        onshow && onshow()      })    } else {      ad.load(() => {        this._lastWaterfallIndex = -1        onload && onload()        ad.show((e) => {          onclose && onclose(e)        }, () => {          onshow && onshow()        })      }, (err) => {        onerror && onerror(err)      })    }  }  // 底价预载逻辑  loadWaterfall (options, onload, onfail, index = 0) {    const {      adpid,      urlCallback    } = options    if (!Array.isArray(adpid)) {      return    }    const options2 = {      adpid: adpid[index],      urlCallback,      retry: false    }    console.log('ad.loadWaterfall::index=' + index)    this.load(options2, (res) => {      this._lastWaterfallIndex = index      onload(options2)    }, (err) => {      index++      if (index >= adpid.length) {        onfail(err)      } else {        this.loadWaterfall(options, onload, onfail, index)      }    })  }  // 底价逻辑,失败后下一个,无重试机制  showWaterfall (options, onload, onfail, onclose, onshow, index = 0) {    const {      adpid,      urlCallback    } = options    if (!Array.isArray(adpid)) {      return    }    if (this._lastWaterfallIndex > -1) {      index = this._lastWaterfallIndex    }    const options2 = {      adpid: adpid[index],      urlCallback,      retry: false    }    console.log('ad.showWaterfall::index=' + index)    this.show(options2, () => {      onload()    }, (err) => {      index++      if (index >= adpid.length) {        onfail(err)      } else {        this.showWaterfall(options, onload, onfail, onclose, onshow, index)      }    }, (res) => {      onclose(res)    }, () => {      onshow()    })  }  // 预载底价瀑布流  preloadWaterfall (options, index = 0, step = 1) {    if (step === 1) {      this.loadWaterfall(options, (res) => {        console.log('preloadWaterfall.success::', res)      }, (err) => {        console.log('loadWaterfall.fail', err)      })      return    }    const {      adpid,      urlCallback    } = options    for (let i = 0; i < step; i++) {      if (index < adpid.length) {        const options2 = {          adpid: adpid[index],          urlCallback        }        this.loadWaterfall(options2, (res) => {          console.log('preloadWaterfall.success::', res)        }, (err) => {          console.log('loadWaterfall.fail', err)          this.preloadWaterfall(options, index, step)        })        index++      } else {        break      }    }  }  isBusy (adpid) {    return (this._ads[adpid] && this._ads[adpid].isLoading)  }  get (options) {    const {      adpid    } = options    if (!this._ads[adpid]) {      this._ads[adpid] = this._createInstance(options)    }    return this._ads[adpid]  }  getProvider (adpid) {    if (this._ads[adpid]) {      return this._ads[adpid].getProvider()    }    return null  }  remove (adpid) {    if (this._ads[adpid]) {      this._ads[adpid].destroy()      delete this._ads[adpid]    }  }  _createInstance (options) {    const adType = options.adType || this._adType    delete options.adType    let ad = null    if (adType === ADType.RewardedVideo) {      ad = new RewardedVideo(options)    } else if (adType === ADType.FullScreenVideo) {      ad = new FullScreenVideo(options)    } else if (adType === ADType.Interstitial) {      ad = new Interstitial(options, true)    }    return ad  }}export default {  props: {    options: {      type: [Object, Array],      default () {        return {}      }    },    disabled: {      type: [Boolean, String],      default: false    },    adpid: {      type: [Number, String, Array],      default: ''    },    preload: {      type: [Boolean, String],      default: true    },    loadnext: {      type: [Boolean, String],      default: false    },    urlCallback: {      type: Object,      default () {        return {}      }    }  },  data () {    return {      loading: false,      errorMessage: null    }  },  created() {    this.$watch('adpid', (newValue, oldValue) => {      this._removeInstance(oldValue)      if (this.preload) {        this._loadAd()      }    })    // 服务器回调透传参数,仅在创建广告实例时可传递参数,如果发生变化需要重新创建广告实例    this.$watch('urlCallback', () => {      this._removeInstance()    })        this._adHelper = new AdHelper(this.adType)        setTimeout(() => {      if (this.preload) {        this._loadAd()      }    }, 100)  },  methods: {    load () {      if (this.isLoading) {        return      }      this._startLoading()      const invoke = this._isWaterfall() ? 'loadWaterfall' : 'load'      this._adHelper[invoke](this._getAdOptions(), () => {        this._onLoad()      }, (err) => {        this._onLoadFail(err)      })    },    show () {      if (this.isLoading) {        return      }      this._startLoading()      const invoke = this._isWaterfall() ? 'showWaterfall' : 'show'      this._adHelper[invoke](this._getAdOptions(), () => {        this._onLoad()      }, (err) => {        this._onLoadFail(err)      }, (res) => {        this._dispatchEvent(EventType.Close, res)        if (this.loadnext) {          this.load()        }      }, () => {        // show        this.loading = false      })    },    getProvider () {      if (Array.isArray(this.adpid)) {        return null      }      return this._adHelper.getProvider(this.adpid)    },    _loadAd () {      if (this._canCreateAd()) {        this.load()      }    },    _onclick () {      if (!this.disabled) {        this.show()      }    },    _getAdOptions () {      return {        adpid: this.adpid,        urlCallback: this.urlCallback      }    },    _isWaterfall () {      return (Array.isArray(this.adpid) && this.adpid.length > 0)    },    _canCreateAd () {      let result = false      if (Array.isArray(this.adpid) && this.adpid.length > 0) {        result = true      } else if (typeof this.adpid === 'string' && this.adpid.length > 0) {        result = true      } else if (typeof this.adpid === 'number') {        result = true      }      return result    },    _removeInstance (adpid) {      const id = adpid || this.adpid      if (Array.isArray(id)) {        id.forEach((item) => {          this._adHelper.remove(item)        })      } else if (id) {        this._adHelper.remove(id)      }    },    _startLoading () {      this.loading = true      this.errorMessage = null    },    _onLoad () {      this.loading = false      this._dispatchEvent(EventType.Load, {})    },    _onLoadFail (err) {      this.loading = false      this.errorMessage = JSON.stringify(err)      this._dispatchEvent(EventType.Error, err)    },    _dispatchEvent (type, data) {      this.$emit(type, {        detail: data      })    }  }}
 |