Sfoglia il codice sorgente

Develop DrawerV4 and Wallets Page
https://dev.wormwood.com.sg/zentao/task-view-512.html

vbea 1 anno fa
parent
commit
1b3580fabb

+ 21 - 0
Strides-APP/app/api/apiWallets.js

@@ -0,0 +1,21 @@
+import { get, post } from "./http";
+
+const prefix = 'devicesApi/dawn/api/v1/';
+
+export default apiWallets = {
+  /**
+   * 获取用户钱包列表
+   * @returns Promise
+   */
+  getWalletsInfo() {
+    return get(prefix + "user/payment-methods", {})
+  },
+  /**
+   * 获取指定钱包的交易历史记录
+   * @param {*} data {latestPk,walletTypeCode}
+   * @returns Promise
+   */
+  getTransactionList(data) {
+    return get(prefix + "user/transaction-histories", data)
+  }
+}

+ 470 - 0
Strides-APP/app/pages/home/DrawerV4.js

@@ -0,0 +1,470 @@
+/**
+ * V4版抽屉菜单
+ * @邠心vbe on 2025/01/17
+ */
+import React from 'react';
+import { Path, Svg } from 'react-native-svg';
+import { StyleSheet, Text, View } from 'react-native';
+import app from '../../../app.json';
+import { PageList } from '../Router';
+import utils from '../../utils/utils';
+import apiCharge from '../../api/apiCharge';
+import Button from '../../components/Button';
+import Dialog from '../../components/Dialog';
+import TextView from '../../components/TextView';
+import { BackButton } from '../../components/Toolbar';
+import { toTopupPage } from '../payment/PaymentConfig';
+
+const DEBUG = app.debug && !app.product;
+
+export default DrawerV3 = ({isLogin=false, userInfo, onLogout, sideCountInfo={}, navigation}) => {
+  const getCharging = () => {
+    Dialog.showProgressDialog();
+    apiCharge.getUserCharging().then(res => {
+      Dialog.dismissLoading();
+      if (res.data.sitePk) {
+        utils.toChargeDetailPage(res.data.sitePk, 'view', PageList.home);
+        //startPage(PageList.chargeDetailPage, {stationInfo: {id: res.data.sitePk}, action: 'view', from: PageList.home});
+        //startPage(PageList.chargeDetail, { stationInfo: {id: res.data.sitePk}, action: 'view'});
+      } else if (res.msg) {
+        toastShort(res.msg);
+      } else {
+        toastShort($t("drawer.noChargingSession"));
+      }
+    }).catch((err) => {
+      if (app.debug)
+        console.log(err);
+      Dialog.dismissLoading();
+      toastShort($t("drawer.noChargingSession"));
+    })
+  }
+
+  const logout = () => {
+    Dialog.showDialog({
+      title: $t('profile.signOut'),
+      message: $t('profile.tipSignOut'),
+      callback: btn => {
+        if (btn == Dialog.BUTTON_OK) {
+          Dialog.showProgressDialog();
+          setTimeout(() => {
+            if (onLogout) onLogout();
+          }, 500);
+        }
+      }
+    })
+  }
+
+  return (
+    <View style={styles.drawerView}>
+      <View style={styles.loginView}>
+        {/* <View style={ui.flexcw}>
+          { (isLogin && userInfo.photoUrl)
+          ? <TouchableWithoutFeedback>
+              <Image
+                style={styles.avatar}
+                source={{uri: utils.getImageUrl(userInfo.photoUrl)}}/>
+            </TouchableWithoutFeedback>
+          : <TouchableWithoutFeedback>
+              <Image
+                style={styles.avatar}
+                source={require('../../images/user/ic-avatar-default.png')}/>
+            </TouchableWithoutFeedback>
+          }
+          <BackButton
+            style={styles.closeMenu}
+            onPress={() => navigation?.toggleDrawer()}>
+            <MaterialIcons
+              name="menu-open"
+              size={24}
+              color={colorLight}/>
+          </BackButton>
+        </View> */}
+        { isLogin
+        ? <View
+            style={styles.nickViewStyle}>
+            <View style={ui.flex1}>
+              <TextView
+                style={styles.nickname}
+                ellipsizeMode='tail'
+                numberOfLines={1}>
+                { userInfo.nickName 
+                ? userInfo.nickName
+                : $t('drawer.logging')
+                }
+              </TextView>
+              <TextView
+                style={styles.emailText}
+                ellipsizeMode='tail'
+                numberOfLines={1}>{userInfo.email}</TextView>
+            </View>
+            <BackButton
+              onPress={logout}>
+              <MaterialIcons
+                size={26}
+                color={textPrimary}
+                name='exit-to-app'/>
+            </BackButton>
+          </View>
+        : <Button
+            style={styles.nickView}
+            viewStyle={styles.nickViewStyle}
+            onClick={() => startPage(PageList.login)}>
+            <TextView
+              style={styles.loginText}
+              ellipsizeMode='tail'
+              numberOfLines={1}>
+              {$t('drawer.sign')}
+            </TextView>
+            <FontAwesome
+              size={24}
+              color={textPrimary}
+              name='angle-right'/>
+          </Button>
+        }
+      </View>
+      <View style={styles.divideLogin}></View>
+      { isLogin && <>
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => startPage(app.isLumiWhitelabel ? PageList.profileV3 : PageList.profile)}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="account-circle"
+            color={textPrimary}
+            size={24}/>
+          <TextView style={styles.label}>{$t('route.profileSettings')}</TextView>
+        </Button>
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => getCharging()}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="gas-station"
+            color={textPrimary}
+            size={24}/>
+          <TextView style={styles.label}>{$t('drawer.charging')}</TextView>
+        </Button>
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.wallet);
+          }}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="finance"
+            color={textPrimary}
+            size={24}/>
+          <TextView style={styles.label}>{$t('drawer.wallet')}</TextView>
+        </Button>
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => startPage(PageList.wallets)}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="wallet-outline"
+            color={textPrimary}
+            size={24}/>
+          <TextView style={styles.label}>{$t('drawer.wallets')}</TextView>
+        </Button>
+        </>
+      }
+      { (app.v3.vouchers && isLogin) &&
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => startPage(PageList.myVoucher)}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="ticket-percent-outline"
+            color={textPrimary}
+            size={24}/>
+          <TextView style={styles.label}>{$t('voucher.vouchers')}</TextView>
+          <TextView
+            style={styles.balanceText}
+            fixedAlign={false}>
+            <Text style={styles.balanceText2}>{sideCountInfo?.activeVoucherCount || 0}</Text>  Active
+          </TextView>
+        </Button>
+      }
+      { (app.notifications.enable && isLogin) &&
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.notification);
+          }}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="bell-badge-outline"
+            color={textPrimary}
+            size={24}/>
+          <TextView style={styles.label}>{$t('route.notifications')}</TextView>
+          <TextView
+            style={styles.balanceText}
+            fixedAlign={false}>
+            <Text style={styles.balanceText2}>{sideCountInfo?.toBeReadCount || 0}</Text>  Unread
+          </TextView>
+        </Button>
+      }
+      { (app.modules.bookmarks && isLogin) &&
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.bookmarks);
+          }}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="bookmark-check-outline"
+            color={textPrimary}
+            size={24}/>
+          <TextView style={styles.label}>{$t('route.bookmarks')}</TextView>
+          <TextView
+            style={styles.balanceText}
+            fixedAlign={false}>
+            <Text style={styles.balanceText2}>{sideCountInfo?.bookMarkCount || 0}</Text>  Saved
+          </TextView>
+        </Button>
+      }
+      {/*附加功能-结束*/}
+      { (app.modules.membership && isLogin) &&
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.membersList);
+          }}>
+          <Svg 
+            style={styles.icon}
+            width={24}
+            height={24}
+            viewBox='0 0 24 24'>
+            <Path
+              fill={textPrimary}
+              d="M7 4C4.8 4 3 5.8 3 8C3 10.2 4.8 12 7 12C9.2 12 11 10.2 11 8C11 5.8 9.2 4 7 4ZM7 10C5.9 10 5 9.1 5 8C5 6.9 5.9 6 7 6C8.1 6 9 6.9 9 8C9 9.1 8.1 10 7 10ZM0 18C0 15.8 3.1 14 7 14C8.5 14 9.9 14.3 11 14.7V17C10.2 16.5 8.8 16 7 16C3.8 16 2 17.4 2 18H11V20H0V18ZM22 4H15C13.9 4 13 4.9 13 6V18C13 19.1 13.9 20 15 20H22C23.1 20 24 19.1 24 18V6C24 4.9 23.1 4 22 4ZM22 18H15V6H22V18Z"/>
+          </Svg>
+          <TextView style={styles.label}>{$t('drawer.members')}</TextView>
+          <TextView
+            style={styles.balanceText}
+            fixedAlign={false}>
+            <Text style={styles.balanceText2}>{sideCountInfo?.membershipCount || 0}</Text>  Active
+          </TextView>
+        </Button>
+      }
+      {/* <Button
+        style={styles.itemButton}
+        viewStyle={styles.itemView}
+        onClick={() => {
+          startPage(PageList.feedback);
+        }}>
+        <MaterialCommunityIcons
+          style={styles.icon}
+          name="message-alert-outline"
+          color="#222"
+          size={24}/>
+        <TextView style={styles.label}>{$t('drawer.feedback')}</TextView>
+      </Button> */}
+      {/* <Button
+        style={styles.itemButton}
+        viewStyle={styles.itemView}
+        onClick={() => {
+          startPage(PageList.settings);
+        }}>
+        <MaterialIcons
+          style={styles.icon}
+          name="settings"
+          color="#222"
+          size={25}
+        />
+        <TextView style={styles.label}>{$t('drawer.settings')}</TextView>
+      </Button> */}
+      { app.modules.support &&
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.supportContact);
+          }}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="face-agent"
+            color="#333"
+            size={26}
+          />
+          <TextView style={styles.label}>{$t('drawer.contactSupport')}</TextView>
+        </Button>
+      }
+      { DEBUG && <>
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.notify);
+          }}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="dev-to"
+            color="#333"
+            size={26}
+          />
+          <TextView style={styles.label}>{$t('route.notificationTest')}</TextView>
+        </Button>
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.selectVoucher, {chargeBoxId: "LUMI-TEST", connectorId: 1});
+          }}>
+          <MaterialCommunityIcons
+            style={styles.icon}
+            name="dev-to"
+            color="#333"
+            size={26}
+          />
+          <TextView style={styles.label}>{"Test Page"}</TextView>
+        </Button>
+      </> }
+    </View>
+  );
+}
+
+const styles = StyleSheet.create({
+  drawerView: {
+    paddingTop: 8,
+    paddingBottom: 8,
+  },
+  loginView: {
+    paddingTop: 0,
+    paddingBottom: 0,
+    backgroundColor: colorLight
+  },
+  avatar: {
+    width: 60,
+    height: 60,
+    marginLeft: 24,
+    borderWidth: 2,
+    borderRadius: 80,
+    borderColor: colorPrimary,
+  },
+  closeMenu: {
+    width: 40,
+    height: 40,
+    marginRight: 16,
+    borderRadius: 40,
+    alignItems: 'center',
+    justifyContent: 'center',
+    backgroundColor: colorPrimary
+  },
+  nickView: {
+    marginTop: 2,
+    borderRadius: 0,
+    backgroundColor: colorLight
+  },
+  nickViewStyle: {
+    flex: 1,
+    alignItems: 'center',
+    flexDirection: 'row',
+    ...$padding(0, 4, 10)
+  },
+  nickname: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 20,
+    fontWeight: 'bold',
+    paddingLeft: 16,
+  },
+  emailText: {
+    color: textPrimary,
+    fontSize: 10,
+    marginTop: -5,
+    paddingLeft: 16,
+    paddingBottom: 4
+  },
+  loginText: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 18,
+    fontWeight: 'bold',
+    marginTop: 4,
+    paddingTop: 4,
+    paddingLeft: 16,
+    paddingBottom: 4,
+    textTransform: 'uppercase'
+  },
+  divideLogin: {
+    height: 8,
+    marginTop: 2,
+    marginRight: 0,
+    marginBottom: 8,
+    backgroundColor: colorPrimary
+  },
+  itemButton: {
+    borderRadius: 0,
+    backgroundColor: colorLight
+  },
+  itemView: {
+    flex: 1,
+    height: 48,
+    paddingLeft: 16,
+    marginBottom: 0,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  icon: {
+    width: 24,
+    height: 24,
+    marginRight: 16
+  },
+  label: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 14
+  },
+  divided: {
+    height: 1,
+    marginTop: 24,
+    marginLeft: 16,
+    backgroundColor: colorAccent
+  },
+  balanceText: {
+    color: textPrimary,
+    fontSize: 14,
+    marginRight: 20
+  },
+  balanceText2: {
+    color: colorPrimary,
+    fontSize: 14,
+    fontWeight: 'bold',
+    marginRight: 20
+  },
+  bridgeText: {
+    width: 20,
+    height: 20,
+    color: textLight,
+    fontSize: 12,
+    marginRight: 16,
+    borderRadius: 30,
+    fontWeight: 'bold',
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+    backgroundColor: "#FF3B30"
+  },
+  bridgeText2: {
+    width: 22,
+    height: 22,
+    color: textLight,
+    fontSize: 10,
+    marginRight: 16,
+    borderRadius: 30,
+    fontWeight: 'bold',
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+    backgroundColor: "#FF3B30"
+  }
+});

+ 86 - 0
Strides-APP/app/pages/wallets/ViewHistory.js

@@ -0,0 +1,86 @@
+/**
+ * 钱包交易历史
+ * @邠心vbe on 2025/01/17
+ */
+import React from 'react';
+import { StyleSheet } from 'react-native';
+import { Pressable } from 'react-native';
+import { View } from 'react-native';
+import TextView from '../../components/TextView';
+import { PageList } from '../Router';
+
+const getTransTitle = (item) => {
+  let title = "";
+  if (item.remarks) {
+    title += item.remarks;
+  } else if (item.amountSymbol == 'M') {
+    title +=(item.siteName || "Charging");
+  } else {
+    title += $t('wallet.topUp');
+  }
+  return title;
+}
+
+const toSummary = (item) => {
+  if (item.refPk) {
+    startPage(PageList.summary, { action: 'view', chargingPk: item.refPk });
+  }
+}
+
+const ViewHistory = ({
+  item,
+  index,
+  separators
+}) => (
+  <Pressable
+    style={styles.historyItem}
+    android_ripple={ripple}
+    onPress={() => toSummary(item)}>
+    <View style={styles.itemContent}>
+      <TextView style={styles.textDesc}>{item.createTime}</TextView>
+      <TextView style={styles.textId}>{$t("receipt.labelTransactionID")}{item.creditHistoryPk}</TextView>
+      <TextView style={styles.textTitle}>{getTransTitle(item)}</TextView>
+    </View>
+    { item.amountSymbol == 'M'
+      ? <TextView style={styles.amountDuct}>- {item.amount}</TextView>
+      : <TextView style={styles.amountText}>+ {item.amount}</TextView>
+    }
+  </Pressable>
+);
+
+export default ViewHistory;
+
+const styles = StyleSheet.create({
+  historyItem: {
+    padding: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  itemContent: {
+    flex: 1,
+    paddingRight: 16
+  },
+  textTitle: {
+    color: textPrimary,
+    fontSize: 15,
+    fontWeight: 'bold'
+  },
+  textDesc: {
+    color: textSecondary,
+    fontSize: 13
+  },
+  textId: {
+    color: textSecondary,
+    fontSize: 14,
+    paddingTop: 2,
+    paddingBottom: 2
+  },
+  amountDuct: {
+    color: '#FF2E00',
+    fontSize: 14
+  },
+  amountText: {
+    color: colorAccent,
+    fontSize: 14
+  }
+})

+ 60 - 0
Strides-APP/app/pages/wallets/ViewWallet.js

@@ -0,0 +1,60 @@
+/**
+ * 钱包卡片组件
+ * @邠心vbe on 2025/01/17
+ */
+import React from 'react';
+import { StyleSheet } from 'react-native';
+import { Text, View } from 'react-native';
+import { ElevationObject } from '../../components/Button';
+import TextView from '../../components/TextView';
+import utils from '../../utils/utils';
+
+const ViewWallet = ({
+  wallet
+}) => (
+  <View style={styles.cardWallet}>
+    <View style={ui.flexc}>
+      <TextView style={styles.walletName}>{wallet.walletTypeName}</TextView>
+    </View>
+    <TextView style={styles.walletProvider}>{wallet.walletPrincipalName}</TextView>
+    <TextView style={styles.walletLabel}>Current Balance:</TextView>
+    <TextView style={styles.walletBalance}>{wallet.currentBalance}</TextView>
+    { utils.isNotEmpty(wallet.expiresDate) &&
+      <TextView style={styles.walletLabel}>Expires {wallet.expiresDate}</TextView>
+    }
+  </View>
+);
+
+export default ViewWallet;
+
+const styles = StyleSheet.create({
+  cardWallet: {
+    height: 182,
+    margin: 16,
+    padding: 16,
+    borderRadius: 16,
+    ...ElevationObject(2),
+    backgroundColor: colorAccent
+  },
+  walletName: {
+    color: textLight,
+    fontSize: 24,
+    fontWeight: 'bold'
+  },
+  walletProvider: {
+    color: textLight,
+    fontSize: 20,
+  },
+  walletLabel: {
+    color: textLight,
+    opacity: .9,
+    fontSize: 14,
+    paddingTop: 16
+  },
+  walletBalance: {
+    color: textLight,
+    fontSize: 20,
+    paddingTop: 4,
+    fontWeight: 'bold'
+  }
+})

+ 197 - 0
Strides-APP/app/pages/wallets/Wallets.js

@@ -0,0 +1,197 @@
+/**
+ * 多钱包页面
+ * @邠心vbe on 2025/01/17
+ */
+import React, { Component } from 'react';
+import { FlatList, StyleSheet } from 'react-native';
+import { View, Text } from 'react-native';
+import PagerView from 'react-native-pager-view';
+import apiWallets from '../../api/apiWallets';
+import { ElevationObject } from '../../components/Button';
+import VbeSkeleton from '../../components/VbeSkeleton';
+import ViewHistory from './ViewHistory';
+import ViewWallet from './ViewWallet';
+
+export default class Wallets extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      loading: true,
+      wallets: [],
+      active: 0,
+      history: {
+
+      },
+      historyList: [],
+      loadingList: false
+    };
+  }
+
+  componentDidMount() {
+    setTimeout(() => {
+      this.getWalletsInfo();
+    }, 500);
+  }
+
+  getWalletsInfo() {
+    apiWallets.getWalletsInfo().then(res => {
+      if (res.data) {
+        this.setState({
+          wallets: res.data
+        })
+      }
+    }).catch(err => {
+      toastShort(err)
+    }).finally(() => {
+      this.setState({
+        loading: false
+      })
+    })
+  }
+
+  getTransactionInfo(code) {
+    if (this.state.history[code]) {
+      this.setState({
+        loadingList: false,
+        historyList: this.state.history[code]
+      })
+      return;
+    }
+    apiWallets.getTransactionList({
+      walletTypeCode: code
+    }).then(res => {
+      if (res.data) {
+        this.state.history[code] = res.data;
+        this.setState({
+          historyList: res.data
+        })
+      } else {
+        this.setState({
+          historyList: []
+        })
+      }
+    }).catch(err => {
+      this.setState({
+        historyList: []
+      })
+    }).finally(() => {
+      this.setState({
+        loadingList: false
+      })
+    })
+  }
+
+  changeCard(e) {
+    //console.log("changeCard", e.nativeEvent.position);
+    this.setState({
+      active: e.nativeEvent.position
+    }, () => {
+      let wallet = this.state.wallets[this.state.active];
+      if (wallet && wallet.walletTypeCode) {
+        this.setState({
+          loadingList: true
+        });
+        setTimeout(() => {
+          this.getTransactionInfo(wallet.walletTypeCode);
+        }, 300);
+      }
+    })
+  }
+
+  divideView = (props) => {
+    return (<View style={styles.divideView}></View>)
+  }
+
+  render() {
+    if (this.state.loading) {
+      return (
+        <VbeSkeleton
+          style={[ui.flex1, $padding(16)]}
+          layout={[
+            {width: "100%", height: 200, borderRadius: 16},
+            {width: "100%", height: $vh(100) - 320, borderRadius: 16, marginTop: 24},
+          ]}
+          animationDirection={"horizontalRight"}
+        />
+      )
+    }
+    return (
+      <View style={styles.container}>
+        <PagerView
+          style={styles.pagerView}
+          initialPage={0}
+          onPageSelected={e => this.changeCard(e)}>
+          { this.state.wallets.map((item, index) => (
+            <ViewWallet key={index} wallet={item}/>
+          ))}
+        </PagerView>
+        <View style={styles.indicatorView}>
+          { this.state.wallets.map((item, index) => (
+            <MaterialCommunityIcons
+              key={index}
+              style={$margin(2)}
+              name={this.state.active == index ? "checkbox-blank-circle" : "checkbox-blank-circle-outline"}
+              size={10}/>
+          ))}
+        </View>
+        <View style={styles.listView}>
+          { this.state.loadingList
+          ? <VbeSkeleton
+            style={[ui.flex1, $padding(16)]}
+            layout={[
+              {width: "100%", height: 14, borderRadius: 16},
+              {width: "100%", height: 14, borderRadius: 16, marginTop: 12},
+              {width: "60%", height: 14, borderRadius: 16, marginTop: 12},
+              {width: "100%", height: 14, borderRadius: 16, marginTop: 24},
+              {width: "100%", height: 14, borderRadius: 16, marginTop: 12},
+              {width: "60%", height: 14, borderRadius: 16, marginTop: 12}
+            ]}/>
+          : <FlatList
+              data={this.state.historyList}
+              renderItem={ViewHistory}
+              ItemSeparatorComponent={this.divideView}
+              keyExtractor={item => item.refPk}
+              ListEmptyComponent={<Text style={styles.noData}>No Data</Text>}/>
+          }
+        </View>
+      </View>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: pageBackground
+  },
+  pagerView: {
+    height: 200
+  },
+  indicatorView: {
+    padding: 8,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+  },
+  listView: {
+    flex: 1,
+    overflow: 'hidden',
+    ...$margin(8, 16, 16),
+    ...ElevationObject(2),
+    borderRadius: 16,
+    backgroundColor: colorLight
+  },
+  noData: {
+    color: textPlacehoder,
+    fontSize: 14,
+    padding: 20,
+    textAlign: 'center'
+  },
+  divideView: {
+    height: 1,
+    opacity: 0.5,
+    marginLeft: 16,
+    marginRight: 16,
+    backgroundColor: '#e8e8e8'
+  }
+})