Browse Source

订单列表详情

main
Mac 1 month ago
parent
commit
62b22366f9
  1. 6
      app/components/AddressIcon.tsx
  2. 17
      app/components/BrightnessIcon.tsx
  3. 32
      app/components/InfoIcon.tsx
  4. 4
      app/components/MyFavoriteIcon.tsx
  5. 17
      app/components/OrderIcon.tsx
  6. 17
      app/components/PhoneIcon.tsx
  7. 24
      app/components/PowerIcon.tsx
  8. 13
      app/components/ShareIcon.tsx
  9. 32
      app/components/ShoppingBagIcon.tsx
  10. 24
      app/components/WatchAppIcon.tsx
  11. 5
      app/constants/productStatus.ts
  12. 31
      app/screens/HomeScreen.tsx
  13. 15
      app/screens/ProductCard.tsx
  14. 636
      app/screens/ProductDetailScreen.tsx
  15. 689
      app/screens/productStatus/OrderDatails.tsx
  16. 84
      app/screens/productStatus/Progress.tsx
  17. 77
      app/screens/productStatus/Status.tsx
  18. 76
      app/services/api/orders.ts
  19. 65
      app/store/orderList.ts

6
app/components/AddressIcon.tsx

@ -1,7 +1,7 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const AddressIcon = ({size = 18}) => (
const AddressIcon = ({size = 18, color = "#FB553C"}) => (
<Svg
viewBox="0 0 1024 1024"
width={size}
@ -9,11 +9,11 @@ const AddressIcon = ({size = 18}) => (
>
<Path
d="M318.8224 205.44c106.9312-106.5472 279.8848-106.5472 386.8416 0a270.848 270.848 0 0 1 79.8976 193.2288 270.848 270.848 0 0 1-73.8304 186.8288l-6.0672 6.2208-132.224 132.4032a86.6816 86.6816 0 0 1-118.7072 3.4816l-3.712-3.4816-132.1984-131.84a272.9216 272.9216 0 0 1-6.0672-380.6208l6.0672-6.2208zm43.4688 43.264a210.8928 210.8928 0 0 0-5.5808 293.5808l5.5808 5.76 131.456 132.0448a25.216 25.216 0 0 0 33.3312 2.2016l2.5088-2.2272 132.7872-132.0192A211.9168 211.9168 0 1 0 362.2912 248.7296z"
fill="#FB553C"
fill={color}
/>
<Path
d="M427.52 314.2912a119.4496 119.4496 0 1 1 169.0624 168.7808 119.4496 119.4496 0 0 1-169.0624-168.7808zm84.736 16.8192a67.584 67.584 0 1 0-0.384 135.1424 67.584 67.584 0 0 0 0.3584-135.168zM709.8624 667.52c-7.424 13.312-3.328 30.0544 9.3952 38.4256 22.016 12.3392 34.0992 25.5488 34.0992 35.1744 0 34.688-109.1584 76.4928-241.3568 76.4928-132.1984 0-241.3568-41.8048-241.3568-76.4928 0-9.6256 12.0576-22.8352 33.7152-34.9184 13.1072-8.6272 17.2032-25.3952 9.7792-38.6816a29.056 29.056 0 0 0-37.632-12.16c-44.672 25.0368-63.6416 54.9632-63.6416 85.76 0 81.408 136.064 134.4512 299.136 134.4512s299.136-53.0432 299.136-134.4512c0-30.7968-18.944-60.7232-63.2064-85.5296L747.52 655.36a29.056 29.056 0 0 0-37.6576 12.16z"
fill="#FB553C"
fill={color}
/>
</Svg>
);

17
app/components/BrightnessIcon.tsx

@ -0,0 +1,17 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const BrightnessIcon = ({size = 20,color = '#3d3d3d'}:{size:number,color:string}) => (
<Svg
viewBox="0 0 1025 1024"
width={size}
height={size}
>
<Path
d="M187.732004 156.526779c-13.330296-13.331627-34.948251-13.331627-48.263899 0-13.335622 13.326301-13.335622 34.937598 0 48.274552l48.263899 48.263899c13.331627 13.331627 34.933604 13.331627 48.269226 0 13.326301-13.326301 13.326301-34.932272 0-48.263899L187.732004 156.526779zM836.261339 156.526779l-48.269226 48.274552c-13.326301 13.331627-13.326301 34.937598 0 48.263899 13.315648 13.331627 34.932272 13.331627 48.269226 0l48.258573-48.263899c13.336953-13.336953 13.336953-34.942925 0-48.274552C871.194942 143.200478 849.592966 143.200478 836.261339 156.526779zM102.402665 426.66267L34.139994 426.66267C15.28903 426.66267 0.002666 441.945039 0.002666 460.789345c0 18.854958 15.28237 34.137328 34.137328 34.137328l68.262672 0c18.850963 0 34.132002-15.28237 34.132002-34.137328C136.534667 441.945039 121.253629 426.66267 102.402665 426.66267zM989.85468 426.66267l-68.264003 0c-18.849632 0-34.137328 15.28237-34.137328 34.126675 0 18.854958 15.286364 34.137328 34.137328 34.137328l68.264003 0c18.849632 0 34.142654-15.28237 34.142654-34.137328C1023.997334 441.945039 1008.704312 426.66267 989.85468 426.66267zM477.862672 34.132002l0 68.264003c0 18.854958 15.28237 34.13067 34.132002 34.13067 18.844306 0 34.137328-15.275712 34.137328-34.13067L546.132002 34.132002C546.132002 15.28237 530.838979 0 511.994674 0 493.145042 0 477.862672 15.28237 477.862672 34.132002zM273.066668 511.992008c0-131.955413 106.967267-238.928006 238.928006-238.928006 131.960739 0 238.933332 106.972593 238.933332 238.928006 0 131.960739-106.972593 238.937327-238.933332 238.937327C380.033935 750.929335 273.066668 643.951415 273.066668 511.992008zM204.803996 511.992008c0 169.675982 137.525348 307.211982 307.190677 307.211982S819.190677 681.667989 819.190677 511.992008c0-169.665329-137.530675-307.190677-307.196004-307.190677S204.803996 342.326679 204.803996 511.992008zM443.730671 989.862667c0 18.838979 15.28237 34.137328 34.132002 34.137328l68.269329 0c18.849632 0 34.132002-15.297017 34.132002-34.137328 0-18.860284-15.28237-34.132002-34.132002-34.132002l-68.269329 0C459.01304 955.730665 443.730671 971.002382 443.730671 989.862667zM375.467999 887.466662c0 18.834985 15.281038 34.132002 34.126675 34.132002l204.799999 0c18.849632 0 34.132002-15.297017 34.132002-34.132002 0-18.865611-15.28237-34.142654-34.132002-34.142654L409.594674 853.324008C390.743711 853.325339 375.467999 868.601051 375.467999 887.466662z"
fill={color}
/>
</Svg>
);
export default BrightnessIcon;

32
app/components/InfoIcon.tsx

@ -0,0 +1,32 @@
import React from 'react';
import Svg, { Path, Circle } from 'react-native-svg';
const InfoIcon = ({size = 20,color = "#3D3D3D"}:{size:number,color:string }) => (
<Svg
viewBox="0 0 1024 1024"
width={size}
height={size}
>
{/* Outer circle */}
<Path
d="M512.50142 958.397886c-119.320573 0-231.499491-46.465265-315.871087-130.837884C112.258737 743.188406 65.792449 631.010511 65.792449 511.688915c0-119.319549 46.466288-231.499491 130.837884-315.871087C281.002952 111.445208 393.180847 64.979944 512.50142 64.979944s231.499491 46.465265 315.871087 130.837884c84.372619 84.372619 130.837884 196.551538 130.837884 315.871087 0 119.321596-46.465265 231.499491-130.837884 315.871087C744.000911 911.932622 631.821993 958.397886 512.50142 958.397886zM512.50142 105.962334c-223.718271 0-405.726581 182.00831-405.726581 405.726581s182.00831 405.726581 405.726581 405.726581c223.718271 0 405.727605-182.00831 405.727605-405.726581S736.220714 105.962334 512.50142 105.962334z"
fill={color}
/>
{/* Info line (i) */}
<Path
d="M510.150886 775.953647c-18.107403 0-32.745798-14.678304-32.745798-32.785707L477.405087 452.191846c0-18.108426 14.638395-32.785707 32.745798-32.785707 18.107403 0 32.745798 14.678304 32.745798 32.785707l0 290.976094C542.896684 761.275343 528.258289 775.953647 510.150886 775.953647z"
fill={color}
/>
{/* Info dot (i) */}
<Circle
cx="511.357364"
cy="296.458969"
r="44.054"
fill={color}
/>
</Svg>
);
export default InfoIcon;

4
app/components/MyFavoriteIcon.tsx

@ -1,7 +1,7 @@
import React from'react';
import { Svg, Path } from'react-native-svg';
const MyFavoriteIcon = ({size}:{size:number}) => {
const MyFavoriteIcon = ({size,color}:{size:number,color:string}) => {
return (
<Svg
viewBox="0 0 1024 1024"
@ -10,7 +10,7 @@ const MyFavoriteIcon = ({size}:{size:number}) => {
>
<Path
d="M511.971859 903.595746 174.348352 607.095845C135.224286 570.081837 44.92877 472.01738 51.120796 360.498494c-0.056282-60.178591 24.431435-112.193245 79.346139-167.136601 55.759955-48.863894 114.222461-72.957639 175.158299-72.957639 91.703585 0 167.815053 53.196573 206.346625 86.35681 38.533618-33.160237 114.642017-86.35681 206.345602-86.35681 60.936861 0 119.401414 24.092721 173.750229 71.605851 56.323796 56.295144 80.815607 108.310821 80.815607 170.06428 6.133697 109.942995-84.162842 208.007451-123.286907 245.021459l-2.618641 2.448772L511.971859 903.595746zM305.626257 178.049139c-47.229674 0-91.64628 18.745946-135.808082 57.363476-42.417065 42.559305-61.107753 80.809467-61.107753 126.661771-5.03876 91.478458 79.289857 178.593538 105.242949 203.137537l2.391467 2.28095L511.971859 826.895877l297.008484-260.669858c26.966165-25.558096 111.292736-112.672152 106.310258-202.518437-0.054235-47.485501-18.742876-85.735663-62.570058-129.588427-42.75271-37.32407-87.171362-56.068993-134.403083-56.068993-90.661859 0-165.249625 67.581188-185.965435 88.324628l-20.380166 20.379143-20.377096-20.379143C470.878952 245.630327 396.288117 178.049139 305.626257 178.049139z"
fill="#707070"
fill={color}
/>
</Svg>
);

17
app/components/OrderIcon.tsx

@ -0,0 +1,17 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const OrderIcon = ({size = 20,color = "#3D3D3D"}:{size:number,color:string}) => (
<Svg
viewBox="0 0 1024 1024"
width={size}
height={size}
>
<Path
d="M725.504 768C725.290667 768 725.333333 170.709333 725.333333 170.709333L640 170.666667V128h85.376C748.928 128 768 146.986667 768 170.709333v597.248A42.666667 42.666667 0 0 1 725.504 810.666667H170.496C147.029333 810.666667 128 791.68 128 767.957333V170.709333C128 147.114667 147.157333 128 170.624 128H256v42.666667H170.624L170.666667 767.957333 725.504 768z m124.949333-469.333333H810.666667v-42.666667h42.666666c23.573333 0 42.666667 18.986667 42.666667 42.709333v597.248A42.666667 42.666667 0 0 1 853.504 938.666667H298.496A42.453333 42.453333 0 0 1 256 896v-42.666667h42.666667v42.666667l554.666666-0.042667 0.021334-228.416c-0.042667-168.597333-0.021333-368.853333-0.021334-368.853333L850.453333 298.666667zM298.666667 341.333333h298.666666v42.666667H298.666667v-42.666667z m0 128h213.333333v42.666667H298.666667v-42.666667z m0-341.376C298.666667 104.405333 317.802667 85.333333 341.461333 85.333333h213.077334C578.176 85.333333 597.333333 104.490667 597.333333 127.957333v42.752A42.688 42.688 0 0 1 554.538667 213.333333h-213.077334A42.752 42.752 0 0 1 298.666667 170.709333V127.957333z m42.666666 42.752L554.538667 170.666667 554.666667 127.957333 341.461333 128 341.333333 170.709333z"
fill={color}
/>
</Svg>
);
export default OrderIcon;

17
app/components/PhoneIcon.tsx

@ -0,0 +1,17 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const PhoneIcon = ({size = 20,color = '#3d3d3d'}:{size:number,color:string}) => (
<Svg
viewBox="0 0 1024 1024"
width={size}
height={size}
>
<Path
d="M737.17551 923.167347c-40.228571 0-86.204082-7.314286-134.269388-22.465306-114.938776-36.04898-228.310204-110.759184-318.693877-210.546939-135.836735-149.942857-201.142857-299.363265-188.081633-432.587755 3.657143-32.914286 14.628571-74.710204 64.261225-108.669388 38.138776-30.302041 81.502041-48.587755 115.461224-47.542857 35.526531 0.522449 48.065306 13.061224 84.636735 66.873469C416.391837 245.55102 420.571429 284.212245 418.481633 306.155102c-3.657143 36.571429-24.032653 52.244898-41.795919 66.35102-4.702041 3.657143-8.881633 6.791837-12.538775 10.44898-21.942857 28.212245-49.110204 66.873469 66.35102 185.991837 98.742857 94.563265 151.510204 106.057143 173.97551 104.489796 17.240816-1.044898 24.555102-10.44898 27.167347-13.583674l0.522449-0.522449c36.571429-51.722449 49.110204-64.261224 84.114286-69.485714 34.481633-5.22449 51.722449 5.22449 124.342857 51.2 65.828571 41.273469 96.130612 68.963265 88.816327 111.804082-2.089796 47.542857-38.138776 111.804082-79.412245 140.538775-28.212245 19.853061-66.873469 29.779592-112.84898 29.779592zM273.240816 142.628571c-18.808163 0-52.244898 9.926531-88.293877 39.183674l-1.044898 1.044898c-33.436735 22.465306-42.840816 48.065306-46.497959 78.889796-11.493878 120.685714 49.632653 259.134694 177.632653 400.195918 138.971429 153.077551 311.379592 219.428571 423.183673 219.428572 37.093878 0 67.395918-7.314286 87.771429-21.420409 33.436735-23.510204 60.604082-78.367347 61.648979-109.191836l0.522449-3.134694c2.089796-12.016327 4.179592-24.032653-70.008163-70.530612-71.053061-44.930612-78.367347-48.065306-95.608163-45.453062-17.763265 2.612245-21.420408 3.134694-56.42449 52.767347l-1.044898 1.044898c-17.763265 22.465306-40.75102 28.734694-56.946939 30.302041-52.767347 4.179592-122.253061-35.004082-206.367347-115.983673l-0.522449-0.522449c-132.179592-135.836735-104.489796-196.440816-68.963265-242.416327l2.612245-2.612245c5.746939-5.22449 10.971429-9.926531 16.718367-14.106122 16.195918-13.061224 24.032653-19.853061 26.122449-37.616327 2.089796-24.032653-15.15102-61.126531-50.677551-110.236735l-0.522449-0.522448c-32.914286-48.587755-36.04898-48.587755-51.2-48.587756-1.044898-0.522449-1.567347-0.522449-2.089796-0.522449z"
fill={color}
/>
</Svg>
);
export default PhoneIcon;

24
app/components/PowerIcon.tsx

@ -0,0 +1,24 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const PowerIcon = ({size, color}:{size: number, color: string}) => (
<Svg
viewBox="0 0 1024 1024"
width={size}
height={size}
>
{/* Outer circle */}
<Path
d="M815.5 208.6C734.5 127.7 626.8 83.1 512 83.1c-114.8 0-222.5 44.6-303.4 125.5C127.7 289.5 83.1 397.3 83.1 512c0 114.8 44.6 222.5 125.5 303.4 80.9 80.9 188.7 125.5 303.4 125.5 114.7 0 222.5-44.6 303.4-125.5C982.7 648.1 982.7 375.9 815.5 208.6zM776 776c-70.4 70.4-164.1 109.2-264 109.2-99.9 0-193.6-38.8-264-109.2-145.6-145.6-145.6-382.5 0-528 70.4-70.4 164.1-109.2 264-109.2 99.8 0 193.6 38.8 264 109.2 70.4 70.4 109.2 164.1 109.2 264S846.4 705.6 776 776z"
fill={color}
/>
{/* Power symbol */}
<Path
d="M667.7 506.9l0.4-0.1c9-2.9 15-11.2 15-20.6 0-11.9-9.6-21.5-21.5-21.5L531.7 464.7l0-39.8 133.5-132.2 0.2-0.4c0.9-1.8 1.8-5.1 2-8.5 0.4-5.7-1.5-11.3-5.4-15.8-3.6-4-9.6-6.4-16.2-6.4-5.7 0-11 1.8-14.5 5l-120.7 119L382.9 260.3l-0.1-0.1c-2.9-2.5-7.7-4-13.2-4-7 0-13.4 2.4-16.7 6.2-6.3 7.1-7.2 17.7-2.2 25.7l2.1 3.4 135.6 132.4 0 40.9-135.7 1-0.4 0-0.4 0.1c-9 2.9-15 11.2-15 20.5 0 9.4 6 17.6 15 20.5l3.5 1.1 132.8 0 0 66.8-135.7 1-0.4 0-0.3 0.1c-9 2.8-15 11.1-15 20.5 0 9.4 6 17.7 15 20.6l3.4 1.1 132.9 0 0.1 132.8 1.1 2.2c2.9 8.8 11.1 14.8 20.4 14.8 9.4 0 17.6-6 20.5-15l1.1-3.5L531.3 618.1l136-1 0.4-0.1c9-2.9 15-11.2 15-20.6 0-11.9-9.6-21.5-21.5-21.5L531.7 574.9 531.7 508 667.7 506.9z"
fill={color}
/>
</Svg>
);
export default PowerIcon;

13
app/components/ShareIcon.tsx

@ -0,0 +1,13 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const ShareIcon = ({ size = 24, fill = '#373737' }) => (
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
<Path
d="M14.8026 20.8883C14.2762 20.8883 13.8551 20.6784 13.434 20.3635C13.0129 19.9436 12.6971 19.4187 12.6971 18.7889V16.6894C10.381 16.6894 5.59104 18.3193 3.5908 21.0485C3.27496 21.5734 2.53803 21.8883 1.90637 21.9933H1.59055C0.537776 21.7833 -0.093887 20.8386 0.0113994 19.7889C0.537776 15.2751 3.11694 11.0209 5.85411 8.8165C7.85436 7.24191 10.1704 6.40212 12.6971 6.19218V4.19772C12.6971 3.25297 13.1182 2.41318 13.9604 2.09825C14.6973 1.88833 15.5395 1.99329 16.1712 2.62313L22.9089 9.44634C23.4353 9.86623 23.7511 10.496 23.8564 11.2309C23.9616 11.9657 23.7511 12.7005 23.2247 13.2253C23.1194 13.3303 23.0142 13.5402 22.8036 13.6452L16.2765 20.2585C15.8554 20.6784 15.329 20.8883 14.8026 20.8883ZM13.1182 14.59H14.8026V18.7889L21.435 11.9657L21.5403 11.8607C21.6456 11.7557 21.6456 11.5458 21.6456 11.4408C21.6456 11.2309 21.5403 11.1259 21.435 11.0209L21.3297 10.9159L14.6973 4.19772V8.18666L13.2234 8.29164C11.0127 8.29164 8.90712 9.02644 7.11743 10.3911C5.01189 12.0706 2.32748 16.4309 1.90637 20C4.53827 16.7458 10.4863 14.59 13.1182 14.59Z"
fill={fill}
/>
</Svg>
);
export default ShareIcon;

32
app/components/ShoppingBagIcon.tsx

@ -1,27 +1,21 @@
import React from 'react';
import { Svg, Path, G, ClipPath, Rect, Defs } from 'react-native-svg';
import { Svg, Path} from 'react-native-svg';
const ShoppingBagIcon = ({
size = 18,
size = 16,
color = "#FF5100",
strokeColor = "transparent",
strokeWidth = 0
}) => (
<Svg width={size} height={size} viewBox="0 0 18 18" fill="none">
<Defs>
<ClipPath id="clip0_168_1003">
<Rect width="18" height="18" fill="white" />
</ClipPath>
</Defs>
<G clipPath="url(#clip0_168_1003)">
<Path
d="M17.2688 2.98125C17.0438 1.35 15.9187 0 14.2312 0H3.76875C2.08125 0 1.06875 1.125 0.73125 2.98125L0 15.0188C0 16.65 1.35 18 2.98125 18H14.9625C16.5938 18 17.9438 16.65 17.9438 15.0188L17.2688 2.98125ZM13.6687 4.95C13.6687 7.48125 11.5875 9.61875 9 9.61875C6.4125 9.61875 4.33125 7.5375 4.33125 4.95C4.33125 4.5 4.725 4.05 5.23125 4.05C5.7375 4.05 6.13125 4.5 6.13125 4.95C6.13125 6.525 7.425 7.81875 9 7.81875C10.575 7.81875 11.8688 6.525 11.8688 4.95C11.8688 4.44375 12.2625 4.05 12.7688 4.05C13.275 4.05 13.6687 4.5 13.6687 4.95Z"
fill={color}
stroke={strokeColor}
strokeWidth={strokeWidth}
/>
</G>
</Svg>
<Svg
viewBox="0 0 1024 1024"
width={size}
height={size}
>
<Path
d="M969.728 877.568L915.968 361.984c-7.68-44.544-46.592-76.8-91.648-76.8h-136.192V221.184c0-98.304-79.872-178.688-178.688-178.688-97.792 0-178.176 80.384-178.176 178.688v64H195.584c-45.568 0-83.968 32.256-92.16 79.36L50.176 875.008c-4.608 27.136 2.56 54.784 20.48 76.288 17.92 20.992 43.52 33.28 71.168 33.28h735.744c27.648 0 53.76-12.288 71.168-33.28 17.92-21.504 25.6-49.152 20.992-73.728zM399.872 221.184c0-60.928 49.664-110.08 110.08-110.08 60.928 0 110.08 49.664 110.08 110.08v64h-220.16V221.184z m497.152 686.08c-2.56 3.584-9.216 8.704-18.944 8.704H141.824c-10.24 0-16.384-5.632-18.944-8.704-2.56-3.584-7.168-10.24-5.12-22.528L171.008 373.76c2.048-11.776 12.288-20.48 24.576-20.48H824.32c12.288 0 22.528 8.704 24.064 18.432l53.76 515.584c2.048 9.728-2.56 16.384-5.12 19.968zM413.696 476.672c0 26.624-21.504 48.128-48.128 48.128S317.44 503.296 317.44 476.672s21.504-48.128 48.128-48.128 48.128 21.504 48.128 48.128z m288.768 0c0 26.624-21.504 48.128-48.128 48.128s-48.128-21.504-48.128-48.128 21.504-48.128 48.128-48.128 48.128 21.504 48.128 48.128z"
fill={color} // Default black, customizable via props
/>
</Svg>
);
export default ShoppingBagIcon;

24
app/components/WatchAppIcon.tsx

@ -0,0 +1,24 @@
import React from 'react';
import Svg, { Path } from 'react-native-svg';
const WatchAppIcon = ({size = 20,color = '#6ED65B'}:{size:number,color?:string}) => (
<Svg
viewBox="0 0 1024 1024"
width={size}
height={size}
>
{/* Speech bubble tail */}
<Path
d="M700.8 592.7c-28.5-16-61.6-31.3-82.4-37.7-20.8-6.4-47.7 44.5-47.7 44.5s-25.2 6.1-80.6-38c-55.4-44.1-61-83.6-61-83.6s28.5-25.1 28.5-42.6-11.5-53.2-33.1-84.4c-21.6-31.2-114.7 0-87.8 111.7 10.2 42.3 33.1 87.4 112.4 155.8s154 77.5 200.1 69.2c46.2-8.3 80.1-78.9 51.6-94.9z"
fill={color}
/>
{/* Speech bubble body */}
<Path
d="M516.5 112.3c-218.5 0-395.6 174.9-395.6 390.6 0 77.3 22.8 149.4 62 210.1 5 7.7-76.6 194.1-70.6 198.7 3.5 2.7 204.5-71.5 208-69.5 57.8 32.7 124.8 51.4 196.2 51.4 218.5 0 395.6-174.9 395.6-390.6 0-215.8-177.1-390.7-395.6-390.7z m0 703.1c-63 0-121.8-18.2-171.1-49.6-7-4.5-124.6 45.4-126.9 43.6-2.8-2.1 44.2-119.8 41.6-123.4-37.8-51.5-60-114.8-60-183.2 0-172.6 141.7-312.5 316.5-312.5s316.5 139.9 316.5 312.5c-0.2 172.7-141.8 312.6-316.6 312.6z"
fill={color}
/>
</Svg>
);
export default WatchAppIcon;

5
app/constants/productStatus.ts

@ -7,12 +7,13 @@ interface ProductStatus {
status: number | null;
}
export const productStatus: ProductStatus[] = [
{ icon: DocumentApprovedIcon, text: '待报价', status: 5 },
{ icon: DocumentApprovedIcon, text: '待报价', status: 8 },
{ icon: PdfDocumentIcon, text: '待付款', status: 0 },
{ icon: DocumentClockIcon, text: '付运费', status: 6 },
{ icon: DocumentClockIcon, text: '待发货', status: 1 },
{ icon: DocumentApprovedIcon, text: '运输中', status: 7 },
{ icon: DocumentApprovedIcon, text: '代收货', status: 2 },
{ icon: PdfDocumentIcon, text: '已完成', status: 3 },
{ icon: DocumentClockIcon, text: '已取消', status: 4 }
{ icon: DocumentClockIcon, text: '已取消', status: 4 },
{ icon: DocumentClockIcon, text: '已退款', status: 5 }
]

31
app/screens/HomeScreen.tsx

@ -24,7 +24,6 @@ import Ionicons from "@expo/vector-icons/Ionicons";
import { useNavigation } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useTranslation } from "react-i18next";
import Swiper from "react-native-swiper";
import widthUtils from "../utils/widthUtils";
import DownArrowIcon from "../components/DownArrowIcon";
import { LinearGradient } from "expo-linear-gradient";
@ -91,13 +90,15 @@ export const HomeScreen = () => {
}
};
const handleProductPress = (item: Product) => {
navigation.navigate("ProductDetail", {
offer_id: item.offer_id,
searchKeyword: searchParams.keyword,
price: item.min_price,
const handleProductPress = useCallback((item: Product) => {
InteractionManager.runAfterInteractions(() => {
navigation.navigate("ProductDetail", {
offer_id: item.offer_id,
searchKeyword: searchParams.keyword,
price: item.min_price,
});
});
};
}, [navigation]);
const onRefresh = useCallback(async () => {
setRefreshing(true);
@ -164,6 +165,18 @@ export const HomeScreen = () => {
});
}, [navigation]);
const navigateToShippingDetails = useCallback(() => {
InteractionManager.runAfterInteractions(() => {
navigation.navigate("ShippingDetailsSection");
});
}, [navigation]);
const navigateToInquiry = useCallback(() => {
InteractionManager.runAfterInteractions(() => {
navigation.navigate("InquiryScreen");
});
}, [navigation]);
const scrollToCategory = (category: string) => {
const categoryIndex = categories.findIndex((c) => c === category);
if (categoryIndex !== -1 && horizontalScrollRef.current) {
@ -297,7 +310,7 @@ export const HomeScreen = () => {
<View style={styles.leftContainer}>
<TouchableOpacity
style={styles.leftTopItem}
onPress={() => navigation.navigate("ShippingDetailsSection")}
onPress={navigateToShippingDetails}
>
<Image
source={require("../../assets/img/a_计算运费.png")}
@ -315,7 +328,7 @@ export const HomeScreen = () => {
{/* 右侧区域 - 一个 */}
<TouchableOpacity
style={styles.rightContainer}
onPress={() => navigation.navigate("InquiryScreen")}
onPress={navigateToInquiry}
>
<Image
source={require("../../assets/img/a_VIP.png")}

15
app/screens/ProductCard.tsx

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { useEffect, useCallback } from "react";
import {
View,
Text,
@ -6,7 +6,8 @@ import {
StyleSheet,
TouchableOpacity,
ScrollView,
Modal
Modal,
InteractionManager
} from "react-native";
import widthUtils from "../utils/widthUtils";
import fontSize from "../utils/fontsizeUtils";
@ -345,6 +346,14 @@ const ProductCard: React.FC<ProductCardProps> = ({
// 关闭确认对话框
setDeleteModalVisible(false);
};
const handleNavigateToCart = useCallback(() => {
setDeleteModalVisible(false);
InteractionManager.runAfterInteractions(() => {
navigation.navigate("MainTabs", { screen: "Cart" });
});
}, [navigation]);
return (
<View style={styles.container}>
<View style={styles.productCardContainer3}>
@ -901,7 +910,7 @@ const ProductCard: React.FC<ProductCardProps> = ({
<TouchableOpacity style={styles.cancelButton1} onPress={cancelDelete}>
<Text style={styles.cancelText}>Non</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.confirmButton} onPress={() => navigation.navigate("MainTabs", { screen: "Cart" })}>
<TouchableOpacity style={styles.confirmButton} onPress={handleNavigateToCart}>
<Text style={styles.confirmText}>Voir le panier</Text>
</TouchableOpacity>
</View>

636
app/screens/ProductDetailScreen.tsx

File diff suppressed because it is too large Load Diff

689
app/screens/productStatus/OrderDatails.tsx

@ -1,13 +1,690 @@
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import React, { useEffect, useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ActivityIndicator,
ScrollView,
Image,
Alert,
Linking,
} from "react-native";
import BackIcon from "../../components/BackIcon";
import MassageIcon from "../../components/MassageIcon";
import fontSize from "../../utils/fontsizeUtils";
import { useNavigation } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useRoute, RouteProp } from "@react-navigation/native";
import { ordersApi, OrderDetailsType } from "../../services/api/orders";
import OrderIcon from "../../components/OrderIcon";
import InfoIcon from "../../components/InfoIcon";
import Progress from "./Progress";
import AddressIcon from "../../components/AddressIcon";
import EditIcon from "../../components/ColorfulEditIcon";
import BrightnessIcon from "../../components/BrightnessIcon";
import PhoneIcon from "../../components/PhoneIcon";
import WatchAppIcon from "../../components/watchAppIcon";
import ShoppingBagIcon from "../../components/ShoppingBagIcon";
import PowerIcon from "../../components/PowerIcon";
import CardIcon from "../../components/ShoppingCartIcon";
import { useOrderListStore } from "../../store/orderList";
export const OrderDetails = () => {
const navigation = useNavigation<NativeStackNavigationProp<any>>();
const route = useRoute<
RouteProp<
{
OrderDetails: {
orderId: string;
};
},
"OrderDetails"
>
>();
const [orderDetails, setOrderDetails] = useState<OrderDetailsType>();
const [isLoading, setIsLoading] = useState(true);
const { deleteOrder, changeOrder,updateOrderShippingInfo } = useOrderListStore();
const getOrderDetails = async () => {
try {
setIsLoading(true);
const response = await ordersApi.getOrderDetails(route.params.orderId);
setOrderDetails(response);
} catch (error) {
console.error("Error fetching order details:", error);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
getOrderDetails();
}, []);
//拨打电话
const callPhone = async (phoneNumber: string) => {
const url = `tel:${phoneNumber}`;
try {
await Linking.openURL(url); // 直接尝试打开拨号界面
} catch (error) {
Alert.alert("错误", "无法打开拨号界面");
console.error("拨号失败:", error);
}
};
return (
<View>
<Text>OrderDetails</Text>
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<BackIcon />
</TouchableOpacity>
<Text style={styles.title}></Text>
<MassageIcon size={22} />
</View>
{isLoading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#f77f3a" />
</View>
) : orderDetails ? (
<View style={styles.container}>
<ScrollView
showsVerticalScrollIndicator={false}
style={{ flex: 1 }}
contentContainerStyle={{ paddingBottom: 70 }}
>
<View style={styles.orderStatus}>
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<OrderIcon size={20} color="#3D3D3D" />
<Text style={styles.orderStatusTitleText}></Text>
</View>
<View style={styles.orderStatusContentPreview}>
<Progress
statuses={orderDetails.order_status}
labels={["待付款", "待发货", "运送中", "待收货", "已完成"]}
/>
</View>
</View>
</View>
{/* 订单信息 */}
<View style={styles.orderStatus}>
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<InfoIcon size={20} color="#3D3D3D" />
<Text style={styles.orderStatusTitleText}></Text>
</View>
<View style={styles.orderStatusContentPreview}>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>Order ID</Text>
<Text style={styles.orderIdText1}>
{orderDetails.order_id}
</Text>
</View>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>Order Date</Text>
<Text style={styles.orderIdText1}>
{orderDetails.create_time}
</Text>
</View>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>Shipping Method</Text>
<Text style={styles.orderIdText1}>
{orderDetails.shipping_fee}
</Text>
</View>
</View>
</View>
</View>
{/* 配送信息 */}
<View style={styles.orderStatus}>
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<AddressIcon size={22} color={"#3D3D3D"} />
<Text style={styles.orderStatusTitleText}></Text>
</View>
<View style={styles.orderStatusContentPreview}>
<View style={styles.orderStatusContentPreviewInformation}>
<View style={styles.warehouse}>
<View style={styles.recipientTitle}>
<Text
style={
styles.orderStatusContentPreviewInformationText
}
>
Warehouse
</Text>
</View>
<View style={styles.recipientTitle}>
<EditIcon size={22} />
</View>
<View style={styles.recipientTitle}>
<Text>{orderDetails.receiver_address}</Text>
</View>
<View style={styles.recipientTitle}>
<View style={styles.warehousePhone}>
<View style={styles.warehousePhoneTextContainer}>
<BrightnessIcon size={16} color="#3D3D3D" />
</View>
<View style={styles.warehousePhoneTextContainer}>
<Text style={styles.warehousePhoneText}>
</Text>
</View>
</View>
</View>
</View>
<View style={styles.recipient}>
<View style={styles.recipientTitle}>
<Text
style={
styles.orderStatusContentPreviewInformationText
}
>
Recipient
</Text>
</View>
<View style={styles.recipientTitle}>
<EditIcon size={22} />
</View>
{/* 姓名 */}
<View style={styles.recipientTitle}>
<Text style={styles.recipientName}>
{orderDetails.receiver_name}
</Text>
</View>
{/* 电话 */}
<View style={styles.recipientTitle}>
<View style={styles.recipientPhoneContainer}>
<PhoneIcon size={16} color="#3D3D3D" />
<Text style={styles.recipientPhone}>
{orderDetails.receiver_phone}
</Text>
</View>
</View>
{/* watchApp */}
<View style={styles.recipientTitle}>
<View style={styles.recipientPhoneContainer}>
<WatchAppIcon size={16} />
<Text style={styles.recipientPhone}>WhatsApp:</Text>
<Text style={styles.recipientPhone}>
{orderDetails.receiver_phone}
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
</View>
{/* 商品信息 */}
<View style={styles.orderStatus}>
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<ShoppingBagIcon size={16} color="#3D3D3D" />
<Text style={styles.orderStatusTitleText}>
({orderDetails.items.length})
</Text>
</View>
<View style={styles.orderStatusContentPreview}>
{orderDetails.items.map((item, index) => (
<View style={styles.productItem} key={index}>
<View style={styles.productItemImage}>
<Image
source={{ uri: item.product_image }}
style={{ width: "100%", height: "100%" }}
/>
</View>
<View style={styles.productItemInfo}>
<View style={styles.productItemInfoName}>
<Text style={styles.productItemInfoNameText}>
{item.product_name}
</Text>
</View>
<View style={styles.productItemInfoSku}>
{item.sku_attributes.map((sku, index) => (
<Text
key={index}
style={styles.productItemInfoSkuText}
>
{sku.attribute_name}:{sku.attribute_value}
</Text>
))}
{/* <text>{item.product_name}</text> */}
</View>
<View style={styles.productItemInfoPrice}>
<Text
style={{
color: "#f77f3a",
fontSize: fontSize(16),
fontWeight: "600",
}}
>
{item.total_price}
</Text>
</View>
</View>
<View style={styles.productItemNum}>
<Text style={styles.productItemNumText}>
x{item.quantity}
</Text>
</View>
</View>
))}
</View>
<View style={styles.dottedLine}></View>
<View style={styles.orderStatusContentPreview}>
<TouchableOpacity style={styles.addCard}>
<View style={styles.addCardBox}>
<CardIcon size={16} color="#0098ef" />
<Text style={styles.addCardText}>Add All to Card</Text>
</View>
</TouchableOpacity>
</View>
</View>
</View>
{/* 价格信息 */}
<View style={styles.orderStatus}>
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<PowerIcon size={20} color="#3D3D3D" />
<Text style={styles.orderStatusTitleText}></Text>
</View>
<View style={styles.orderStatusContentPreview}>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>Subtotal</Text>
<Text style={styles.orderIdText1}>
{orderDetails.total_amount}
</Text>
</View>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>
Platform Shipping Fee
</Text>
<Text style={styles.orderIdText1}>
{orderDetails.shipping_fee}
</Text>
</View>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>
International Shipping Fee
</Text>
<Text style={styles.orderIdText1}>
{orderDetails.shipping_fee}
</Text>
</View>
<View style={styles.dottedLine}></View>
<View style={styles.orderId}>
<Text style={styles.TotalText}>Total</Text>
<Text style={styles.TotalPrice}>
{orderDetails.total_amount}
</Text>
</View>
<View>
<Text style={styles.orderRemakeText}>
+ ${orderDetails.shipping_fee} estimated international fee
(COD)
</Text>
</View>
</View>
</View>
</View>
</ScrollView>
{/* 代付款 */}
{orderDetails.order_status === 0 && (
<View style={styles.bottomButtons}>
<TouchableOpacity
style={styles.bottomButton1}
onPress={() => {
deleteOrder(route.params.orderId);
}}
>
<Text style={styles.bottomButtonText1}></Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.bottomButton}
onPress={() => {
navigation.navigate("Pay", {
order_id: route.params.orderId,
});
}}
>
<Text style={styles.bottomButtonText}></Text>
</TouchableOpacity>
</View>
)}
{/* 待发货 */}
{orderDetails.order_status === 1 && (
<View style={styles.bottomButtons}>
<TouchableOpacity
style={styles.bottomButton1}
onPress={() => {
callPhone("15903995548");
}}
>
<Text style={styles.bottomButtonText1}></Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.bottomButton}
onPress={() => {
changeOrder(route.params.orderId, 2);
navigation.goBack();
}}
>
<Text style={styles.bottomButtonText}></Text>
</TouchableOpacity>
</View>
)}
{/* 代收货 */}
{orderDetails.order_status === 2 && (
<View style={styles.bottomButtons}>
<TouchableOpacity style={styles.bottomButton1} onPress={() => {}}>
<Text style={styles.bottomButtonText1}></Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.bottomButton}
onPress={() => {
updateOrderShippingInfo(route.params.orderId,{
shipping_status: 0,
shipping_info: {
shipping_company: "string",
shipping_no: "string",
shipping_info: {}
}
});
navigation.goBack();
}}
>
<Text style={styles.bottomButtonText}></Text>
</TouchableOpacity>
</View>
)}
{/* 已完成 */}
{orderDetails.order_status === 3 && (
<View style={styles.bottomButtons}>
<TouchableOpacity
style={styles.bottomButton1}
onPress={() => {
deleteOrder(route.params.orderId);
navigation.goBack();
}}
>
<Text style={styles.bottomButtonText1}>Cancel Order</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bottomButton}>
<Text style={styles.bottomButtonText}>Pay Now</Text>
</TouchableOpacity>
</View>
)}
{/* 已取消 */}
{orderDetails.order_status === 4 && (
<View style={styles.bottomButtons}>
<TouchableOpacity style={styles.bottomButton1} onPress={() => {}}>
<Text style={styles.bottomButtonText1}></Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bottomButton}>
<Text style={styles.bottomButtonText}></Text>
</TouchableOpacity>
</View>
)}
</View>
) : (
<Text></Text>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f8f9fa",
},
header: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
padding: 16,
backgroundColor: "#fff",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 3,
elevation: 3,
},
title: {
fontSize: fontSize(16),
fontWeight: "600",
},
orderStatus: {
paddingInline: 16,
marginTop: 10,
},
orderStatusContent: {
backgroundColor: "#fff",
borderRadius: 16,
},
orderStatusTitle: {
flexDirection: "row",
alignItems: "center",
borderBottomWidth: 1,
borderColor: "#f5f5f5",
padding: 10,
},
orderStatusTitleText: {
fontSize: fontSize(16),
fontWeight: "600",
marginLeft: 10,
},
orderStatusContentPreview: {
padding: 10,
justifyContent: "center",
},
productItem: {
flexDirection: "row",
width: "100%",
borderBottomWidth: 1,
borderColor: "#f5f5f5",
padding: 10,
},
productItemImage: {
width: "15%",
height: 50,
borderRadius: 10,
},
productItemInfo: {
width: "75%",
justifyContent: "space-between",
paddingLeft: 10,
},
productItemNum: {
width: "10%",
alignItems: "center",
justifyContent: "flex-end",
},
productItemNumText: {
fontSize: fontSize(16),
color: "#999",
},
productItemInfoName: {
width: "100%",
paddingVertical: 5,
},
productItemInfoNameText: {
fontSize: fontSize(13),
fontWeight: "600",
},
productItemInfoSkuText: {
fontSize: fontSize(13),
color: "#999",
},
productItemInfoSku: {
width: "100%",
paddingVertical: 5,
},
productItemInfoPrice: {
width: "100%",
paddingVertical: 5,
},
orderStatusContentPreviewInformation: {
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
orderId: {
flexDirection: "row",
justifyContent: "space-between",
paddingVertical: 10,
width: "100%",
},
orderIdText: {
color: "#999",
width: "50%",
},
orderIdText1: {
width: "50%",
textAlign: "right",
},
TotalText: {
color: "#f77f3a",
fontSize: fontSize(18),
fontWeight: "600",
width: "50%",
},
TotalPrice: {
color: "#f77f3a",
fontSize: fontSize(18),
fontWeight: "600",
width: "50%",
textAlign: "right",
},
warehouse: {
width: "50%",
},
recipientTitle: {
paddingVertical: 5,
},
recipientPhoneContainer: {
flexDirection: "row",
alignItems: "center",
},
recipient: {
width: "50%",
},
orderStatusContentPreviewInformationText: {
fontSize: fontSize(16),
fontWeight: "600",
},
warehousePhone: {
padding: 5,
backgroundColor: "#f9f9f9",
borderRadius: 10,
width: "90%",
flexDirection: "row",
alignItems: "center",
},
warehousePhoneText: {
fontSize: fontSize(14),
fontWeight: "400",
color: "#3D3D3D",
},
warehousePhoneTextContainer: {
paddingRight: 5,
},
recipientName: {
fontSize: fontSize(16),
fontWeight: "600",
},
recipientPhone: {
fontSize: fontSize(14),
fontWeight: "400",
color: "#3D3D3D",
},
dottedLine: {
width: "100%",
borderBottomWidth: 2,
borderColor: "#f5f5f5",
borderStyle: "dashed",
},
orderRemakeText: {
fontSize: fontSize(14),
fontWeight: "400",
color: "#999",
},
addCard: {
width: "100%",
justifyContent: "center",
alignItems: "center",
},
addCardBox: {
padding: 10,
borderWidth: 1,
borderColor: "#0098ef",
borderRadius: 10,
backgroundColor: "#e2f2fd",
opacity: 0.5,
flexDirection: "row",
alignItems: "center",
},
addCardText: {
fontSize: fontSize(16),
fontWeight: "600",
color: "#0098ef",
marginLeft: 5,
},
bottomButtons: {
position: "absolute",
bottom: 0,
width: "100%",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
padding: 10,
backgroundColor: "#fff",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: -4,
},
shadowOpacity: 0.1,
shadowRadius: 3,
elevation: 3,
},
bottomButton1: {
padding: 10,
marginHorizontal: 10,
alignItems: "center",
backgroundColor: "#f0f0f0",
borderRadius: 5,
flex: 1,
},
bottomButton: {
padding: 10,
marginHorizontal: 10,
alignItems: "center",
backgroundColor: "#fe7f42",
borderRadius: 5,
flex: 1,
},
bottomButtonText: {
fontSize: fontSize(18),
fontWeight: "600",
color: "#fff",
},
bottomButtonText1: {
fontSize: fontSize(18),
fontWeight: "600",
color: "#999",
},
});

84
app/screens/productStatus/Progress.tsx

@ -0,0 +1,84 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { Text } from 'react-native-paper';
interface ProgressProps {
statuses: number;
labels?: string[];
}
const Progress: React.FC<ProgressProps> = ({ statuses , labels = [] }) => {
return (
<View style={styles.mainContainer}>
<View style={styles.progressContainer}>
{labels.map((_, index) => (
<React.Fragment key={index}>
<View
style={[
styles.node,
index < statuses + 1 && styles.completedNode
]}
/>
{index < labels.length - 1 && (
<View
style={[
styles.line,
index < statuses&& styles.completedLine
]}
/>
)}
</React.Fragment>
))}
</View>
<View style={styles.labelsContainer}>
{labels.map((label, index) => (
<Text key={index} style={styles.label}>{label}</Text>
))}
</View>
</View>
);
};
const styles = StyleSheet.create({
mainContainer: {
alignItems: 'center',
},
progressContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 10,
},
node: {
width: 20,
height: 20,
borderRadius: 10,
backgroundColor: '#E0E0E0',
},
completedNode: {
backgroundColor: '#4CAF50',
},
line: {
height: 2,
width: 40,
backgroundColor: '#E0E0E0',
},
completedLine: {
backgroundColor: '#4CAF50',
},
labelsContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
paddingHorizontal: 10,
},
label: {
fontSize: 12,
color: '#666',
textAlign: 'center',
width: 60,
},
});
export default Progress;

77
app/screens/productStatus/Status.tsx

@ -21,6 +21,7 @@ import {
} from "../../services/api/orders";
import { useNavigation } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useOrderListStore } from "../../store/orderList";
// import ImageView from "react-native-image-viewing";
type StatusScreenRouteProp = RouteProp<
@ -43,33 +44,25 @@ export function Status() {
return initialList;
});
const [status, setStatus] = useState<number | null>(null);
const [orderList, setOrderList] = useState<PaginatedOrderResponse>();
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
const [loading, setLoading] = useState(true);
const [imageViewerVisible, setImageViewerVisible] = useState(false);
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const [images, setImages] = useState<string[]>([]);
const statusScrollViewRef = useRef<ScrollView>(null);
const statusItemRef = useRef<React.ElementRef<typeof TouchableOpacity>>(null);
const { orders, getAllOrders } = useOrderListStore();
const getAllOrders = async () => {
const getAllOrdersList = async () => {
setLoading(true);
try {
const data = {
page: page,
page_size: pageSize,
status: route.params.status,
};
const response = await ordersApi.getAllOrders(data);
setOrderList((prev) => ({
...response,
items:
page === 1
? response.items
: [...(prev?.items || []), ...response.items],
}));
setTotal(response.total);
await getAllOrders(data, page);
} finally {
setLoading(false);
}
@ -93,7 +86,7 @@ export function Status() {
setStatus(route.params.status);
scrollToStatus();
setPage(1);
getAllOrders();
getAllOrdersList();
}, []);
const getStatus = (status: number) => {
@ -128,22 +121,19 @@ export function Status() {
if (status) {
data.status = status;
}
if (status === 0) {
data.status = 0;
}
try {
const response = await ordersApi.getAllOrders(data);
setOrderList((prev) => ({
...response,
items:
page === 1
? response.items
: [...(prev?.items || []), ...response.items],
}));
await getAllOrders(data, page);
// 滚动状态列表到选中项
} finally {
setLoading(false);
}
};
const handleOrderDetailsPress = (orderId: number) => {
const handleOrderDetailsPress = (orderId: string) => {
navigation.navigate("OrderDetails", { orderId });
};
@ -203,18 +193,29 @@ export function Status() {
onMomentumScrollEnd={(event) => {
const { contentOffset, contentSize, layoutMeasurement } =
event.nativeEvent;
console.log('Scroll values:', {
contentOffsetY: contentOffset.y,
layoutHeight: layoutMeasurement.height,
contentHeight: contentSize.height,
sum: contentOffset.y + layoutMeasurement.height
});
const isAtBottom =
contentOffset.y + layoutMeasurement.height >=
contentSize.height;
contentSize.height - 20;
if (isAtBottom) {
setLoading(true);
setPage(page + 1);
getAllOrders();
const data: PaginatedOrderRequest = {
page: page,
page_size: pageSize,
status:status,
};
getAllOrders(data,page);
}
}}
>
{orderList?.items.map((item, index) => (
{orders?.items.map((item, index) => (
<View style={styles.orderItem} key={index}>
<View style={styles.orderStatus}>
<Text style={styles.orderStatusOrderText}>
@ -313,7 +314,7 @@ const styles = StyleSheet.create({
width: "100%",
},
statusItem: {
width: widthUtils(100,100).width,
width: widthUtils(100, 100).width,
padding: 16,
backgroundColor: "white",
},
@ -354,9 +355,12 @@ const styles = StyleSheet.create({
orderStatusOrderText: {
fontSize: fontSize(16),
fontWeight: "600",
width: "70%",
},
orderStatusText: {
color: "#f77f3a",
width: "30%",
textAlign: "right",
},
orderProductList: {
width: "100%",
@ -370,8 +374,8 @@ const styles = StyleSheet.create({
borderColor: "#f5f5f5",
},
orderProductItemImage: {
width: widthUtils(30,30).width,
height: widthUtils(30,30).height,
width: widthUtils(30, 30).width,
height: widthUtils(30, 30).height,
marginRight: 10,
},
orderProductItemInfo: {
@ -391,19 +395,25 @@ const styles = StyleSheet.create({
justifyContent: "space-between",
},
orderProductView: {
padding: 5,
width: "50%",
borderRadius: 8,
borderWidth: 1,
borderColor: "#f77f3a",
alignItems: "flex-end",
},
orderProductViewText: {
color: "#f77f3a",
fontSize: fontSize(14),
borderWidth: 1,
borderColor: "#f77f3a",
width: "50%",
borderRadius: 8,
padding: 5,
textAlign: "center",
},
orderProductPriceText: {
fontSize: fontSize(16),
fontWeight: "600",
color: "#f77f3a",
textAlign: "right",
},
orderProductTotalText: {
fontSize: fontSize(16),
@ -411,6 +421,7 @@ const styles = StyleSheet.create({
},
orderProductPriceItem: {
flexDirection: "row",
width: "50%",
},
loadingContainer: {
flex: 1,

76
app/services/api/orders.ts

@ -257,7 +257,7 @@ interface Address {
pay_status: number;
order_status: number;
shipping_status: number;
order_id: number;
order_id: string;
order_no: string;
items: OrderItem[];
create_time: string; // or Date
@ -280,6 +280,64 @@ interface Address {
page_size: number;
}
interface SkuAttributesDetails {
attribute_name: string;
attribute_value: string;
}
interface OrderItemDetails {
offer_id: number;
cart_item_id: number | null;
sku_id: number;
product_name: string;
product_name_en: string;
product_name_ar: string;
product_name_fr: string;
product_image: string;
sku_attributes: SkuAttributesDetails[];
quantity: number;
unit_price: number;
total_price: number;
order_item_id: string;
order_id: string;
create_time: string; // or Date
update_time: string; // or Date
}
export interface OrderDetailsType {
user_id: number;
total_amount: number;
actual_amount: number;
discount_amount: number;
shipping_fee: number;
address_id: number;
receiver_name: string;
receiver_phone: string;
receiver_address: string;
buyer_message: string;
pay_status: number;
order_status: number;
shipping_status: number;
order_id: string;
order_no: string;
items: OrderItemDetails[];
create_time: string; // or Date
transport_type: number;
payment_method: string;
pay_time: string | null; // or Date | null
shipping_time: string | null; // or Date | null
complete_time: string | null; // or Date | null
update_time: string; // or Date
}
export interface UpdateOrderShippingInfo {
"shipping_status": number,
"shipping_info": {
"shipping_company": string,
"shipping_no": string,
"shipping_info": {}
}
}
export const ordersApi = {
getOrders: (data:OrderPreviewData) => apiService.post<OrderData>("/api/orders/preview",data),
@ -304,8 +362,20 @@ interface Address {
apiService.get<PaginatedOrderResponse>(`/api/orders`,data),
// 获取订单指定信息
getOrderDetails: (order_id:number) =>
apiService.get<Order>(`/api/orders/${order_id}`),
getOrderDetails: (order_id:string) =>
apiService.get<OrderDetailsType>(`/api/orders/${order_id}`),
// 删除订单
deleteOrder: (order_id:string) =>
apiService.delete<void>(`/api/orders/${order_id}`),
// 修改订单
changeOrder: (order_id:string,status:number) =>
apiService.patch<void>(`/api/orders/${order_id}/status?status=${status}`),
// 修改物流信息
updateOrderShippingInfo: (order_id:string,data:UpdateOrderShippingInfo) =>
apiService.patch<void>(`/api/orders/${order_id}/shipping`,data),
};

65
app/store/orderList.ts

@ -0,0 +1,65 @@
import { create } from 'zustand';
import { ordersApi, PaginatedOrderResponse, PaginatedOrderRequest,UpdateOrderShippingInfo} from '../services/api/orders';
interface OrderListState {
orders: PaginatedOrderResponse,
getAllOrders: (data: PaginatedOrderRequest,page:number) => Promise<void>,
deleteOrder: (orderId: string) => Promise<void>,
changeOrder: (orderId: string,status:number) => Promise<void>,
updateOrderShippingInfo: (orderId: string,data:UpdateOrderShippingInfo) => Promise<void>,
}
export const useOrderListStore = create<OrderListState>((set, get) => ({
orders: {
items: [],
total: 0,
page: 1,
page_size: 10,
},
getAllOrders: async (data: PaginatedOrderRequest,page:number) => {
const response = await ordersApi.getAllOrders(data);
set((state) => ({
orders: {
...response,
items: page === 1
? response.items
: [...state.orders.items, ...response.items],
}
}));
},
deleteOrder: async (orderId: string) => {
await ordersApi.deleteOrder(orderId);
set((state) => ({
orders: {
...state.orders,
items: state.orders.items.filter(item => item.order_id !== orderId),
total: state.orders.total - 1
}
}));
},
changeOrder: async (orderId: string,status:number) => {
await ordersApi.changeOrder(orderId,status);
set((state) => ({
orders: {
...state.orders,
items: state.orders.items.filter(item => item.order_id !== orderId),
total: state.orders.total - 1
}
}));
},
updateOrderShippingInfo: async (orderId: string,data:UpdateOrderShippingInfo) => {
await ordersApi.updateOrderShippingInfo(orderId,data);
set((state) => ({
orders: {
...state.orders,
items: state.orders.items.filter(item => item.order_id !== orderId),
total: state.orders.total - 1
}
}));
},
}));
Loading…
Cancel
Save