Cart.jsx 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import * as WebBrowser from 'expo-web-browser';
  2. import * as React from 'react';
  3. import { StyleSheet, View, Image } from 'react-native';
  4. import { Div, Text } from 'react-native-magnus';
  5. import { Flex } from '@ant-design/react-native';
  6. import { Modal, TouchableRipple, Badge } from 'react-native-paper';
  7. import { ScrollView } from 'react-native-gesture-handler';
  8. import { useCreation, useRequest } from '@umijs/hooks';
  9. import { useNavigation, useFocusEffect } from '@react-navigation/native';
  10. import useModel from 'flooks';
  11. import Detail from './model';
  12. import MapModel from '../Map/model';
  13. import Icon from '../../components/SvgIcon';
  14. import Button from '../../components/Button';
  15. import Plus from '../../components/Plus';
  16. import { navigate } from '../../navigation/RootNavigation';
  17. import { accAdd, accMul } from '../../Utils/NumberUtils';
  18. import { alert } from '../../Utils/TotastUtils';
  19. export default function Cart() {
  20. const {
  21. id,
  22. merchantInfo,
  23. addCart,
  24. getCart,
  25. setCartRequest,
  26. clearCart,
  27. setCartMap,
  28. changeNum,
  29. cartMoneyInfo,
  30. } = useModel(Detail, ['id', 'merchantInfo', 'cartMoneyInfo']);
  31. useFocusEffect(
  32. React.useCallback(() => {
  33. setshowCart(true);
  34. }, [])
  35. );
  36. const [showCart, setshowCart] = React.useState(false);
  37. const [cartList, setcartList] = React.useState([]);
  38. const { startingAmount } = merchantInfo;
  39. const [showList, setshowList] = React.useState(false);
  40. const cartRequest = useRequest(getCart, {
  41. refreshDeps: [id],
  42. onSuccess: (result) => {
  43. const value = result || [];
  44. setcartList(value);
  45. setCartRequest(cartRequest);
  46. if (value.length === 0) {
  47. setshowList(false);
  48. }
  49. },
  50. });
  51. const num = useCreation(() => {
  52. return cartList.reduce((total, item) => {
  53. return accAdd(total, item.num);
  54. }, 0);
  55. }, [cartList]);
  56. const cartMap = useCreation(() => {
  57. const map = new Map([]);
  58. cartList.forEach((item) => {
  59. map.set(item.goodsId, {
  60. num: map.has(item.goodsId)
  61. ? map.get(item.goodsId).num + item.num
  62. : item.num,
  63. specIds: map.has(item.goodsId)
  64. ? map.get(item.goodsId).specIds.add(item.id)
  65. : new Set([item.id]),
  66. });
  67. });
  68. return map;
  69. }, [cartList]);
  70. React.useEffect(() => {
  71. setCartMap(cartMap);
  72. }, [cartMap]);
  73. const {
  74. deliveryAmount,
  75. goodsTotal,
  76. fullReduction,
  77. packingPrice,
  78. reducedAmount,
  79. } = cartMoneyInfo;
  80. // 钱
  81. const price = useCreation(() => {
  82. if (goodsTotal) {
  83. return (goodsTotal - reducedAmount).toFixed(2);
  84. } else {
  85. return 0;
  86. }
  87. }, [goodsTotal, reducedAmount]);
  88. const total = useCreation(() => {
  89. if (goodsTotal) {
  90. return (goodsTotal + packingPrice - fullReduction).toFixed(2);
  91. } else {
  92. return 0;
  93. }
  94. }, [goodsTotal, fullReduction, packingPrice]);
  95. const canSubmit = useCreation(() => {
  96. if (price >= startingAmount && num > 0) {
  97. return true;
  98. } else {
  99. return false;
  100. }
  101. }, [num, startingAmount, price]);
  102. const goodsList = (list) => {
  103. return list.map((item) => {
  104. const { goods } = item;
  105. return (
  106. <Flex key={item.id} style={styles.item}>
  107. <Image
  108. style={styles.icon2}
  109. resizeMode="cover"
  110. source={{ uri: goods.img }}
  111. />
  112. <Flex.Item style={styles.goodsMain}>
  113. <Flex align="stretch">
  114. <Text>{goods.name}</Text>
  115. <Text type="error" style={{ marginLeft: 5 }}>
  116. ¥{item.goodsRealPrice || item.goodsPrice}
  117. </Text>
  118. </Flex>
  119. <Text size="c2" type="info">
  120. {item.specification}
  121. </Text>
  122. <Plus
  123. num={item.num}
  124. minus={() => {
  125. changeNum(new Set([item.id]), item.num - 1);
  126. }}
  127. loading={cartRequest.loading}
  128. plusEvent={() => {
  129. addCart(item.goodsId, item.specificationId.join(','), 1);
  130. }}
  131. />
  132. </Flex.Item>
  133. </Flex>
  134. );
  135. });
  136. };
  137. return (
  138. <>
  139. {showCart && (
  140. <>
  141. <View style={styles.main}>
  142. <Flex style={styles.bg}>
  143. <TouchableRipple
  144. style={styles.iconTouch}
  145. disabled={num === 0}
  146. onPress={() => setshowList(true)}
  147. >
  148. <Icon
  149. type={num > 0 ? 'primary' : ''}
  150. name="orderCart"
  151. width={49}
  152. height={53}
  153. badge={num}
  154. />
  155. </TouchableRipple>
  156. <Flex.Item style={styles.center}>
  157. <Div row alignItems="center" h={18}>
  158. <Text
  159. fontSize="xl"
  160. lineHeight={18}
  161. color={num === 0 ? 'gray300' : 'white'}
  162. >
  163. {num === 0 ? '未选购商品' : `¥${price}`}
  164. </Text>
  165. <Text
  166. fontSize="sm"
  167. color="gray300"
  168. lineHeight={18}
  169. textDecorLine="line-through"
  170. textDecorColor="gray300"
  171. ml={5}
  172. >
  173. ¥{total}
  174. </Text>
  175. </Div>
  176. <Text fontSize="xs" color="gray300">
  177. 另需配送费¥{deliveryAmount || 0}
  178. </Text>
  179. </Flex.Item>
  180. <Button
  181. size="large"
  182. type="primary"
  183. width={106}
  184. height={37}
  185. disabled={!canSubmit}
  186. radius={0}
  187. fontColor={!canSubmit ? '#B4B4B4' : '#fff'}
  188. loading={cartRequest.loading}
  189. onPress={() => {
  190. navigate('Submit');
  191. setshowCart(false);
  192. }}
  193. >
  194. {!canSubmit ? `¥${startingAmount || 0}起送` : '去结算'}
  195. </Button>
  196. </Flex>
  197. </View>
  198. <Modal
  199. animationType="slide-up"
  200. visible={showList}
  201. onDismiss={() => setshowList(false)}
  202. contentContainerStyle={styles.contentContainerStyle}
  203. >
  204. <Flex justify="between" style={styles.top}>
  205. <Text>已选商品</Text>
  206. <TouchableRipple
  207. disabled={num === 0}
  208. onPress={() => {
  209. alert('', '确认要清空购物车吗?', clearCart);
  210. }}
  211. >
  212. <Icon name="delete" type="info" width={20} height={20} />
  213. </TouchableRipple>
  214. </Flex>
  215. <ScrollView contentContainerStyle={styles.scroll}>
  216. {goodsList(cartList)}
  217. </ScrollView>
  218. </Modal>
  219. </>
  220. )}
  221. </>
  222. );
  223. }
  224. const styles = StyleSheet.create({
  225. main: {
  226. position: 'absolute',
  227. left: 0,
  228. right: 0,
  229. bottom: 0,
  230. height: 53,
  231. zIndex: 2,
  232. justifyContent: 'flex-end',
  233. },
  234. bg: {
  235. height: 37,
  236. backgroundColor: 'rgba(120, 120, 120, 1)',
  237. },
  238. iconTouch: {
  239. marginLeft: 15,
  240. alignSelf: 'flex-end',
  241. },
  242. center: {
  243. paddingHorizontal: 10,
  244. },
  245. contentContainerStyle: {
  246. backgroundColor: '#fff',
  247. position: 'absolute',
  248. bottom: 37,
  249. left: 0,
  250. right: 0,
  251. justifyContent: 'flex-start',
  252. paddingHorizontal: 20,
  253. paddingTop: 20,
  254. paddingBottom: 30,
  255. },
  256. icon2: {
  257. width: 40,
  258. height: 40,
  259. borderRadius: 3,
  260. },
  261. goodsMain: {
  262. marginLeft: 10,
  263. },
  264. top: {
  265. paddingBottom: 8,
  266. borderBottomWidth: 1,
  267. borderColor: '#E5E5E5',
  268. },
  269. item: {
  270. paddingTop: 10,
  271. overflow: 'hidden',
  272. },
  273. scroll: {
  274. flexGrow: 1,
  275. paddingBottom: 15,
  276. borderBottomWidth: 1,
  277. borderColor: '#e5e5e5',
  278. },
  279. });