广告屏react-native项目
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

739 lines
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:'未知'
  60. };
  61. }
  62. // 监听更新状态
  63. codePushStatusDidChange(syncStatus) {
  64. switch(syncStatus) {
  65. case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
  66. this.setState({ syncMessage: "检查更新" });
  67. break;
  68. case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
  69. this.setState({ syncMessage: "下载更新" });
  70. break;
  71. case CodePush.SyncStatus.AWAITING_USER_ACTION:
  72. this.setState({ syncMessage: "等待用户操作" });
  73. break;
  74. case CodePush.SyncStatus.INSTALLING_UPDATE:
  75. this.setState({ syncMessage: "安装更新" });
  76. break;
  77. case CodePush.SyncStatus.UP_TO_DATE:
  78. this.setState({ syncMessage: "已更新到最新程序", progress: false });
  79. break;
  80. case CodePush.SyncStatus.UPDATE_IGNORED:
  81. this.setState({ syncMessage: "更新被取消", progress: false });
  82. break;
  83. case CodePush.SyncStatus.UPDATE_INSTALLED:
  84. this.setState({ syncMessage: "更新已安装,重启应用后生效", progress: false });
  85. break;
  86. case CodePush.SyncStatus.UNKNOWN_ERROR:
  87. this.setState({ syncMessage: "未知错误", 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} easing="ease-out" duration={1500} delay={500} 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={2} 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.contentItemTopDetailCurPriceStrUnit}>¥</Text>
  259. <Text style={styles.contentItemTopDetailCurPriceStr}>{contentItem.target.salePriceStr}</Text>
  260. </View>
  261. <View style={styles.contentItemTopDetailSalePrice}>
  262. <Text style={styles.contentItemTopDetailSalePriceStr} >¥{contentItem.target.priceStr}</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='contain' 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:'transparent',//'rgba(255,255,255,0.5)',
  415. },
  416. bottomLogo: {
  417. width:'100%',
  418. height:'100%',
  419. backgroundColor:'transparent'
  420. },
  421. bottomQrcode1Background : {
  422. flex: 1,
  423. width:'100%',
  424. height:'100%',
  425. marginLeft: 21/PixelRatio.get(),
  426. paddingTop: 27/PixelRatio.get(),
  427. paddingBottom: 11/PixelRatio.get(),
  428. flexDirection: 'column',
  429. backgroundColor:'transparent'
  430. },
  431. bottomQrcode2Background : {
  432. flex: 1,
  433. width:'100%',
  434. height:'100%',
  435. marginLeft: 21/PixelRatio.get(),
  436. paddingTop: 26/PixelRatio.get(),
  437. paddingBottom: 11/PixelRatio.get(),
  438. flexDirection: 'column',
  439. backgroundColor:'transparent'
  440. },
  441. bottomQrcode1: {
  442. flex: 2,
  443. width:'100%',
  444. height:'100%',
  445. backgroundColor:'transparent'
  446. },
  447. bottomQrcode2: {
  448. flex: 2,
  449. width:'100%',
  450. height:'100%',
  451. backgroundColor:'transparent'
  452. },
  453. bottomQrcode1Str: {
  454. flex: 1,
  455. textAlign :'center',
  456. textAlignVertical:'center',
  457. fontSize: 16/PixelRatio.get(),
  458. color : 'white',
  459. backgroundColor:'transparent'
  460. },
  461. bottomQrcode2Str: {
  462. flex: 1,
  463. textAlign :'center',
  464. textAlignVertical:'center',
  465. fontSize: 16/PixelRatio.get(),
  466. color : 'white',
  467. backgroundColor:'transparent'
  468. },
  469. bottomPlacehold: {
  470. flex: 8,
  471. width:'100%',
  472. height:'100%',
  473. backgroundColor:'transparent',
  474. textAlign :'right',
  475. textAlignVertical:'bottom',
  476. fontSize: 27/PixelRatio.get(),
  477. color : 'gray'
  478. },
  479. //layer content item
  480. contentItem:{
  481. flex: 1,
  482. width:'100%',
  483. height:'100%',
  484. flexDirection: 'column',
  485. backgroundColor:'transparent'
  486. },
  487. contentItemDownLayer:{
  488. position:'absolute',
  489. width:'100%',
  490. height:'100%',
  491. flexDirection: 'column',
  492. alignItems: 'center',
  493. backgroundColor:'transparent'
  494. },
  495. contentItemUpLayer:{
  496. width:210/PixelRatio.get(),
  497. height:153/PixelRatio.get(),
  498. position:'absolute',
  499. backgroundColor:'transparent'
  500. },
  501. contentItemTop:{
  502. flex: 3,
  503. width:'100%',
  504. height:'100%',
  505. paddingLeft: 66/PixelRatio.get(),
  506. paddingRight: 53/PixelRatio.get(),
  507. paddingTop: 40/PixelRatio.get(),
  508. flexDirection: 'row',
  509. alignItems: 'center',
  510. backgroundColor:'transparent'
  511. },
  512. contentItemBottom:{
  513. flex: 1,
  514. width:'100%',
  515. height:'100%',
  516. paddingLeft: 66/PixelRatio.get(),
  517. paddingRight: 53/PixelRatio.get(),
  518. paddingBottom: 40/PixelRatio.get(),
  519. flexDirection: 'row',
  520. alignItems: 'center',
  521. backgroundColor:'transparent'
  522. },
  523. //layer content item top
  524. contentItemTopCoverImg:{
  525. flex: 5,
  526. width:'100%',
  527. height:'100%',
  528. borderRadius:27/PixelRatio.get(),
  529. backgroundColor:'transparent'
  530. },
  531. contentItemTopDetail:{
  532. flex: 6,
  533. width:'100%',
  534. height:'100%',
  535. paddingLeft: 27/PixelRatio.get(),
  536. paddingRight: 79/PixelRatio.get(),
  537. alignItems: 'center',
  538. backgroundColor:'transparent'
  539. },
  540. contentItemTopQrcode:{
  541. flex: 5,
  542. width:'100%',
  543. height:'100%',
  544. backgroundColor:'transparent'
  545. },
  546. //layer content item bottom
  547. contentItemBottomMerchantName:{
  548. flex: 5,
  549. width:'100%',
  550. height:'100%',
  551. alignItems: 'center',
  552. backgroundColor:'transparent',
  553. textAlign :'center',
  554. textAlignVertical:'center',
  555. fontSize: 27/PixelRatio.get(),
  556. fontWeight : 'bold'
  557. },
  558. contentItemBottomPlacehold:{
  559. flex: 6,
  560. paddingLeft: 27/PixelRatio.get(),
  561. paddingRight: 79/PixelRatio.get(),
  562. width:'100%',
  563. height:'100%',
  564. backgroundColor:'transparent',
  565. },
  566. contentItemBottomAction:{
  567. flex: 5,
  568. width:'100%',
  569. height:'100%',
  570. backgroundColor:'transparent',
  571. fontWeight : 'bold',
  572. textAlign :'center',
  573. textAlignVertical:'center',
  574. fontSize: 36/PixelRatio.get(),
  575. color: 'darkgray'
  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. },
  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. */
  599. contentItemTopDetailPrice:{
  600. flex: 2,
  601. width:'100%',
  602. height:'100%',
  603. backgroundColor:'transparent',
  604. flexDirection: 'row',
  605. },
  606. contentItemTopDetailCurPrice:{
  607. flex: 3,
  608. width:'100%',
  609. height:'100%',
  610. flexDirection: 'row',
  611. backgroundColor:'transparent',
  612. },
  613. contentItemTopDetailCurPriceStr:{
  614. backgroundColor:'transparent',
  615. fontSize:96/PixelRatio.get(),
  616. fontFamily:"PingFangSC-Bold",
  617. fontWeight: "bold",
  618. textAlign :'left',
  619. textAlignVertical:'bottom',
  620. color : 'red'
  621. },
  622. contentItemTopDetailCurPriceStrUnit:{
  623. backgroundColor:'transparent',
  624. textAlign :'left',
  625. textAlignVertical:'bottom',
  626. paddingBottom: 16/PixelRatio.get(),
  627. fontSize: 48/PixelRatio.get(),
  628. color : 'red'
  629. },
  630. contentItemTopDetailSalePrice:{
  631. flex: 1,
  632. width:'100%',
  633. height:'100%',
  634. backgroundColor:'transparent',
  635. },
  636. contentItemTopDetailSalePriceStr:{
  637. width:'100%',
  638. height:'100%',
  639. backgroundColor:'transparent',
  640. textAlign :'left',
  641. textAlignVertical:'bottom',
  642. fontSize: 27/PixelRatio.get(),
  643. textDecorationLine: 'line-through',
  644. color : 'gray'
  645. },
  646. });