广告屏react-native项目
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.
 
 
 
 
 

737 line
20 KiB

  1. import React, { Component } from 'react';
  2. import {
  3. Platform,
  4. StyleSheet,
  5. Text,
  6. View,
  7. Image,
  8. ImageBackground,
  9. PixelRatio,
  10. NativeModules
  11. } from 'react-native';
  12. //引用插件
  13. import Package from './package.json'
  14. import HttpUtils from './HttpUtils.js';
  15. import CodePush from "react-native-code-push";
  16. import DeviceInfo from "react-native-device-info";
  17. import * as Animatable from 'react-native-animatable';
  18. var testMac = 'FF:FF:FF:FF:FF:FF'
  19. var contentItemDefault = {
  20. type:0,
  21. subType:0,
  22. qrcode:[],
  23. target:{
  24. coverImg:'',
  25. title:'',
  26. subTitle:'',
  27. priceStr:'',
  28. salePriceStr:'',
  29. remark:'',
  30. }
  31. }
  32. var baseInfoDefault = {
  33. imgUrlH:'',
  34. imgQrcodeWeapp:'',
  35. imgQrcodeWemp:''
  36. }
  37. var curAdIndex = 0;
  38. var errorMsg = {
  39. ERR_MAC_GET:'设备编号获取错误',
  40. ERR_DATA_GET:'广告数据获取错误'
  41. }
  42. export default class MyPage extends Component {
  43. constructor(props) {
  44. super(props);
  45. this.state = {
  46. baseInfo: baseInfoDefault,
  47. adDataList:[],
  48. contentItem0:null,
  49. contentItem1:null,
  50. contentItem2:null,
  51. contentDisplayStatus:false,
  52. syncMessage: "初始化..." ,
  53. errorMessage: '加载中...',
  54. progress: {
  55. receivedBytes:0,
  56. totalBytes:0
  57. },
  58. macAddress: '',
  59. versionInfo:'Unknown'
  60. };
  61. }
  62. // 监听更新状态
  63. codePushStatusDidChange(syncStatus) {
  64. switch(syncStatus) {
  65. case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
  66. this.setState({ syncMessage: "Checking for update." });
  67. break;
  68. case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
  69. this.setState({ syncMessage: "Downloading package." });
  70. break;
  71. case CodePush.SyncStatus.AWAITING_USER_ACTION:
  72. this.setState({ syncMessage: "Awaiting user action." });
  73. break;
  74. case CodePush.SyncStatus.INSTALLING_UPDATE:
  75. this.setState({ syncMessage: "Installing update." });
  76. break;
  77. case CodePush.SyncStatus.UP_TO_DATE:
  78. this.setState({ syncMessage: "App up to date.", progress: false });
  79. break;
  80. case CodePush.SyncStatus.UPDATE_IGNORED:
  81. this.setState({ syncMessage: "Update cancelled by user.", progress: false });
  82. break;
  83. case CodePush.SyncStatus.UPDATE_INSTALLED:
  84. this.setState({ syncMessage: "Update installed and will be applied on restart.", progress: false });
  85. break;
  86. case CodePush.SyncStatus.UNKNOWN_ERROR:
  87. this.setState({ syncMessage: "An unknown error occurred.", progress: false });
  88. break;
  89. }
  90. }
  91. codePushDownloadDidProgress(progress) {
  92. this.setState({ progress });
  93. }
  94. updateContent() {
  95. if (this.state.adDataList.length <=0)
  96. return false;
  97. if (curAdIndex >= this.state.adDataList.length) {
  98. curAdIndex = 0
  99. }
  100. this.setState({contentItem0:this.state.adDataList[curAdIndex]});
  101. if (curAdIndex + 1 < this.state.adDataList.length)
  102. this.setState({contentItem1:this.state.adDataList[curAdIndex+1]});
  103. else
  104. this.setState({contentItem1:null});
  105. if (curAdIndex + 2 < this.state.adDataList.length)
  106. this.setState({contentItem2:this.state.adDataList[curAdIndex+2]});
  107. else
  108. this.setState({contentItem2:null});
  109. curAdIndex+=3
  110. return true;
  111. }
  112. hbRequest() {
  113. HttpUtils.post(NativeModules.BuildConfig.apiHost + 'api/wxDeviceScreenAd/heartbeat?deviceId='
  114. +encodeURIComponent(this.state.macAddress),
  115. {version:this.state.versionInfo})
  116. .then(result => {
  117. })
  118. .catch(error => {
  119. })
  120. }
  121. getAdDataList() {
  122. HttpUtils.get(NativeModules.BuildConfig.apiHost + 'api/wxDeviceScreenAd/list?deviceId='+encodeURIComponent(this.state.macAddress)+'&pageNum=1&pageSize=1000')
  123. .then((result) => {
  124. if (result.code != 200) {
  125. this.setState({contentDisplayStatus: false})
  126. this.setState({errorMessage : result.message+'\n'+this.state.macAddress});
  127. } else if (result.data.list) {
  128. this.setState({adDataList : result.data.list});
  129. if (this.updateContent()) {
  130. this.setState({contentDisplayStatus: true})
  131. }
  132. } else {
  133. this.setState({contentDisplayStatus: false})
  134. this.setState({errorMessage : errorMsg.ERR_DATA_GET});
  135. }
  136. })
  137. .catch(error => {
  138. this.setState({contentDisplayStatus: false})
  139. this.setState({errorMessage : error.message});
  140. })
  141. }
  142. getBaseInfo() {
  143. HttpUtils.get(NativeModules.BuildConfig.apiHost + 'api/wxDeviceScreenAd/info?deviceId='+encodeURIComponent(this.state.macAddress))
  144. .then(result => {
  145. if (result.code != 200) {
  146. this.setState({contentDisplayStatus: false})
  147. this.setState({errorMessage : result.message+'\n'+this.state.macAddress});
  148. } else if (result.data) {
  149. this.setState({baseInfo:result.data});
  150. } else {
  151. this.setState({contentDisplayStatus: false})
  152. this.setState({errorMessage : errorMsg.ERR_DATA_GET});
  153. }
  154. })
  155. .catch(error => {
  156. this.setState({contentDisplayStatus: false})
  157. this.setState({errorMessage : error.message});
  158. })
  159. }
  160. componentDidMount() {
  161. CodePush.allowRestart();
  162. CodePush.sync(
  163. { installMode: CodePush.InstallMode.IMMEDIATE},
  164. this.codePushStatusDidChange.bind(this),
  165. this.codePushDownloadDidProgress.bind(this)
  166. );
  167. CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING)
  168. .then((metadata: LocalPackage) => {
  169. this.setState({ versionInfo: metadata ? metadata.appVersion + "-" + metadata.label : "Unknown"});
  170. }, (error: any) => {
  171. this.setState({ versionInfo: "Unknown"});
  172. });
  173. DeviceInfo.getMACAddress().then((mac)=>{
  174. if (mac=='') {
  175. if (NativeModules.BuildConfig.buildType == 'debug') {
  176. this.setState({macAddress : this.testMac})
  177. this.startAd()
  178. } else {
  179. this.setState({ contentDisplayStatus: false})
  180. this.setState({ errorMessage : errorMsg.ERR_MAC_GET});
  181. }
  182. } else {
  183. this.setState({macAddress : mac})
  184. this.startAd()
  185. }
  186. this.setState({ contentDisplayStatus: true})
  187. }).catch(e => {
  188. this.setState({ contentDisplayStatus: false})
  189. this.setState({ errorMessage : errorMsg.ERR_MAC_GET});
  190. })
  191. }
  192. startAd() {
  193. this.getBaseInfo()
  194. this.getAdDataList()
  195. setInterval(
  196. ()=>{
  197. if (this.state.contentDisplayStatus) {
  198. this.setState({ contentDisplayStatus: false})
  199. if (this.updateContent()) {
  200. this.setState({ contentDisplayStatus: true})
  201. }
  202. } else {
  203. this.getBaseInfo()
  204. this.getAdDataList()
  205. }
  206. },
  207. 1000*10, //10秒更新一下页面
  208. );
  209. setInterval(
  210. ()=>{
  211. this.getAdDataList()
  212. },
  213. 1000*60*60, //1小时一次
  214. );
  215. setInterval(
  216. ()=>{
  217. this.hbRequest()
  218. },
  219. 1000*60*5, //5分钟一次
  220. );
  221. }
  222. getContentViewItemUplayer(contentItem) {
  223. if (contentItem.type == 0) {
  224. if (contentItem.subType == 2)
  225. return (<Image source={require('./image/groupbuy.png')} resizeMode='center' style={styles.contentItemUpLayer} /> )
  226. if (contentItem.subType == 6)
  227. return (<Image source={require('./image/discount.png')} resizeMode='center' style={styles.contentItemUpLayer} /> )
  228. if (contentItem.subType == 7)
  229. return (<Image source={require('./image/groupbuy.png')} resizeMode='center' style={styles.contentItemUpLayer} /> )
  230. }
  231. }
  232. getContentViewItem(contentItem, annomation) {
  233. if (!contentItem)
  234. return (
  235. <View style={styles.contentItem}>
  236. </View>
  237. )
  238. actionText = '扫码领取';
  239. if (contentItem.target.type == 8)
  240. actionText = '扫码砍价';
  241. else if (contentItem.target.type == 9)
  242. actionText = '扫码拼团';
  243. merchantName = "";
  244. if (contentItem.target.merchantVoList.length > 1)
  245. merchantName = '多商户通用';
  246. else
  247. merchantName = contentItem.target.merchantVoList[0].merchantName;
  248. return (
  249. <Animatable.View animation={annomation} style={styles.contentItem}>
  250. <ImageBackground source={require('./image/item-background.png')} resizeMode='center' style={styles.contentItemDownLayer} >
  251. <View style={styles.contentItemTop}>
  252. <Image source={{uri: contentItem.target.coverImg}} resizeMode='cover' style={styles.contentItemTopCoverImg} />
  253. <View style={styles.contentItemTopDetail}>
  254. <Text style={styles.contentItemTopDetailTitle} numberOfLines={1} ellipsizeMode="tail">{contentItem.target.title}</Text>
  255. <Text style={styles.contentItemTopDetailRemark} numberOfLines={1} ellipsizeMode="tail">{contentItem.target.remark}</Text>
  256. <View style={styles.contentItemTopDetailPrice}>
  257. <View style={styles.contentItemTopDetailCurPrice}>
  258. <Text style={styles.contentItemTopDetailCurPriceStr}>{contentItem.target.priceStr}</Text>
  259. <Text style={styles.contentItemTopDetailCurPriceStrUnit}>元</Text>
  260. </View>
  261. <View style={styles.contentItemTopDetailSalePrice}>
  262. <Text style={styles.contentItemTopDetailSalePriceStr} >{contentItem.target.salePriceStr}元</Text>
  263. </View>
  264. </View>
  265. </View>
  266. <Image source={{uri:'data:image/png;base64,'+contentItem.qrcode}} resizeMode='contain' style={styles.contentItemTopQrcode} />
  267. </View>
  268. <View style={styles.contentItemBottom}>
  269. <Text style={styles.contentItemBottomMerchantName}>{merchantName}</Text>
  270. <View style={styles.contentItemBottomPlacehold}></View>
  271. <Text style={styles.contentItemBottomAction}>{actionText}</Text>
  272. </View>
  273. </ImageBackground>
  274. {this.getContentViewItemUplayer(contentItem)}
  275. </Animatable.View>
  276. )
  277. }
  278. getContentView() {
  279. if (this.state.contentDisplayStatus) {
  280. return (<View style={styles.content}>
  281. {this.getContentViewItem(this.state.contentItem0,"slideInDown")}
  282. {this.getContentViewItem(this.state.contentItem1,"slideInLeft")}
  283. {this.getContentViewItem(this.state.contentItem2,"slideInRight")}
  284. </View>)
  285. }else{
  286. return (
  287. <View style={styles.content}>
  288. <Text style={styles.updatePage}>{this.state.errorMessage}</Text>
  289. </View>)
  290. }
  291. }
  292. render() {
  293. if (this.state.progress) {
  294. if (this.state.progress.totalBytes > 0)
  295. return (
  296. <Text style={styles.updatePage}>{this.state.syncMessage}{'\n'}
  297. {this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received{'\n'}
  298. </Text>
  299. );
  300. return (
  301. <Text style={styles.updatePage}>{this.state.syncMessage}
  302. </Text>
  303. );
  304. }
  305. return (
  306. <ImageBackground style={styles.background} resizeMode='center' source={require('./image/background.png')}>
  307. <View style={styles.title}>
  308. <View style={styles.titleImagePlace}>
  309. <Image source={require('./image/title.png')} resizeMode='center' style={styles.titleImage} />
  310. </View>
  311. <ImageBackground source={require('./image/title-qrcode.png') } resizeMode='center' style={styles.titleQrcodeBonder} >
  312. <View style={styles.titleQrcodePlacehold}></View>
  313. <Image source={{uri: this.state.baseInfo.imgQrcodeWeapp}} resizeMode='center' style={styles.titleQrcode} />
  314. <View style={styles.titleQrcodePlacehold}></View>
  315. </ImageBackground>
  316. </View>
  317. {this.getContentView()}
  318. <View style={styles.bottom}>
  319. <View style={styles.bottomLogoBackground}>
  320. <Image source={{ uri: this.state.baseInfo.imgUrlH, cache: 'force-cache'}} resizeMode='center' style={styles.bottomLogo} />
  321. </View>
  322. <View style={styles.bottomQrcode1Background}>
  323. <Image source={{ uri: this.state.baseInfo.imgQrcodeWeapp, cache: 'force-cache'}} resizeMode='center' style={styles.bottomQrcode1} />
  324. <Text style={styles.bottomQrcode1Str}>小程序</Text>
  325. </View>
  326. <View style={styles.bottomQrcode2Background}>
  327. <Image source={{ uri: this.state.baseInfo.imgQrcodeWemp, cache: 'force-cache'}} resizeMode='center' style={styles.bottomQrcode2} />
  328. <Text style={styles.bottomQrcode1Str}>公众号</Text>
  329. </View>
  330. <Text style={styles.bottomPlacehold}>{this.state.versionInfo}</Text>
  331. </View>
  332. </ImageBackground>
  333. );
  334. }
  335. }
  336. const styles = StyleSheet.create({
  337. updatePage:{
  338. flex: 2,
  339. width:'100%',
  340. height:'100%',
  341. backgroundColor:'transparent',
  342. textAlign :'center',
  343. textAlignVertical:'center',
  344. fontSize: 63/PixelRatio.get(),
  345. color: 'darkblue'
  346. },
  347. //layer background
  348. background:{
  349. flex: 1,
  350. width:'100%',
  351. height:'100%'
  352. },
  353. //layer top
  354. title:{
  355. flex: 6,
  356. flexDirection: 'row',
  357. alignItems: 'center',
  358. paddingLeft:42/PixelRatio.get(),
  359. paddingRight:42/PixelRatio.get(),
  360. backgroundColor:'transparent'
  361. },
  362. content:{
  363. flex: 18,
  364. flexDirection: 'column',
  365. alignItems: 'center',
  366. backgroundColor:'transparent'
  367. },
  368. bottom:{
  369. flex: 2,
  370. flexDirection: 'row',
  371. alignItems: 'center',
  372. paddingLeft:42/PixelRatio.get(),
  373. paddingRight:42/PixelRatio.get(),
  374. backgroundColor:'transparent'
  375. },
  376. //layer title
  377. titleImagePlace: {
  378. flex: 2,
  379. paddingTop: '20%',
  380. paddingLeft: '15%',
  381. alignItems: 'center',
  382. backgroundColor:'transparent'
  383. },
  384. titleImage: {
  385. width:'100%',
  386. height:'100%',
  387. flex: 1,
  388. backgroundColor:'transparent'
  389. },
  390. titleQrcodeBonder: {
  391. width:'100%',
  392. height:'100%',
  393. alignItems: 'center',
  394. flexDirection: 'column',
  395. flex: 1,
  396. backgroundColor:'transparent'
  397. },
  398. titleQrcodePlacehold: {
  399. flex: 5,
  400. backgroundColor:'transparent'
  401. },
  402. titleQrcode: {
  403. flex: 6,
  404. width:'100%',
  405. height:'100%',
  406. backgroundColor:'transparent'
  407. },
  408. //layer bottom
  409. bottomLogoBackground: {
  410. flex: 3,
  411. borderRadius:16/PixelRatio.get(),
  412. marginTop: 26/PixelRatio.get(),
  413. marginBottom: 26/PixelRatio.get(),
  414. backgroundColor:'white'
  415. },
  416. bottomLogo: {
  417. width:'100%',
  418. height:'100%',
  419. borderRadius:27/PixelRatio.get(),
  420. backgroundColor:'transparent'
  421. },
  422. bottomQrcode1Background : {
  423. flex: 1,
  424. width:'100%',
  425. height:'100%',
  426. marginLeft: 21/PixelRatio.get(),
  427. paddingTop: 27/PixelRatio.get(),
  428. paddingBottom: 11/PixelRatio.get(),
  429. flexDirection: 'column',
  430. backgroundColor:'transparent'
  431. },
  432. bottomQrcode2Background : {
  433. flex: 1,
  434. width:'100%',
  435. height:'100%',
  436. marginLeft: 21/PixelRatio.get(),
  437. paddingTop: 26/PixelRatio.get(),
  438. paddingBottom: 11/PixelRatio.get(),
  439. flexDirection: 'column',
  440. backgroundColor:'transparent'
  441. },
  442. bottomQrcode1: {
  443. flex: 2,
  444. width:'100%',
  445. height:'100%',
  446. backgroundColor:'transparent'
  447. },
  448. bottomQrcode2: {
  449. flex: 2,
  450. width:'100%',
  451. height:'100%',
  452. backgroundColor:'transparent'
  453. },
  454. bottomQrcode1Str: {
  455. flex: 1,
  456. textAlign :'center',
  457. textAlignVertical:'center',
  458. fontSize: 16/PixelRatio.get(),
  459. color : 'black',
  460. backgroundColor:'transparent'
  461. },
  462. bottomQrcode2Str: {
  463. flex: 1,
  464. textAlign :'center',
  465. textAlignVertical:'center',
  466. fontSize: 16/PixelRatio.get(),
  467. color : 'black',
  468. backgroundColor:'transparent'
  469. },
  470. bottomPlacehold: {
  471. flex: 8,
  472. width:'100%',
  473. height:'100%',
  474. backgroundColor:'transparent',
  475. textAlign :'right',
  476. textAlignVertical:'bottom',
  477. fontSize: 27/PixelRatio.get(),
  478. color : 'gray'
  479. },
  480. //layer content item
  481. contentItem:{
  482. flex: 1,
  483. width:'100%',
  484. height:'100%',
  485. flexDirection: 'column',
  486. backgroundColor:'transparent'
  487. },
  488. contentItemDownLayer:{
  489. position:'absolute',
  490. width:'100%',
  491. height:'100%',
  492. flexDirection: 'column',
  493. alignItems: 'center',
  494. backgroundColor:'transparent'
  495. },
  496. contentItemUpLayer:{
  497. width:210/PixelRatio.get(),
  498. height:153/PixelRatio.get(),
  499. position:'absolute',
  500. backgroundColor:'transparent'
  501. },
  502. contentItemTop:{
  503. flex: 3,
  504. width:'100%',
  505. height:'100%',
  506. paddingLeft: 66/PixelRatio.get(),
  507. paddingRight: 53/PixelRatio.get(),
  508. paddingTop: 40/PixelRatio.get(),
  509. flexDirection: 'row',
  510. alignItems: 'center',
  511. backgroundColor:'transparent'
  512. },
  513. contentItemBottom:{
  514. flex: 1,
  515. width:'100%',
  516. height:'100%',
  517. paddingLeft: 66/PixelRatio.get(),
  518. paddingRight: 53/PixelRatio.get(),
  519. paddingBottom: 40/PixelRatio.get(),
  520. flexDirection: 'row',
  521. alignItems: 'center',
  522. backgroundColor:'transparent'
  523. },
  524. //layer content item top
  525. contentItemTopCoverImg:{
  526. flex: 5,
  527. width:'100%',
  528. height:'100%',
  529. borderRadius:27/PixelRatio.get(),
  530. backgroundColor:'transparent'
  531. },
  532. contentItemTopDetail:{
  533. flex: 6,
  534. width:'100%',
  535. height:'100%',
  536. paddingLeft: 27/PixelRatio.get(),
  537. paddingRight: 79/PixelRatio.get(),
  538. alignItems: 'center',
  539. backgroundColor:'transparent'
  540. },
  541. contentItemTopQrcode:{
  542. flex: 5,
  543. width:'100%',
  544. height:'100%',
  545. backgroundColor:'transparent'
  546. },
  547. //layer content item bottom
  548. contentItemBottomMerchantName:{
  549. flex: 5,
  550. width:'100%',
  551. height:'100%',
  552. alignItems: 'center',
  553. backgroundColor:'transparent',
  554. textAlign :'center',
  555. textAlignVertical:'center',
  556. fontSize: 27/PixelRatio.get(),
  557. fontWeight : 'bold'
  558. },
  559. contentItemBottomPlacehold:{
  560. flex: 6,
  561. paddingLeft: 27/PixelRatio.get(),
  562. paddingRight: 79/PixelRatio.get(),
  563. width:'100%',
  564. height:'100%',
  565. backgroundColor:'transparent',
  566. },
  567. contentItemBottomAction:{
  568. flex: 5,
  569. width:'100%',
  570. height:'100%',
  571. backgroundColor:'transparent',
  572. fontWeight : 'bold',
  573. textAlign :'center',
  574. textAlignVertical:'center',
  575. fontSize: 36/PixelRatio.get(),
  576. },
  577. //layer content item top detail
  578. contentItemTopDetailTitle:{
  579. flex: 2,
  580. width:'100%',
  581. height:'100%',
  582. backgroundColor:'transparent',
  583. textAlign :'left',
  584. textAlignVertical:'center',
  585. fontSize: 53/PixelRatio.get(),
  586. color: 'darkgray'
  587. },
  588. contentItemTopDetailRemark:{
  589. flex: 1,
  590. width:'100%',
  591. height:'100%',
  592. backgroundColor:'transparent',
  593. textAlign :'left',
  594. textAlignVertical:'center',
  595. fontSize: 27/PixelRatio.get(),
  596. color : 'gray'
  597. },
  598. contentItemTopDetailPrice:{
  599. flex: 2,
  600. width:'100%',
  601. height:'100%',
  602. backgroundColor:'transparent',
  603. flexDirection: 'row',
  604. },
  605. contentItemTopDetailCurPrice:{
  606. flex: 3,
  607. width:'100%',
  608. height:'100%',
  609. flexDirection: 'row',
  610. backgroundColor:'transparent',
  611. },
  612. contentItemTopDetailCurPriceStr:{
  613. backgroundColor:'transparent',
  614. textAlign :'left',
  615. textAlignVertical:'bottom',
  616. fontSize: 84/PixelRatio.get(),
  617. color : 'red'
  618. },
  619. contentItemTopDetailCurPriceStrUnit:{
  620. backgroundColor:'transparent',
  621. textAlign :'left',
  622. textAlignVertical:'bottom',
  623. fontSize: 27/PixelRatio.get(),
  624. color : 'red'
  625. },
  626. contentItemTopDetailSalePrice:{
  627. flex: 1,
  628. width:'100%',
  629. height:'100%',
  630. backgroundColor:'transparent',
  631. },
  632. contentItemTopDetailSalePriceStr:{
  633. width:'100%',
  634. height:'100%',
  635. backgroundColor:'transparent',
  636. textAlign :'left',
  637. textAlignVertical:'bottom',
  638. fontSize: 27/PixelRatio.get(),
  639. textDecorationLine: 'line-through',
  640. color : 'gray'
  641. },
  642. });