panhui 5 年 前
コミット
ede706468b

+ 13 - 1
App.tsx

@@ -1,6 +1,7 @@
 import { StatusBar } from 'expo-status-bar';
 import React from 'react';
 import * as SplashScreen from 'expo-splash-screen';
+import { Text, Div, Button } from 'react-native-magnus';
 import { SafeAreaProvider } from 'react-native-safe-area-context';
 import { ThemeProvider } from 'react-native-magnus';
 import { UseRequestProvider, useRequest } from 'ahooks';
@@ -43,7 +44,18 @@ export default function App() {
       >
         <ThemeProvider theme={theme}>
           <SafeAreaProvider>
-            <Navigation colorScheme={colorScheme} />
+            <Div flex={1}>
+              <Button
+                fontSize="xl"
+                position="absolute"
+                zIndex="999"
+                bg="transparent"
+                color="black"
+              >
+                骑手端测试版 (0807)
+              </Button>
+              <Navigation colorScheme={colorScheme} />
+            </Div>
             <StatusBar />
           </SafeAreaProvider>
         </ThemeProvider>

+ 1 - 0
mine/SettingScreen.tsx

@@ -73,6 +73,7 @@ export default function SettingScreen({ navigation }: StackScreenProps) {
           onPress={() => {
             alert(navigation, {
               msg: '确认要退出当前账号吗?',
+              hasCancel: true,
               submitEvent: () => logout(),
             });
           }}

+ 7 - 2
modals/AlertModalScreen.tsx

@@ -12,7 +12,7 @@ export default function AlertModalScreen({
   route,
 }: StackScreenProps<RootStackParamList, 'AlertModal'>) {
   const { params } = route;
-  const { title, msg, hasCancel, submitText, submitEvent } = params;
+  const { title, msg, hasCancel, submitText, submitEvent, dangers } = params;
   const { t } = useTranslation();
 
   return (
@@ -23,7 +23,12 @@ export default function AlertModalScreen({
             {title || t('ti-shi')}
           </Text>
 
-          <Text fontSize="md" p={10} textAlign="center">
+          <Text
+            fontSize="md"
+            color={dangers ? 'red500' : 'black'}
+            p={10}
+            textAlign="center"
+          >
             {msg}
           </Text>
 

+ 14 - 2
notice/EmailDetailScreen.tsx

@@ -6,13 +6,25 @@ import { ScrollView } from 'react-native-gesture-handler';
 import { useRequest } from 'ahooks';
 
 import { RootStackParamList } from '../types';
+import { getChatTime } from '../utils/TimeUtils';
+import request from '../utils/RequestUtils';
 
 export default function RegisterScreen({ navigation, route }) {
   const { params } = route;
   const { emailId } = params;
-  const { data, loading, reload } = useRequest(`/email/get/${emailId}`, {
+  const { data, loading, reload, run } = useRequest(`/email/get/${emailId}`, {
     refreshDeps: [emailId],
     initialData: {},
+    onSuccess: (res) => {
+      if (!res.isRead) {
+        request.post('/email/save', {
+          data: {
+            ...data,
+            isRead: true,
+          },
+        });
+      }
+    },
   });
 
   return (
@@ -28,7 +40,7 @@ export default function RegisterScreen({ navigation, route }) {
             <Text fontSize="xl" fontWeight="bold">
               {data.title}
             </Text>
-            <Text>12月26日</Text>
+            <Text>{getChatTime(data.sendTime)}</Text>
           </Div>
 
           <Text

+ 3 - 3
notice/NoticeCom.tsx

@@ -15,14 +15,14 @@ export default function NoticeCom({
 }) {
   const {
     receiveUserId,
-    isReader,
+    isRead,
     content,
     receiveAvatar,
     sendAvatar,
     sendTime,
   } = info;
-  const isReceive = receiveUserId === userId;
-  const active = !isReader && isReceive;
+  const isReceive = type === 'email' || receiveUserId === userId;
+  const active = !isRead && isReceive;
   const avatar = isReceive ? sendAvatar : receiveAvatar;
   return (
     <Button block bg="white" py={0} px={13} rounded="none" onPress={onPress}>

+ 20 - 5
order/OrderCom.tsx

@@ -1,7 +1,14 @@
 import * as React from 'react';
 import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
 
-export default function OrderCom({ info, goDetail, receiverOrder, goMap }) {
+export default function OrderCom({
+  info,
+  type,
+  goDetail,
+  receiverOrder,
+  goMap,
+  changeStatus,
+}) {
   const {
     user,
     userAddress,
@@ -9,6 +16,8 @@ export default function OrderCom({ info, goDetail, receiverOrder, goMap }) {
     riderStatus,
     timeOfArrival,
     deliveryAmount,
+    merShowName,
+    merAddress,
   } = info;
 
   return (
@@ -36,9 +45,9 @@ export default function OrderCom({ info, goDetail, receiverOrder, goMap }) {
             </Text>
             <Div flex={1} ml={12}>
               <Text fontSize="sm" pb={3}>
-                {merchant.showName}
+                {merShowName || merchant.showName}
               </Text>
-              <Text fontSize="xs">{merchant.address}</Text>
+              <Text fontSize="xs">{merAddress || merchant.address}</Text>
             </Div>
           </Div>
           <Div row mt={10}>
@@ -75,16 +84,22 @@ export default function OrderCom({ info, goDetail, receiverOrder, goMap }) {
               查看导航
             </Button>
             {riderStatus === 'RECEIVED' && (
-              <Button ml={20} flex={1} bg="yellow500" onPress={receiverOrder}>
+              <Button ml={20} flex={1} bg="yellow500" onPress={changeStatus}>
                 我已到店
               </Button>
             )}
 
             {riderStatus === 'ARRIVE' && (
-              <Button ml={20} flex={1} bg="yellow500" onPress={receiverOrder}>
+              <Button ml={20} flex={1} bg="yellow500" onPress={goDetail}>
                 拍照取货
               </Button>
             )}
+
+            {riderStatus === 'TAKE_MEAL' && (
+              <Button ml={20} flex={1} bg="yellow500" onPress={changeStatus}>
+                确认送达
+              </Button>
+            )}
           </Div>
         )}
       </Div>

+ 99 - 16
order/OrderDetailScreen.tsx

@@ -4,9 +4,13 @@ import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
 import { ScrollView } from 'react-native-gesture-handler';
 import { useRequest, useCreation } from 'ahooks';
 import { RefreshControl } from 'react-native';
-import { toastInfo } from '../utils/SystemUtils';
+import { toastInfo, toastSuccess, alert } from '../utils/SystemUtils';
 
 import { RiderStatusMap } from '../utils/RiderInfoUtils';
+import ImagePicker from '../components/ImagePicker';
+
+import useModel from 'flooks';
+import OrderModel from './model';
 
 export default function OrderDetailScreen({
   navigation,
@@ -15,11 +19,21 @@ export default function OrderDetailScreen({
   const { params } = route;
   const { orderId } = params;
 
-  const { data, loading, reload } = useRequest(`/orderInfo/get/${orderId}`, {
-    defaultLoading: false,
-    debounceInterval: 1000,
-    initialData: {},
-  });
+  const [pickImg, setpickImg] = React.useState<string>('');
+
+  const { receiverOrder, changeStatus, changeStatusAll } = useModel(
+    OrderModel,
+    []
+  );
+
+  const { data, loading, reload, run } = useRequest(
+    `/orderInfo/get/${orderId}`,
+    {
+      defaultLoading: false,
+      debounceInterval: 1000,
+      initialData: {},
+    }
+  );
 
   const orderGoodsSpecs = useCreation(() => {
     return data.orderGoodsSpecs || [];
@@ -39,6 +53,37 @@ export default function OrderDetailScreen({
     }, 0);
   }, [orderGoodsSpecs]);
 
+  function orderChange() {
+    alert(navigation, {
+      msg: statusInfo.infoText,
+      hasCancel: true,
+      dangers: true,
+      submitEvent: () => {
+        changeStatus(
+          data.id,
+          statusInfo.nextStatus,
+          (res) => {
+            toastSuccess(statusInfo.successText);
+          },
+          () => {
+            alert(navigation, {
+              msg: statusInfo.errorText,
+              hasCancel: true,
+              dangers: true,
+              submitEvent: () => {
+                changeStatusAll(data.id, statusInfo.nextStatus, (res) => {
+                  toastSuccess(statusInfo.successText);
+                  run();
+                });
+              },
+            });
+          },
+          pickImg
+        );
+      },
+    });
+  }
+
   return (
     <Div bg="gray100" flex={1}>
       {statusInfo.type && statusInfo.type !== 'order' && (
@@ -88,6 +133,21 @@ export default function OrderDetailScreen({
         {statusInfo.type && (
           <>
             <Div bg="white" rounded="xs" px={15} py={10}>
+              {statusInfo.type == 'user' && (
+                <Div row py={10}>
+                  <Div flex={1}>
+                    <Text fontSize="xl" fontWeight="bold" color="yellow500">
+                      {statusInfo.name}
+                    </Text>
+                    <Text fontSize="sm" color="gray600" mt={2}>
+                      流水号:{data.id}
+                    </Text>
+                  </Div>
+                  <Button bg="yellow500" w={112} onPress={orderChange}>
+                    确认送达
+                  </Button>
+                </Div>
+              )}
               {statusInfo.type === 'merchant' && (
                 <>
                   <Div row py={10}>
@@ -101,23 +161,30 @@ export default function OrderDetailScreen({
                       bg="yellow500"
                       w={112}
                       disabled={statusInfo.status != 0}
+                      onPress={orderChange}
                     >
                       我已到店
                     </Button>
                   </Div>
 
                   {statusInfo.status === 1 && (
-                    <Div row py={10}>
-                      <Div flex={1}>
-                        <Text>我已取货</Text>
-                        <Text fontSize="sm" color="gray600" mt={2} pr={48}>
-                          为避免货物纠纷,请在取货时 检查并拍照存证
-                        </Text>
+                    <>
+                      <Div row py={10}>
+                        <Div flex={1}>
+                          <Text>我已取货</Text>
+                          <Text fontSize="sm" color="gray600" mt={2} pr={48}>
+                            为避免货物纠纷,请在取货时 检查并拍照存证
+                          </Text>
+                        </Div>
+                        <Button bg="yellow500" w={112} onPress={orderChange}>
+                          拍照取货
+                        </Button>
                       </Div>
-                      <Button bg="yellow500" w={112}>
-                        拍照取货
-                      </Button>
-                    </Div>
+                      <ImagePicker
+                        img={pickImg}
+                        setImg={(img) => setpickImg(img)}
+                      />
+                    </>
                   )}
                 </>
               )}
@@ -248,6 +315,22 @@ export default function OrderDetailScreen({
                   })}
                 </Div>
               </Div>
+
+              {statusInfo.type === 'order' && (
+                <Button
+                  bg="yellow500"
+                  w={112}
+                  alignSelf="flex-end"
+                  my={10}
+                  onPress={() => {
+                    receiverOrder(data.id, (res) => {
+                      toastSuccess('接单成功');
+                    });
+                  }}
+                >
+                  接单
+                </Button>
+              )}
             </Div>
             {(statusInfo.type === 'merchant' || statusInfo.type === 'user') && (
               <Button block mx={15} my={10} bg="yellow500">

+ 54 - 4
order/OrderScreen.tsx

@@ -16,9 +16,9 @@ import { useTranslation } from 'react-i18next';
 import moment from 'moment';
 
 import { promot } from '../utils/SystemUtils';
-import { orderRiderStatus } from '../utils/RiderInfoUtils';
+import { orderRiderStatus, RiderStatusMap } from '../utils/RiderInfoUtils';
 import request from '../utils/RequestUtils';
-import { toastSuccess } from '../utils/SystemUtils';
+import { toastSuccess, alert } from '../utils/SystemUtils';
 
 import OrderCom from './OrderCom';
 
@@ -26,7 +26,10 @@ export default function OrderScreen({ navigation }: StackScreenProps) {
   const { t } = useTranslation();
   const { locationInfo, getNowLocation } = useModel(Map, ['locationInfo']);
 
-  const { receiverOrder } = useModel(OrderModel, []);
+  const { receiverOrder, changeStatus, changeStatusAll } = useModel(
+    OrderModel,
+    []
+  );
 
   const [chooseStatus, setChooseStatus] = React.useState<string>(
     'NOT_RECEIVED'
@@ -57,9 +60,20 @@ export default function OrderScreen({ navigation }: StackScreenProps) {
       formatResult: chooseStatusInfo.formatResult,
       defaultLoading: false,
       debounceInterval: 1000,
+      initialData: [],
     }
   );
 
+  const showData = useCreation(() => {
+    if (chooseStatusInfo.status) {
+      return data.filter((item) => {
+        return chooseStatusInfo.status.indexOf(item.riderStatus) !== -1;
+      });
+    } else {
+      return data;
+    }
+  }, [data, chooseStatusInfo]);
+
   return (
     <Div bg="gray100" flex={1}>
       <Div
@@ -103,6 +117,7 @@ export default function OrderScreen({ navigation }: StackScreenProps) {
           return (
             <OrderCom
               info={item}
+              type={chooseStatusInfo.type}
               goDetail={() =>
                 navigation.navigate('OrderStack', {
                   screen: 'OrderDetail',
@@ -124,10 +139,45 @@ export default function OrderScreen({ navigation }: StackScreenProps) {
                   },
                 })
               }
+              changeStatus={() => {
+                const orderStatusInfo = RiderStatusMap.get(item.riderStatus);
+
+                alert(navigation, {
+                  msg: orderStatusInfo.infoText,
+                  hasCancel: true,
+                  dangers: true,
+                  submitEvent: () => {
+                    changeStatus(
+                      item.id,
+                      orderStatusInfo.nextStatus,
+                      (res) => {
+                        toastSuccess(orderStatusInfo.successText);
+                      },
+                      () => {
+                        alert(navigation, {
+                          msg: orderStatusInfo.errorText,
+                          hasCancel: true,
+                          dangers: true,
+                          submitEvent: () => {
+                            changeStatusAll(
+                              item.id,
+                              orderStatusInfo.nextStatus,
+                              (res) => {
+                                toastSuccess(orderStatusInfo.successText);
+                                run();
+                              }
+                            );
+                          },
+                        });
+                      }
+                    );
+                  },
+                });
+              }}
             />
           );
         }}
-        data={data}
+        data={showData}
         contentContainerStyle={{
           flexGrow: 1,
           paddingHorizontal: 15,

+ 71 - 1
order/model.ts

@@ -1,6 +1,6 @@
 import request from '../utils/RequestUtils';
 import { toastShow, toastInfo, toastSuccess } from '../utils/SystemUtils';
-
+import MapModel from '../map/model';
 const OrderMap = (now, successEvent) => ({
   receiverOrder(orderId) {
     toastShow();
@@ -20,6 +20,76 @@ const OrderMap = (now, successEvent) => ({
         toastInfo(e.error);
       });
   },
+  changeStatus(orderId, status, successEvent, errorEvent, pickImg) {
+    toastShow();
+    const { pickupPhotos } = now();
+    if (status === 'TAKE_MEAL') {
+      pickupPhotos(orderId, status, successEvent, errorEvent, pickImg);
+      return;
+    }
+    const { getNowLocation } = now(MapModel);
+    getNowLocation()
+      .then((res) => {
+        const { location } = res;
+        return request.post('/orderInfo/riderStatus', {
+          data: {
+            orderId,
+            status,
+            longitude: location.lng,
+            latitude: location.lat,
+          },
+          requestType: 'form',
+        });
+      })
+      .then((res) => {
+        if (successEvent) {
+          successEvent(res);
+        }
+      })
+      .catch((e) => {
+        if (e.error === '未到店' && errorEvent) {
+          errorEvent();
+        } else {
+          toastInfo(e.error);
+        }
+      });
+  },
+  pickupPhotos(orderId, status, successEvent, errorEvent, pickImg) {
+    request
+      .get('/orderInfo/pickupPhotos', {
+        params: {
+          orderId,
+          status,
+          img: pickImg,
+        },
+      })
+      .then((res) => {
+        if (successEvent) {
+          successEvent(res);
+        }
+      })
+      .catch((e) => {
+        toastInfo(e.error);
+      });
+  },
+  changeStatusAll(orderId, status, successEvent) {
+    toastShow();
+    request
+      .get('/orderInfo/', {
+        params: {
+          orderId,
+          status,
+        },
+      })
+      .then((res) => {
+        if (successEvent) {
+          successEvent(res);
+        }
+      })
+      .catch((e) => {
+        toastInfo(e.error);
+      });
+  },
 });
 
 export default OrderMap;

+ 18 - 10
utils/RiderInfoUtils.ts

@@ -50,6 +50,7 @@ const orderRiderStatus = new Map([
       formatResult: (res) => {
         return res;
       },
+      type: 'order',
     },
   ],
   [
@@ -58,14 +59,11 @@ const orderRiderStatus = new Map([
       name: 'dai-qu-can',
       requestUrl: '/orderInfo/my',
       status: ['ARRIVE', 'RECEIVED'],
-      params: {
-        query: {
-          riderStatus: 'RECEIVED',
-        },
-      },
+      params: {},
       formatResult: (res) => {
         return res.content;
       },
+      type: 'orderNew',
     },
   ],
   [
@@ -73,17 +71,15 @@ const orderRiderStatus = new Map([
     {
       name: 'dai-song-da',
       requestUrl: '/orderInfo/my',
-      params: {
-        query: {
-          riderStatus: 'TAKE_MEAL',
-        },
-      },
+      status: ['TAKE_MEAL'],
+      params: {},
       formatResult: (res) => {
         return res;
       },
       formatResult: (res) => {
         return res.content;
       },
+      type: 'orderNew',
     },
   ],
 ]);
@@ -102,6 +98,10 @@ const RiderStatusMap = new Map([
       name: '已接单,待取餐',
       type: 'merchant',
       status: 0,
+      nextStatus: 'ARRIVE',
+      successText: '到店成功',
+      infoText: '确认已经成功到店吗?',
+      errorText: '当前距离商家过远,您确认已经到店吗?',
     },
   ],
   [
@@ -110,6 +110,10 @@ const RiderStatusMap = new Map([
       name: '已到店,待取餐',
       type: 'merchant',
       status: 1,
+      nextStatus: 'TAKE_MEAL',
+      successText: '取餐成功',
+      infoText: '确认已经成功取餐吗?',
+      errorText: '当前距离商家过远,您确认已经取餐吗?',
     },
   ],
   [
@@ -117,6 +121,10 @@ const RiderStatusMap = new Map([
     {
       name: '已取餐,配送中',
       type: 'user',
+      nextStatus: 'CARRY_OUT',
+      successText: '配送成功',
+      infoText: '确认餐品已送到用户手中么?',
+      errorText: '当前距离离用户过远,您确认已送达吗?',
     },
   ],
   [