Charge.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. /**
  2. * 充电页面
  3. * @邠心vbe on 2021/04/12
  4. */
  5. import React, { Component } from 'react';
  6. import { View, Text, StyleSheet, ImageBackground, Image, TextInput } from 'react-native';
  7. import apiCharge from '../../api/apiCharge';
  8. import Button from '../../components/Button';
  9. import Dialog from '../../components/Dialog';
  10. import { PageList } from '../Router';
  11. import { BatteryView, ChargeStyle, circleSize, EnterStationDialog, TypeImage } from './Charging';
  12. import Payment, { PaymentDefault, PAYTYPE } from '../wallet/Payment';
  13. import { QRResult } from './QRScan';
  14. import { ErrorDialog } from './InfoDialog';
  15. import utils from '../../utils/utils';
  16. import TextRadius from '../../components/TextRadius';
  17. export default class Charge extends Component {
  18. constructor(props) {
  19. super(props);
  20. this.state = {
  21. available: false,
  22. isPrivate: false,
  23. refreshId: 0,
  24. isStart: false,
  25. isPending: false,
  26. isCharging: false,
  27. isAuthentic: false,
  28. rateList: [],
  29. selectRate: '',
  30. connectorInfo: {},
  31. stationInfo: {},
  32. lastUpdated: '',
  33. errorCode: 'A9',
  34. errorMessage: '',
  35. showErrorDialog: false,
  36. showStationDialog: false,
  37. curerntPerUser: undefined,
  38. //currentPayment: PAYTYPE.CREDIT_WALLET,
  39. //currentPaytype: "Credit Wallet",
  40. currentPayment: PaymentDefault.DEFAULT.payType,
  41. currentPaytype: PaymentDefault.DEFAULT.payName
  42. };
  43. this.changeMethod = false;
  44. this.canAutoRefresh = false;
  45. this.inputStationId = '';
  46. }
  47. componentDidMount() {
  48. this.canAutoRefresh = true;
  49. if (this.props.stationInfo) {
  50. this.setState({
  51. rateList: this.props.stationInfo.rateList ?? [],
  52. stationInfo: this.props.stationInfo
  53. }, () => {
  54. this.refreshAvailable();
  55. this.checkIsCharge();
  56. });
  57. }
  58. }
  59. componentDidUpdate() {
  60. if (this.props.visible && this.props.refreshId != this.state.refreshId) {
  61. this.onMethodChanged();
  62. this.setState({
  63. refreshId: this.props.refreshId,
  64. rateList: this.props.stationInfo.rateList ?? [],
  65. stationInfo: this.props.stationInfo
  66. }, () => this.refreshAvailable());
  67. if (QRResult.haveResult()) {
  68. const info = QRResult.getResult()
  69. console.log('QRResult', info);
  70. this.setState({
  71. isAuthentic: true,
  72. connectorInfo: info
  73. //soc: info.chargeType == 'AC' ? 0 : 'In Charging'
  74. });
  75. this.checkChargeStatus();
  76. } else if (this.state.isStart) {
  77. this.checkIsCharge();
  78. } else {
  79. this.checkChargeStatus();
  80. }
  81. }
  82. }
  83. componentWillUnmount() {
  84. this.canAutoRefresh = false;
  85. }
  86. //刷新可用充电接口
  87. refreshAvailable() {
  88. const info = this.state.stationInfo
  89. const all = info?.allConnector;
  90. if (info.siteType == 'Private') {
  91. this.setState({
  92. isPrivate: true
  93. })
  94. }
  95. if (all) {
  96. this.setState({
  97. available: !all.available > 0
  98. });
  99. }
  100. }
  101. enterStatioinId() {
  102. if (QRResult.haveResult()) {
  103. const info = QRResult.getResult()
  104. console.log('EnterResult', info);
  105. this.setState({
  106. isAuthentic: true,
  107. connectorInfo: info
  108. //soc: info.chargeType == 'AC' ? 0 : 'In Charging'
  109. });
  110. this.checkChargeStatus();
  111. }
  112. }
  113. onMethodChange() {
  114. this.changeMethod = true;
  115. startPage(PageList.paymentMethod, {info: this.state.connectorInfo, type: this.state.currentPayment});
  116. }
  117. onMethodChanged() {
  118. if (this.changeMethod) {
  119. this.changeMethod = false;
  120. if (global.paymentOption?.title) {
  121. this.setState({
  122. curerntPerUser: global.paymentOption.amount,
  123. currentPayment: global.paymentOption.value,
  124. currentPaytype: global.paymentOption.title
  125. }, () => {
  126. global.paymentOption= {}
  127. })
  128. }
  129. }
  130. }
  131. //扫码之前-站点信息Section
  132. StationInfo() {
  133. return (
  134. <View style={styles.listView}>
  135. <View style={ChargeStyle.stationInfoView}>
  136. <ImageBackground
  137. style={{
  138. width: 42,
  139. height: 42
  140. }}
  141. source={require('../../images/charge/icon-station-no.png')}>
  142. <Text style={{
  143. left: 0,
  144. right: 0,
  145. bottom: 1,
  146. fontSize: 8,
  147. textAlign: 'center',
  148. position: 'absolute'
  149. }}>{this.state.connectorInfo.connectorId}</Text>
  150. </ImageBackground>
  151. <View style={ChargeStyle.infoGroup}>
  152. <Text style={ChargeStyle.infoTitle}>Type</Text>
  153. <Text style={ChargeStyle.infoText}>{this.state.connectorInfo.chargeType}{this.state.connectorInfo.wattage}</Text>
  154. </View>
  155. <View style={ChargeStyle.infoGroup}>
  156. <Text style={ChargeStyle.infoTitle}>Power</Text>
  157. <Text style={ChargeStyle.infoText}>{this.state.connectorInfo.wattage}kW{/*this.state.connectorInfo.rateType*/}</Text>
  158. </View>
  159. <View style={ChargeStyle.infoGroup}>
  160. <Text style={ChargeStyle.infoTitle}>Rate</Text>
  161. <Text style={ChargeStyle.infoText}>{currency}{this.state.connectorInfo.rate}/{this.state.connectorInfo.rateType}</Text>
  162. </View>
  163. { this.state.connectorInfo.isCheckThrough
  164. ? <View style={ChargeStyle.infoGroup}>
  165. <MaterialIcons name='check-circle' size={18} color='#90DB0A'/>
  166. <Text style={ChargeStyle.authText}>Authenticated</Text>
  167. </View>
  168. : <View style={ChargeStyle.infoGroup}>
  169. <MaterialCommunityIcons name='close-circle' size={18} color='#FF6666'/>
  170. <Text style={ChargeStyle.authText}>Not Connected</Text>
  171. </View>
  172. }
  173. </View>
  174. </View>
  175. );
  176. }
  177. //扫码之前-站点信息Section-end
  178. //扫码之后-选择的站点信息Section
  179. UseStationInfo() {
  180. return (
  181. <View style={[styles.listView, { marginTop: 16}]}>
  182. <View style={ChargeStyle.stationInfoView}>
  183. <ImageBackground
  184. style={{
  185. width: 42,
  186. height: 42
  187. }}
  188. source={require('../../images/charge/icon-station-no.png')}>
  189. <Text style={{
  190. left: 0,
  191. right: 0,
  192. bottom: 1,
  193. fontSize: 8,
  194. color: '#333',
  195. textAlign: 'center',
  196. position: 'absolute'
  197. }}>{this.state.connectorInfo.connectorId}</Text>
  198. </ImageBackground>
  199. <View style={ChargeStyle.infoGroup}>
  200. <Text style={ChargeStyle.infoTitle}>Type</Text>
  201. <Text style={ChargeStyle.infoText}>{this.state.connectorInfo.chargeType}{this.state.connectorInfo.wattage}</Text>
  202. </View>
  203. <View style={ChargeStyle.infoGroup}>
  204. <Text style={ChargeStyle.infoTitle}>Power</Text>
  205. <Text style={ChargeStyle.infoText}>{this.state.connectorInfo.wattage}kW</Text>
  206. </View>
  207. <View style={ChargeStyle.infoGroup}>
  208. <Text style={ChargeStyle.infoTitle}>Rate</Text>
  209. <Text style={ChargeStyle.infoText}>{currency}{this.state.connectorInfo.rate}/{this.state.connectorInfo.rateType}</Text>
  210. </View>
  211. <View style={ChargeStyle.infoGroup}>
  212. <Text style={styles.inUse}>In Use</Text>
  213. </View>
  214. </View>
  215. <View style={[ChargeStyle.stationInfoView, ChargeStyle.itemDivide]}>
  216. <View style={ChargeStyle.infoGroup}>
  217. <Text style={ChargeStyle.infoTitle}>Time Elapsed</Text>
  218. <Text style={ChargeStyle.infoText}>{this.state.connectorInfo.timeElapsed?.toFixed(0) ?? 0} Minutes</Text>
  219. </View>
  220. <View style={ChargeStyle.infoGroup}>
  221. <Text style={ChargeStyle.infoTitle}>Total kWh Delivered</Text>
  222. <Text style={ChargeStyle.infoText}>{this.state.connectorInfo.totalKWhDelivered ?? 0} kWh</Text>
  223. </View>
  224. <View style={ChargeStyle.infoGroup}>
  225. <Text style={ChargeStyle.infoTitle}>Total Charges</Text>
  226. <Text style={ChargeStyle.infoText}>{currency} {this.state.connectorInfo.totalCharges?.toFixed(2) ?? '0.0'}</Text>
  227. </View>
  228. </View>
  229. </View>
  230. );
  231. }
  232. //扫码之后-选择的站点信息Section-end
  233. //初始页面-扫码认证之前
  234. StepRateView() {
  235. return (
  236. <>
  237. <Text style={styles.title}>Rates</Text>
  238. <View style={styles.listView}>
  239. { this.state.rateList.length > 0
  240. ? this.state.rateList.map((item, index) => {
  241. return (
  242. <View key={index} style={[ChargeStyle.stationInfoView, index > 0 ? ChargeStyle.itemDivide : {}]}>
  243. <Image
  244. style={ChargeStyle.infoIcon}
  245. source={item.type?.indexOf('AC') >= 0 ? TypeImage.AC : TypeImage.DC}/>
  246. <View style={ChargeStyle.infoGroup}>
  247. <Text style={ChargeStyle.infoTitle}>Type</Text>
  248. <Text style={ChargeStyle.infoText}>{item.type}</Text>
  249. </View>
  250. <View style={ChargeStyle.infoGroup}>
  251. <Text style={ChargeStyle.infoTitle}>Power</Text>
  252. <Text style={ChargeStyle.infoText}>{item.power}</Text>
  253. </View>
  254. <View style={ChargeStyle.infoGroup}>
  255. <Text style={ChargeStyle.infoTitle}>Rate</Text>
  256. <Text style={ChargeStyle.infoText}>{item.rates}</Text>
  257. </View>
  258. { item?.connectorCount?.available > 0
  259. ? <TextRadius style={[ChargeStyle.infoStatus, ChargeStyle.statusAvailable]}>Available</TextRadius>
  260. : <TextRadius style={[ChargeStyle.infoStatus, ChargeStyle.statusUnavailable]}>Unavailable</TextRadius>
  261. }
  262. </View>
  263. );
  264. })
  265. : <Text style={ui.noData}>No Rates</Text>
  266. }
  267. </View>
  268. <View style={styles.privateView}>
  269. { this.state.isPrivate &&
  270. <Text style={styles.privateText}>NOTE: The charging stations are for private usage.</Text>
  271. }
  272. </View>
  273. <Payment refreshId={this.state.refreshId}/>
  274. <View style={styles.buttonGroup}>
  275. <Button
  276. style={styles.buttonLeft}
  277. text='Scan QR'
  278. //disabled={this.state.available}
  279. onClick={() => {
  280. startPage(PageList.scanqr, {actionDetail: false, id: this.state.stationInfo.id});
  281. }}/>
  282. <Button
  283. style={styles.buttonRight}
  284. text='Enter Station ID'
  285. //disabled={this.state.available}
  286. onClick={() => {
  287. this.setState({
  288. showStationDialog: true
  289. })
  290. }}/>
  291. </View>
  292. </>
  293. );
  294. }
  295. //初始页面-扫码认证之前-end
  296. //扫码认证之后-充电开始之前
  297. StepStartView() {
  298. return (
  299. <>
  300. <Text style={styles.title}>Your Selection</Text>
  301. {this.StationInfo()}
  302. <View style={ui.center}>
  303. <ImageBackground
  304. style={styles.batteryBorder}
  305. source={require('../../images/charge/ic-charge-circle.png')}>
  306. <Text style={{
  307. color: '#333',
  308. fontSize: 16,
  309. lineHeight: 22,
  310. textAlign: 'center'
  311. }}>
  312. Press<Text style={{padding: 10, fontWeight: 'bold'}}> Start </Text>to begin Charging
  313. </Text>
  314. </ImageBackground>
  315. </View>
  316. <Payment
  317. refreshId={this.state.refreshId}
  318. payType={this.state.currentPaytype}
  319. balance={this.state.curerntPerUser}
  320. isPayPerUse={this.state.currentPayment == PAYTYPE.PAY_PER_USE}
  321. onMethodChange={() => this.onMethodChange()}
  322. />
  323. <Button
  324. style={styles.buttonView}
  325. text='Start'
  326. elevation={1.5}
  327. onClick={() => this.startCharge()}/>
  328. </>
  329. );
  330. }
  331. //扫码认证之后-充电开始之前-end
  332. //正在充电页面
  333. StepChargeView() {
  334. return (
  335. <>
  336. {this.UseStationInfo()}
  337. <BatteryView
  338. soc={this.state.connectorInfo.batteryPercent}
  339. isCharging={this.state.isCharging}
  340. isPending={this.state.isPending}
  341. />
  342. { this.state.lastUpdated
  343. ? <Text style={styles.updateTip}>{'Last updated at ' + this.state.lastUpdated + '\nPull down to refresh'}</Text>
  344. : null
  345. }
  346. <Payment
  347. refreshId={this.state.refreshId}
  348. payType={this.state.currentPaytype}
  349. balance={this.state.curerntPerUser}
  350. />
  351. <Button
  352. style={styles.buttonView}
  353. disabled={this.state.isPending}
  354. text={this.state.isCharging ? 'Stop Charging' : 'Complete'}
  355. elevation={1.5}
  356. onClick={() => {
  357. if (this.state.isCharging) {
  358. Dialog.showDialog({
  359. title: 'Stop Charging',
  360. message: 'Are you sure stop charging?',
  361. callback: ok => {
  362. if (ok == Dialog.BUTTON_OK) {
  363. this.stopCharge();
  364. }
  365. }
  366. });
  367. } else {
  368. this.stopCharge();
  369. }
  370. }}/>
  371. </>
  372. );
  373. }
  374. //正在充电页面-end
  375. //自动刷新
  376. autoCheckIsCharge() {
  377. if (this.canAutoRefresh) {
  378. this.checkIsCharge();
  379. }
  380. }
  381. //自动刷新状态
  382. autoCheckChargeStatus() {
  383. setTimeout(() => {
  384. if (this.canAutoRefresh) {
  385. this.checkChargeStatus();
  386. }
  387. }, 10000);
  388. }
  389. //获取充电数据(百分比)
  390. checkIsCharge(showError) {
  391. const params = {
  392. sitePk: this.props.stationInfo.id
  393. }
  394. apiCharge.checkIsCharging(params).then(res => {
  395. this.setState({
  396. isStart: true,
  397. isCharging: true,
  398. isAuthentic: true,
  399. connectorInfo: res.data,
  400. lastUpdated: utils.getNowHHmm()
  401. });
  402. if (this.canAutoRefresh) {
  403. setTimeout(() => {
  404. this.autoCheckIsCharge();
  405. }, 30000);
  406. }
  407. if (!this.props.visible && this.props.onCharge)
  408. this.props.onCharge()
  409. }).catch(err => {
  410. //TODO 模拟测试
  411. this.setState({
  412. isStart: false,
  413. isCharging: false
  414. });
  415. setTimeout(() => {
  416. this.autoCheckIsCharge();
  417. }, 30000);
  418. if (showError) {
  419. this.setState({
  420. errorCode: 'A4',
  421. showErrorDialog: true,
  422. errorMessage: 'Your vehicle doesn’t seem to be charging. Please check your vehicle.'
  423. });
  424. }
  425. });
  426. }
  427. //获取充电桩对应接口的状态
  428. checkChargeStatus() {
  429. //TODO 模拟测试
  430. /*this.setState({
  431. isStart: true,
  432. isCharging: true,
  433. isAuthentic: true
  434. });
  435. return;*/
  436. const params = {
  437. connectorId: this.state.connectorInfo.connectorId,
  438. chargeBoxId: this.state.connectorInfo.chargeBoxId,
  439. }
  440. if (!params.chargeBoxId || !params.connectorId) {
  441. return;
  442. }
  443. apiCharge.getCurrentStatus(params).then(res => {
  444. if (res.data.status) {
  445. switch (res.data.status) {
  446. case 'Available': //可用的
  447. this.state.connectorInfo.isCheckThrough = false;
  448. this.setState({
  449. isStart: false,
  450. isPending: false,
  451. isCharging: false,
  452. connectorInfo: this.state.connectorInfo
  453. });
  454. break;
  455. case 'Preparing': //已插入
  456. this.state.connectorInfo.isCheckThrough = true;
  457. this.setState({
  458. isStart: false,
  459. isPending: false,
  460. isCharging: false,
  461. available: true,
  462. connectorInfo: this.state.connectorInfo
  463. });
  464. //this.checkIsCharge();
  465. break;
  466. case 'Charging': //正在充电
  467. this.canAutoRefresh = true;
  468. this.state.connectorInfo.isCheckThrough = true;
  469. this.setState({
  470. isPending: false,
  471. connectorInfo: this.state.connectorInfo
  472. });
  473. this.checkIsCharge();
  474. break;
  475. case 'Initiating': //充电确认中
  476. this.canAutoRefresh = true;
  477. this.state.connectorInfo.isCheckThrough = true;
  478. this.setState({
  479. isStart: true,
  480. isPending: true,
  481. isCharging: true,
  482. isAuthentic: true,
  483. connectorInfo: this.state.connectorInfo
  484. });
  485. this.autoCheckChargeStatus();
  486. break;
  487. case 'SuspendedEVSE':
  488. this.setState({
  489. errorCode: 'A5',
  490. showErrorDialog: true,
  491. errorMessage: 'The charging station is unable to charge your vehicle.Please reauthenticate.'
  492. });
  493. break;
  494. case 'SuspendedEV': //已连接上但未充电
  495. this.checkIsCharge(true);
  496. break;
  497. case 'Reserved': //预定中
  498. this.setState({
  499. errorCode: 'A5',
  500. showErrorDialog: true,
  501. errorMessage: 'The charging station is reserved and unable to charge your vehicle.'
  502. });
  503. break;
  504. case 'Finishing': //已完成
  505. this.setState({
  506. isStart: true,
  507. isPending: false,
  508. isCharging: false
  509. });
  510. break;
  511. default:
  512. this.setState({
  513. isStart: false,
  514. isPending: false,
  515. isCharging: false
  516. });
  517. this.setState({
  518. errorCode: 'A4',
  519. showErrorDialog: true,
  520. errorMessage: 'Your vehicle doesn’t seem to be charging. Please check your vehicle. (E0)'
  521. });
  522. break;
  523. }
  524. }
  525. }).catch(err => {
  526. toastShort(err)
  527. this.setState({
  528. errorCode: 'A9',
  529. showErrorDialog: true,
  530. errorMessage: 'There seems to be an authentication error! Please try again'
  531. });
  532. })
  533. }
  534. //开始充电api
  535. startCharge() {
  536. if (this.state.connectorInfo.isCheckThrough) {
  537. Dialog.showProgressDialog();
  538. const params = {
  539. chargeBoxId: this.state.connectorInfo.chargeBoxId,
  540. connectorId: this.state.connectorInfo.connectorId
  541. }
  542. apiCharge.startCharge(params).then(res => {
  543. this.setState({
  544. isStart: true,
  545. isPending: true,
  546. isCharging: true
  547. });
  548. this.canAutoRefresh = true;
  549. this.autoCheckChargeStatus();
  550. /*setTimeout(() => {
  551. this.autoCheckIsCharge();
  552. }, 30000);*/
  553. Dialog.dismissLoading();
  554. }).catch(err => {
  555. //toastShort(err);
  556. Dialog.dismissLoading();
  557. this.setState({
  558. errorCode: 'A4',
  559. showErrorDialog: true,
  560. errorMessage: ''+err
  561. });
  562. });
  563. } else {
  564. this.setState({
  565. errorCode: 'A1',
  566. showErrorDialog: true,
  567. errorMessage: 'Your vehicle is not connected to the charging station. Please check the connector.'
  568. });
  569. }
  570. }
  571. //停止充电api
  572. stopCharge() {
  573. this.canAutoRefresh = false;
  574. Dialog.showProgressDialog();
  575. apiCharge.stopCharge().then(res => {
  576. if (res.data.chargingPk) {
  577. setTimeout(() => {
  578. Dialog.dismissLoading();
  579. this.setState({
  580. isStart: false,
  581. isPending: false,
  582. isCharging: false
  583. });
  584. startPage(PageList.summary, {
  585. chargingPk: res.data.chargingPk,
  586. id: this.state.stationInfo.id,
  587. name: this.state.stationInfo.name,
  588. address: this.state.stationInfo.address
  589. });
  590. }, 3000);
  591. } else {
  592. Dialog.dismissLoading();
  593. toastShort('An error detected, please retry.')
  594. }
  595. }).catch(err => {
  596. Dialog.dismissLoading();
  597. toastShort(err);
  598. this.setState({
  599. isStart: false,
  600. isPending: false,
  601. isCharging: false
  602. });
  603. //模拟进入结算页
  604. /*startPage(PageList.summary, {
  605. chargingPk: 1,
  606. id: this.state.stationInfo.id,
  607. name: this.state.stationInfo.name,
  608. address: this.state.stationInfo.address
  609. });*/
  610. });
  611. }
  612. closeError() {
  613. this.setState({
  614. showErrorDialog: false,
  615. showStationDialog: false
  616. });
  617. }
  618. render() {
  619. return (
  620. <View style={{
  621. paddingLeft: 16,
  622. paddingRight: 16,
  623. ...this.props.style
  624. }}>
  625. { this.state.isAuthentic //是否扫码认证
  626. ? this.state.isStart //是否开始充电
  627. ? this.StepChargeView()
  628. : this.StepStartView()
  629. : this.StepRateView()
  630. }
  631. <ErrorDialog
  632. visible={this.state.showErrorDialog}
  633. code={this.state.errorCode}
  634. message={this.state.errorMessage}
  635. onClose={() => {
  636. this.closeError();
  637. }}
  638. />
  639. <EnterStationDialog
  640. visible={this.state.showStationDialog}
  641. stationId={this.state.stationInfo.id}
  642. onConfirm={() => this.enterStatioinId()}
  643. onClose={() => this.closeError()}
  644. />
  645. </View>
  646. );
  647. }
  648. }
  649. const styles = StyleSheet.create({
  650. title: {
  651. color: '#000',
  652. fontSize: 14,
  653. fontWeight: 'bold',
  654. paddingTop: 16,
  655. paddingBottom: 16
  656. },
  657. listView: {
  658. padding: 8,
  659. borderRadius: 8,
  660. backgroundColor: '#F5F5F5'
  661. },
  662. batteryBorder: {
  663. margin: 30,
  664. padding: 32,
  665. width: circleSize,
  666. height: circleSize,
  667. alignItems: 'center',
  668. justifyContent: 'center'
  669. },
  670. buttonView: {
  671. marginTop: 16,
  672. marginBottom: 32
  673. },
  674. buttonGroup: {
  675. marginTop: 16,
  676. marginBottom: 16,
  677. alignItems: 'center',
  678. flexDirection: 'row'
  679. },
  680. buttonLeft: {
  681. flex: 1,
  682. elevation: 1.5,
  683. },
  684. buttonRight: {
  685. flex: 1,
  686. marginLeft: 16,
  687. elevation: 1.5
  688. },
  689. inUse: {
  690. color: '#fff',
  691. fontSize: 12,
  692. paddingTop: 4,
  693. paddingLeft: 8,
  694. paddingRight: 8,
  695. paddingBottom: 4,
  696. borderRadius: 4,
  697. backgroundColor: '#FF7A00'
  698. },
  699. updateTip: {
  700. color: '#aaa',
  701. fontSize: 10,
  702. textAlign: 'center',
  703. paddingBottom: 16
  704. },
  705. privateView: {
  706. height: $vht(25),
  707. alignItems: 'center',
  708. justifyContent: 'center'
  709. },
  710. privateText: {
  711. color: '#FA5759'
  712. }
  713. })