index.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import Taro, { useLoad, useReady } from '@tarojs/taro'
  2. import { PropsWithChildren, useState } from 'react'
  3. import { View, Video, Image } from '@tarojs/components'
  4. import useGetCustomClient from '@/hooks/useGetCustomClient'
  5. import { wrapProps, generateUUID } from '@/plugin/share'
  6. import './index.less'
  7. import http from '@/http/index'
  8. import { adSelfPredict } from '@/http/api/index'
  9. import { adActionLog } from '@/logCenter/index'
  10. import { reportBusinessType } from '@/plugin/share/const'
  11. import { queryURLParams } from '@/plugin/share'
  12. import AES from 'crypto-js/aes.js'
  13. // 在一些场景下 loadedMetaFiredInOnce 被触发了很多次
  14. let loadedMetaFiredInOnce = 0
  15. let pqtId
  16. function YLQCustom(props: PropsWithChildren<CustomPropsType>) {
  17. let {
  18. adpId,
  19. width,
  20. onEmitOpenMiniProgram,
  21. onError,
  22. onLoad,
  23. onClose
  24. } = wrapProps(props)
  25. const [show, setShow] = useState(true)
  26. const [adData, setAdData] = useState<any>({})
  27. useReady(() => {
  28. console.log('YLQCustom init', Taro.$global)
  29. init()
  30. pqtId = generateUUID()
  31. getAdConfig()
  32. })
  33. function init() {
  34. if (
  35. typeof adpId !== 'string' ||
  36. typeof onEmitOpenMiniProgram !== 'function'
  37. ) {
  38. catchError('参数错误', 1031, '用户必传参数没传')
  39. return
  40. }
  41. }
  42. function getAdConfig() {
  43. http.post(`${adSelfPredict}?adpId=${adpId}`, {
  44. baseInfo: {},
  45. positionId: 1,
  46. phoneModel : '',
  47. careModelStatus : 1,
  48. videoId: 0
  49. }, {
  50. header: { 'content-type': 'application/json;' }
  51. }).then((res: RequestType) => {
  52. const { code, data, msg } = res
  53. if(code === 10001) {
  54. catchError('广告资源加载失败', 1022, msg)
  55. return
  56. }
  57. if(code === 10002) {
  58. catchError('adpId 无效', 1021, msg)
  59. return
  60. }
  61. if(code === 10003) {
  62. catchError('初始化失败', 1011, msg)
  63. return
  64. }
  65. const { ownPlatform } = data || {}
  66. const { adType, platformCreativeInfo } = ownPlatform || {}
  67. const { landingPageAddress } = platformCreativeInfo || {}
  68. if (!landingPageAddress) {
  69. catchError('数据异常', 1013, '无landingPageAddress')
  70. return
  71. }
  72. setAdData({
  73. adType,
  74. ...platformCreativeInfo
  75. })
  76. }).catch((e) => {
  77. catchError('初始化失败', 1011, e.message)
  78. })
  79. }
  80. function videoPlay() {
  81. adActionReport(reportBusinessType.adPlay, 'adPlay')
  82. }
  83. function videoClick() {
  84. adActionReport(reportBusinessType.adClick, 'adClick')
  85. videoOpenMiniProgram()
  86. closeCustom()
  87. }
  88. function videoOpenMiniProgram() {
  89. const { landingPageAddress } = adData
  90. const query = queryURLParams(createAdActionReportData())
  91. adActionReport(reportBusinessType.adPlay, 'adOpen')
  92. const orgPath = `path=${encodeURIComponent(landingPageAddress)}&${query}`
  93. const path = AES.encrypt(orgPath, 'wx5ef216d1caf4a0eaylq').toString()
  94. onEmitOpenMiniProgram(
  95. 'wx5ef216d1caf4a0ea',
  96. `/pages/ad-launch-page/index?q=${path}`
  97. )
  98. console.log(`/pages/ad-launch-page/index?q=${path}`)
  99. }
  100. function videoLoad() {
  101. adActionReport(reportBusinessType.adLoad, 'adLoad')
  102. onLoad()
  103. }
  104. function videoError() {
  105. catchError('广告加载失败', 1012, '素材播放视频')
  106. }
  107. function videoView() {
  108. adActionReport(reportBusinessType.adView, 'adView')
  109. }
  110. function videoTimeUpdate() {}
  111. function closeCustom() {
  112. adActionReport(reportBusinessType.adClose, 'adClose')
  113. onClose()
  114. setShow(false)
  115. }
  116. function adActionReport(eventId, businessType, extParams = {}) {
  117. const data = createAdActionReportData()
  118. adActionLog([{
  119. businessType,
  120. eventId,
  121. ...data,
  122. ...extParams
  123. }])
  124. }
  125. function createAdActionReportData() {
  126. const {
  127. trafficCode, // 流量主code
  128. // 广告主
  129. advertiserCode,
  130. advertiserId,
  131. // 广告计划
  132. campaignCode,
  133. campaignId,
  134. // 广告
  135. adCode,
  136. adId,
  137. // 创意
  138. creativeCode,
  139. id,
  140. // 广告位
  141. positionId,
  142. // 竞价
  143. bidType = '',
  144. unitPrice = '', // 单价
  145. bidCreativeParam = {}, // {}
  146. adType: ownAdSystemType
  147. } = adData
  148. return {
  149. adpCode: trafficCode,
  150. advertiserCode,
  151. advertiserId,
  152. campaignCode,
  153. campaignId,
  154. adCode,
  155. adId,
  156. creativeCode,
  157. id,
  158. positionId,
  159. bidType,
  160. unitPrice, // 单价
  161. bidCreativeParam: JSON.stringify(bidCreativeParam || {}), // {}
  162. adpId,
  163. pqtId,
  164. ownAdSystemType
  165. }
  166. }
  167. function catchError(message, code, errMessage) {
  168. onError(code)
  169. setShow(false)
  170. adActionReport(reportBusinessType.adError, 'adError', {
  171. errorCode: code,
  172. message,
  173. errMessage
  174. })
  175. }
  176. return (
  177. <>
  178. {show && <View className='pq-custom' style={{width: `${width}px`}}>
  179. <View className='custom-container'>
  180. {/* 广告icon */}
  181. <View className='icon'>
  182. 广告
  183. </View>
  184. {/* 关闭icon */}
  185. <View className='close-icon' onClick={closeCustom}>
  186. </View>
  187. <Custom
  188. width={width}
  189. adData={adData}
  190. onPlay={videoPlay}
  191. onClick={videoClick}
  192. onLoad={videoLoad}
  193. onView={videoView}
  194. onError={videoError}
  195. onTimeUpdate={videoTimeUpdate}
  196. />
  197. </View>
  198. </View>}
  199. </>
  200. )
  201. }
  202. function Custom({
  203. width, adData, onPlay, onClick, onLoad,
  204. onView, onError, onTimeUpdate
  205. }) {
  206. const [style, setStyle] = useState({ width: '0px', height: '0px' })
  207. useReady(() => {
  208. loadedMetaFiredInOnce = 0
  209. onView()
  210. })
  211. useGetCustomClient((customClient) => {
  212. let clientWidth = customClient.width
  213. let clientHeight = customClient.height
  214. if (typeof width === 'number') {
  215. clientWidth = width
  216. clientHeight = clientWidth * 667 / 375
  217. }
  218. setStyle({
  219. width: `${clientWidth}px`,
  220. height: `${clientHeight}px`
  221. })
  222. })
  223. function onLoadedMetaData() {
  224. if (loadedMetaFiredInOnce++ < 1) {
  225. // 上报load
  226. onLoad()
  227. }
  228. }
  229. return (
  230. <View className='custom'>
  231. <Video
  232. style={style}
  233. controls={false}
  234. autoplay
  235. loop
  236. src={adData.materialAddress}
  237. poster={adData.materialCoverPic}
  238. onPlay={onPlay}
  239. onTimeUpdate={onTimeUpdate}
  240. onError={onError}
  241. onClick={onClick}
  242. onLoadedMetaData={onLoadedMetaData}
  243. />
  244. <View className='custom-bottom' style={{width: `${width}px`}}>
  245. <Image src={adData.creativeLogoAddress} className='logo' />
  246. <View className='title'>{adData.creativeTitle}</View>
  247. <View className='button'>{adData.clickButtonText}</View>
  248. </View>
  249. </View>
  250. )
  251. }
  252. export default YLQCustom