|
|
@@ -0,0 +1,251 @@
|
|
|
+import * as WebBrowser from 'expo-web-browser';
|
|
|
+import * as React from 'react';
|
|
|
+import { StyleSheet, View, Image } from 'react-native';
|
|
|
+import { Flex } from '@ant-design/react-native';
|
|
|
+import { Modal, Portal, TouchableRipple, Badge } from 'react-native-paper';
|
|
|
+import { ScrollView } from 'react-native-gesture-handler';
|
|
|
+
|
|
|
+import { useCreation, useRequest, useMount } from '@umijs/hooks';
|
|
|
+
|
|
|
+import useModel from 'flooks';
|
|
|
+import Detail from './model';
|
|
|
+
|
|
|
+import Icon from '../../components/SvgIcon';
|
|
|
+import Text from '../../components/Text';
|
|
|
+import Button from '../../components/Button';
|
|
|
+import Plus from '../../components/Plus';
|
|
|
+
|
|
|
+import { accAdd, accMul } from '../../Utils/NumberUtils';
|
|
|
+import { alert } from '../../Utils/TotastUtils';
|
|
|
+
|
|
|
+export default function Cart() {
|
|
|
+ const {
|
|
|
+ id,
|
|
|
+ merchantInfo,
|
|
|
+ addCart,
|
|
|
+ getCart,
|
|
|
+ setCartRequest,
|
|
|
+ clearCart,
|
|
|
+ setCartMap,
|
|
|
+ } = useModel(Detail, ['id', 'merchantInfo']);
|
|
|
+
|
|
|
+ const [cartList, setcartList] = React.useState([]);
|
|
|
+
|
|
|
+ const { deliveryAmount, startingAmount } = merchantInfo;
|
|
|
+
|
|
|
+ const [showList, setshowList] = React.useState(false);
|
|
|
+
|
|
|
+ const cartRequest = useRequest(getCart, {
|
|
|
+ refreshDeps: [id],
|
|
|
+ onSuccess: (result) => {
|
|
|
+ const value = result || [];
|
|
|
+ setcartList(value);
|
|
|
+ setCartRequest(cartRequest);
|
|
|
+ if (value.length === 0) {
|
|
|
+ setshowList(false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ const num = useCreation(() => {
|
|
|
+ return cartList.reduce((total, item) => {
|
|
|
+ return accAdd(total, item.num);
|
|
|
+ }, 0);
|
|
|
+ }, [cartList]);
|
|
|
+
|
|
|
+ const cartMap = useCreation(() => {
|
|
|
+ const map = new Map([]);
|
|
|
+ cartList.forEach((item) => {
|
|
|
+ map.set(
|
|
|
+ item.goodsId,
|
|
|
+ map.has(item.goodsId) ? map.get(item.goodsId) + item.num : item.num
|
|
|
+ );
|
|
|
+ });
|
|
|
+ return map;
|
|
|
+ }, [cartList]);
|
|
|
+
|
|
|
+ React.useEffect(() => {
|
|
|
+ setCartMap(cartMap);
|
|
|
+ }, [cartMap]);
|
|
|
+
|
|
|
+ const price = useCreation(() => {
|
|
|
+ return cartList.reduce((total, item) => {
|
|
|
+ return accAdd(total, accMul(item.num, item.goodsRealPrice));
|
|
|
+ }, 0);
|
|
|
+ }, [num]);
|
|
|
+
|
|
|
+ const canSubmit = useCreation(() => {
|
|
|
+ if (price >= startingAmount && num > 0) {
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }, [num, startingAmount, price]);
|
|
|
+
|
|
|
+ const goodsList = (list) => {
|
|
|
+ return list.map((item) => {
|
|
|
+ const { goods } = item;
|
|
|
+ return (
|
|
|
+ <Flex key={item.id} style={styles.item}>
|
|
|
+ <Image
|
|
|
+ style={styles.icon2}
|
|
|
+ resizeMode="cover"
|
|
|
+ source={{ uri: goods.img }}
|
|
|
+ />
|
|
|
+ <Flex.Item style={styles.goodsMain}>
|
|
|
+ <Flex align="stretch">
|
|
|
+ <Text>{goods.name}</Text>
|
|
|
+ <Text type="error" style={{ marginLeft: 5 }}>
|
|
|
+ ¥{item.goodsRealPrice || item.goodsPrice}
|
|
|
+ </Text>
|
|
|
+ </Flex>
|
|
|
+ <Text size="c2" type="info">
|
|
|
+ {item.specification}
|
|
|
+ </Text>
|
|
|
+ <Plus
|
|
|
+ num={item.num}
|
|
|
+ minus={() => {}}
|
|
|
+ loading={cartRequest.loading}
|
|
|
+ plusEvent={() => {
|
|
|
+ addCart(item.goodsId, item.specificationId.join(','), 1);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Flex.Item>
|
|
|
+ </Flex>
|
|
|
+ );
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <Portal>
|
|
|
+ <View style={styles.main}>
|
|
|
+ <Flex style={styles.bg}>
|
|
|
+ <TouchableRipple
|
|
|
+ style={styles.iconTouch}
|
|
|
+ disabled={num === 0}
|
|
|
+ onPress={() => setshowList(true)}
|
|
|
+ >
|
|
|
+ <Icon
|
|
|
+ type={num > 0 ? 'primary' : ''}
|
|
|
+ name="orderCart"
|
|
|
+ width={49}
|
|
|
+ height={53}
|
|
|
+ badge={num}
|
|
|
+ />
|
|
|
+ </TouchableRipple>
|
|
|
+
|
|
|
+ <Flex.Item style={styles.center}>
|
|
|
+ <Text
|
|
|
+ size="s1"
|
|
|
+ style={{
|
|
|
+ lineHeight: 18,
|
|
|
+ marginVertical: 0,
|
|
|
+ }}
|
|
|
+ color={num === 0 ? '#B4B4B4' : '#fff'}
|
|
|
+ >
|
|
|
+ {num === 0 ? '未选购商品' : `¥${price}`}
|
|
|
+ </Text>
|
|
|
+ <Text size="c2" type="info">
|
|
|
+ 另需配送费¥{deliveryAmount || 0}
|
|
|
+ </Text>
|
|
|
+ </Flex.Item>
|
|
|
+
|
|
|
+ <Button
|
|
|
+ size="large"
|
|
|
+ type="primary"
|
|
|
+ width={106}
|
|
|
+ height={37}
|
|
|
+ disabled={!canSubmit}
|
|
|
+ radius={0}
|
|
|
+ fontColor={!canSubmit ? '#B4B4B4' : '#fff'}
|
|
|
+ onPress={() => {}}
|
|
|
+ loading={cartRequest.loading}
|
|
|
+ >
|
|
|
+ {!canSubmit ? `¥${startingAmount}起送` : '去结算'}
|
|
|
+ </Button>
|
|
|
+ </Flex>
|
|
|
+ </View>
|
|
|
+ <Modal
|
|
|
+ animationType="slide-up"
|
|
|
+ visible={showList}
|
|
|
+ onDismiss={() => setshowList(false)}
|
|
|
+ contentContainerStyle={styles.contentContainerStyle}
|
|
|
+ >
|
|
|
+ <Flex justify="between" style={styles.top}>
|
|
|
+ <Text>已选商品</Text>
|
|
|
+ <TouchableRipple
|
|
|
+ disabled={num === 0}
|
|
|
+ onPress={() => {
|
|
|
+ alert('', '确认要清空购物车吗?', clearCart);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Icon name="delete" type="info" width={20} height={20} />
|
|
|
+ </TouchableRipple>
|
|
|
+ </Flex>
|
|
|
+
|
|
|
+ <ScrollView contentContainerStyle={styles.scroll}>
|
|
|
+ {goodsList(cartList)}
|
|
|
+ </ScrollView>
|
|
|
+ </Modal>
|
|
|
+ </Portal>
|
|
|
+ </>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+const styles = StyleSheet.create({
|
|
|
+ main: {
|
|
|
+ position: 'absolute',
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ bottom: 0,
|
|
|
+ height: 53,
|
|
|
+ zIndex: 2,
|
|
|
+ justifyContent: 'flex-end',
|
|
|
+ },
|
|
|
+ bg: {
|
|
|
+ height: 37,
|
|
|
+ backgroundColor: 'rgba(120, 120, 120, 1)',
|
|
|
+ },
|
|
|
+ iconTouch: {
|
|
|
+ marginLeft: 15,
|
|
|
+ alignSelf: 'flex-end',
|
|
|
+ },
|
|
|
+ center: {
|
|
|
+ paddingHorizontal: 10,
|
|
|
+ },
|
|
|
+ contentContainerStyle: {
|
|
|
+ backgroundColor: '#fff',
|
|
|
+ position: 'absolute',
|
|
|
+ bottom: 37,
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ justifyContent: 'flex-start',
|
|
|
+ paddingHorizontal: 20,
|
|
|
+ paddingTop: 20,
|
|
|
+ paddingBottom: 30,
|
|
|
+ },
|
|
|
+ icon2: {
|
|
|
+ width: 40,
|
|
|
+ height: 40,
|
|
|
+ borderRadius: 3,
|
|
|
+ },
|
|
|
+ goodsMain: {
|
|
|
+ marginLeft: 10,
|
|
|
+ },
|
|
|
+ top: {
|
|
|
+ paddingBottom: 8,
|
|
|
+ borderBottomWidth: 1,
|
|
|
+ borderColor: '#E5E5E5',
|
|
|
+ },
|
|
|
+ item: {
|
|
|
+ paddingTop: 10,
|
|
|
+ overflow: 'hidden',
|
|
|
+ },
|
|
|
+ scroll: {
|
|
|
+ flexGrow: 1,
|
|
|
+ paddingBottom: 15,
|
|
|
+ borderBottomWidth: 1,
|
|
|
+ borderColor: '#e5e5e5',
|
|
|
+ },
|
|
|
+});
|