panhui %!s(int64=5) %!d(string=hai) anos
pai
achega
62594e81fb

+ 0 - 3
App.tsx

@@ -15,7 +15,6 @@ import theme from './constants/Theme';
 import request from './utils/RequestUtils';
 
 import User from './stores/User';
-import IM from './im/model';
 
 export default function App() {
   const isLoadingComplete = useCachedResources();
@@ -26,8 +25,6 @@ export default function App() {
     'initialRouteName',
   ]);
 
-  const { messages } = useModel(IM, ['messages']);
-
   const { loading, run } = useRequest(getInit, {
     refreshDeps: [id],
     debounceInterval: 2000,

+ 1 - 1
constants/Theme.ts

@@ -42,7 +42,7 @@ export default {
 
     green100: '#eefbe9',
     green200: '#cdf4bd',
-    green300: '#aced91',
+    green300: '#84CCC9',
     green400: '#8be665',
     green500: '#69df39',
     green600: '#50c620',

+ 0 - 118
im/model.ts

@@ -1,118 +0,0 @@
-import * as firebase from 'firebase';
-
-const IM = (now) => ({
-  SDKAppID: 1400401634,
-  userID: '2105',
-  userSig:
-    'eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zIhwoYGplDx4pTsxIKCzBQlK0MTAwMTA0MzYxOITGpFQWZRKlDc1NTUyMDAACJakpkLFrM0Bao1MIGqLc5MBxqbGGqUnZzlFZWiHRoeFaOf45eX6h*j7*nkXZ4XmOIeleYTXBbp7VNUHpqTE*xqq1QLANeJMS4_',
-  messages: [],
-  init() {
-    const { SDKAppID, userID, userSig } = now();
-    // 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例
-    let options = {
-      SDKAppID, // 接入时需要将0替换为您的即时通信应用的 SDKAppID
-    };
-    let tim = TIM.create(options); // SDK 实例通常用 tim 表示
-    // 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明
-    tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用
-    // tim.setLogLevel(1); // release级别,SDK 输出关键信息,生产环境时建议使用
-
-    // 将腾讯云对象存储服务 SDK (以下简称 COS SDK)注册为插件,IM SDK 发送文件、图片等消息时,需要用到腾讯云的 COS 服务
-    // HTML5 环境,注册 COS SDK
-    tim.registerPlugin({ 'cos-js-sdk': COS });
-
-    // 监听事件,如:
-    tim.on(TIM.EVENT.SDK_READY, function (event) {
-      // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
-      // event.name - TIM.EVENT.SDK_READY
-    });
-
-    tim.on(TIM.EVENT.MESSAGE_RECEIVED, function (event) {
-      console.log(event);
-      // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
-      // event.name - TIM.EVENT.MESSAGE_RECEIVED
-      // event.data - 存储 Message 对象的数组 - [Message]
-      now({
-        messages: event.data,
-      });
-    });
-
-    tim.on(TIM.EVENT.MESSAGE_REVOKED, function (event) {
-      // 收到消息被撤回的通知。使用前需要将SDK版本升级至v2.4.0或以上。
-      // event.name - TIM.EVENT.MESSAGE_REVOKED
-      // event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isRevoked 属性值为 true
-    });
-
-    tim.on(TIM.EVENT.MESSAGE_READ_BY_PEER, function (event) {
-      // SDK 收到对端已读消息的通知,即已读回执。使用前需要将SDK版本升级至v2.7.0或以上。仅支持单聊会话。
-      // event.name - TIM.EVENT.MESSAGE_READ_BY_PEER
-      // event.data - event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isPeerRead 属性值为 true
-    });
-
-    tim.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, function (event) {
-      // 收到会话列表更新通知,可通过遍历 event.data 获取会话列表数据并渲染到页面
-      // event.name - TIM.EVENT.CONVERSATION_LIST_UPDATED
-      // event.data - 存储 Conversation 对象的数组 - [Conversation]
-    });
-
-    tim.on(TIM.EVENT.GROUP_LIST_UPDATED, function (event) {
-      // 收到群组列表更新通知,可通过遍历 event.data 获取群组列表数据并渲染到页面
-      // event.name - TIM.EVENT.GROUP_LIST_UPDATED
-      // event.data - 存储 Group 对象的数组 - [Group]
-    });
-
-    tim.on(TIM.EVENT.PROFILE_UPDATED, function (event) {
-      // 收到自己或好友的资料变更通知
-      // event.name - TIM.EVENT.PROFILE_UPDATED
-      // event.data - 存储 Profile 对象的数组 - [Profile]
-    });
-
-    tim.on(TIM.EVENT.BLACKLIST_UPDATED, function (event) {
-      // 收到黑名单列表更新通知
-      // event.name - TIM.EVENT.BLACKLIST_UPDATED
-      // event.data - 存储 userID 的数组 - [userID]
-    });
-
-    tim.on(TIM.EVENT.ERROR, function (event) {
-      // 收到 SDK 发生错误通知,可以获取错误码和错误信息
-      // event.name - TIM.EVENT.ERROR
-      // event.data.code - 错误码
-      // event.data.message - 错误信息
-    });
-
-    tim.on(TIM.EVENT.SDK_NOT_READY, function (event) {
-      // 收到 SDK 进入 not ready 状态通知,此时 SDK 无法正常工作
-      // event.name - TIM.EVENT.SDK_NOT_READY
-    });
-
-    tim.on(TIM.EVENT.KICKED_OUT, function (event) {
-      // 收到被踢下线通知
-      // event.name - TIM.EVENT.KICKED_OUT
-      // event.data.type - 被踢下线的原因,例如 :
-      //   - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢
-      //   - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢
-      //   - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢(v2.4.0起支持)。
-    });
-
-    tim.on(TIM.EVENT.NET_STATE_CHANGE, function (event) {
-      // 网络状态发生改变(v2.5.0 起支持)。
-      // event.name - TIM.EVENT.NET_STATE_CHANGE
-      // event.data.state 当前网络状态,枚举值及说明如下:
-      //   - TIM.TYPES.NET_STATE_CONNECTED - 已接入网络
-      //   - TIM.TYPES.NET_STATE_CONNECTING - 连接中。很可能遇到网络抖动,SDK 在重试。接入侧可根据此状态提示“当前网络不稳定”或“连接中”
-      //   - TIM.TYPES.NET_STATE_DISCONNECTED - 未接入网络。接入侧可根据此状态提示“当前网络不可用”。SDK 仍会继续重试,若用户网络恢复,SDK 会自动同步消息
-    });
-
-    // 开始登录
-    tim
-      .login({
-        userID,
-        userSig,
-      })
-      .then((res) => {
-        console.log(res);
-      });
-  },
-});
-
-export default IM;

+ 4 - 1
locales/zh-CN.json

@@ -120,5 +120,8 @@
   "wo-de-tou-su": "我的投诉",
   "she-zhi": "设置",
   "tong-zhi-he-ti-shi-yin-she-zhi": "通知和提示音设置",
-  "qi-shou-fu-wu-he-zuo-xie-yi": "骑手服务合作协议"
+  "qi-shou-fu-wu-he-zuo-xie-yi": "骑手服务合作协议",
+  "wei-jie-dan": "未接单",
+  "dai-qu-can": "待取餐",
+  "dai-song-da": "待送达"
 }

+ 4 - 2
login/model.ts

@@ -16,9 +16,11 @@ const MapModel = (now) => ({
   loginByPsd() {
     toastShow();
     return request
-      .post('/auth/phoneLogin', {
+      .post('/auth/login', {
         data: {
-          phone: '1562356',
+          username: '1562356',
+          password: '123456',
+          expiration: '1',
         },
         requestType: 'form',
       })

+ 21 - 0
map/OrderMapScreen.tsx

@@ -0,0 +1,21 @@
+import { StackScreenProps } from '@react-navigation/stack';
+import * as React from 'react';
+import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
+import { ScrollView } from 'react-native-gesture-handler';
+
+export default function OrderMapScreen({ navigation }: StackScreenProps) {
+  return (
+    <Div bg="gray100">
+      <ScrollView
+        contentContainerStyle={{
+          flexGrow: 1,
+          backgroundColor: '#f2f2f2',
+        }}
+      >
+        <Div>
+          <Text></Text>
+        </Div>
+      </ScrollView>
+    </Div>
+  );
+}

+ 1 - 1
mine/MineAppraisalScreen.tsx

@@ -115,7 +115,7 @@ export default function MineAppraisalScreen({ navigation }: StackScreenProps) {
       isNoMore: (r: Result) => {
         return false;
       },
-      defaultLoading: true,
+      defaultLoading: false,
       debounceInterval: 1000,
       loadMore: true,
     }

+ 1 - 1
mine/MineComplaint.tsx

@@ -83,7 +83,7 @@ export default function MineAppraisalScreen({ navigation }: StackScreenProps) {
       isNoMore: (r: Result) => {
         return false;
       },
-      defaultLoading: true,
+      defaultLoading: false,
       debounceInterval: 1000,
       loadMore: true,
     }

+ 21 - 14
modals/InputModalScreen.tsx

@@ -10,7 +10,7 @@ export default function InputModalScreen({
   route,
 }: StackScreenProps) {
   const { params } = route;
-  const { title, defaultVal, hasCancel, submitText, submitEvent } =
+  const { title,secureTextEntry, defaultVal, hasCancel, submitText, submitEvent, tips } =
     params || {};
   const { t } = useTranslation();
 
@@ -33,23 +33,30 @@ export default function InputModalScreen({
             opacity={1}
             loaderColor="gray400"
             color="gray900"
+            secureTextEntry={secureTextEntry}
             onChangeText={(text) => setVal(text)}
           />
 
+          <Text color="gray500" textAlign="center" mt={3}>
+            {tips}
+          </Text>
+
           <Div row py={10} mt={10}>
-            <Button
-              flex={1}
-              mx={3}
-              rounded="xs"
-              bg="white"
-              color="black"
-              borderWidth={1}
-              borderColor="yellow500"
-              fontSize="sm"
-              onPress={() => navigation.goBack()}
-            >
-              {hasCancel ? t('qu-xiao') : submitText || t('que-ren')}
-            </Button>
+            {hasCancel && (
+              <Button
+                flex={1}
+                mx={3}
+                rounded="xs"
+                bg="white"
+                color="black"
+                borderWidth={1}
+                borderColor="yellow500"
+                fontSize="sm"
+                onPress={() => navigation.goBack()}
+              >
+                {hasCancel ? t('qu-xiao') : submitText || t('que-ren')}
+              </Button>
+            )}
             <Button
               flex={1}
               mx={3}

+ 7 - 0
navigation/LoginStackNavigator.tsx

@@ -50,6 +50,13 @@ export default function Navigation({
         cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
         headerStyle: {
           backgroundColor: '#FFC21C',
+          elevation: 0,
+          shadowOffset: {
+            width: 0,
+            height: 0,
+          },
+          shadowOpacity: 0,
+          shadowRadius: 0,
         },
         headerTintColor: '#fff',
         headerTitleStyle: {

+ 1 - 1
navigation/MianTabNavigator.tsx

@@ -23,7 +23,7 @@ export default function MainTabNavigator() {
 
   return (
     <MainTab.Navigator
-      initialRouteName="Mine"
+      initialRouteName="Order"
       tabBarOptions={{ activeTintColor: Colors[colorScheme].tint }}
     >
       <MainTab.Screen

+ 7 - 0
navigation/MineStackNavigator.tsx

@@ -50,6 +50,13 @@ export default function Navigation({
         cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
         headerStyle: {
           backgroundColor: '#FFC21C',
+          elevation: 0,
+          shadowOffset: {
+            width: 0,
+            height: 0,
+          },
+          shadowOpacity: 0,
+          shadowRadius: 0,
         },
         headerTintColor: '#fff',
         headerTitleStyle: {

+ 12 - 5
navigation/NoticeStackNavigator.tsx

@@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next';
 
 import { NoticeStackParamList } from '../types';
 
-import NoticeScreen from '../notice/NoticeScreen';
+import ChatScreen from '../notice/ChatScreen';
 
 const NoticeStack = createStackNavigator<NoticeStackParamList>();
 export default function Navigation({
@@ -25,7 +25,7 @@ export default function Navigation({
   const { t } = useTranslation();
   return (
     <NoticeStack.Navigator
-      initialRouteName="Notice"
+      initialRouteName="Chat"
       screenOptions={{
         cardOverlayEnabled: true,
         cardStyle: { backgroundColor: '#f2f2f2', flex: 1 },
@@ -35,6 +35,13 @@ export default function Navigation({
         cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
         headerStyle: {
           backgroundColor: '#FFC21C',
+          elevation: 0,
+          shadowOffset: {
+            width: 0,
+            height: 0,
+          },
+          shadowOpacity: 0,
+          shadowRadius: 0,
         },
         headerTintColor: '#fff',
         headerTitleStyle: {
@@ -45,9 +52,9 @@ export default function Navigation({
       }}
     >
       <NoticeStack.Screen
-        name="Notice"
-        component={NoticeScreen}
-        options={{ title: t('qi-shou-shen-he') }}
+        name="Chat"
+        component={ChatScreen}
+        options={{ title: '聊天' }}
       />
     </NoticeStack.Navigator>
   );

+ 11 - 5
navigation/OrderStackNavigator.tsx

@@ -14,7 +14,8 @@ import { useTranslation } from 'react-i18next';
 
 import { OrderStackParamList } from '../types';
 
-import OrderScreen from '../order/OrderScreen';
+import OrderDetailScreen from '../order/OrderDetailScreen';
+import OrderMapScreen from '../map/OrderMapScreen';
 
 const OrderStack = createStackNavigator<OrderStackParamList>();
 export default function Navigation({
@@ -25,7 +26,6 @@ export default function Navigation({
   const { t } = useTranslation();
   return (
     <OrderStack.Navigator
-      initialRouteName="Order"
       screenOptions={{
         cardOverlayEnabled: true,
         cardStyle: { backgroundColor: '#f2f2f2', flex: 1 },
@@ -45,9 +45,15 @@ export default function Navigation({
       }}
     >
       <OrderStack.Screen
-        name="Order"
-        component={OrderScreen}
-        options={{ title: t('qi-shou-shen-he') }}
+        name="OrderDetail"
+        component={OrderDetailScreen}
+        options={{ title: '订单详情' }}
+        initialParams={{ orderId: 2077 }}
+      />
+      <OrderStack.Screen
+        name="OrderMap"
+        component={OrderMapScreen}
+        options={{ title: '地图' }}
       />
     </OrderStack.Navigator>
   );

+ 24 - 6
navigation/index.tsx

@@ -26,6 +26,10 @@ import MainTabNavigator from './MianTabNavigator';
 //我的模块堆栈
 import MineStackNavigator from './MineStackNavigator';
 
+import OrderStackNavigator from './OrderStackNavigator';
+
+import NoticeStackNavigator from './NoticeStackNavigator';
+
 import { useCreation } from 'ahooks';
 
 import { RootStackParamList } from '../types';
@@ -45,12 +49,13 @@ export default function Navigation({
     console.log(initialRouteName);
     if (__DEV__) {
       return {
-        name: 'Main',
+        name: 'OrderStack',
+        screen: 'OrderDetail',
       };
     } else {
       return {
-        name: initialRouteName !== 'Main' ? 'Login' : initialRouteName,
-        screen: initialRouteName !== 'Main' ? initialRouteName : 'Order',
+        name: initialRouteName !== 'MainStack' ? 'Login' : initialRouteName,
+        screen: initialRouteName !== 'MainStack' ? initialRouteName : 'Order',
       };
     }
   }, [__DEV__, initialRouteName]);
@@ -101,15 +106,13 @@ function RootNavigator({ initRoute }) {
           cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
         }}
       />
-
       <Stack.Screen
-        name="Main"
+        name="MainStack"
         component={MainTabNavigator}
         options={{
           cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
         }}
       />
-
       <Stack.Screen
         name="MineStack"
         component={MineStackNavigator}
@@ -117,6 +120,21 @@ function RootNavigator({ initRoute }) {
           cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
         }}
       />
+      <Stack.Screen
+        name="NoticeStack"
+        component={NoticeStackNavigator}
+        options={{
+          cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
+        }}
+      />
+      <Stack.Screen
+        name="OrderStack"
+        component={OrderStackNavigator}
+        options={{
+          cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
+        }}
+      />
+
       <Stack.Screen
         name="Modal"
         mode="modals"

+ 86 - 0
notice/ChatScreen.tsx

@@ -0,0 +1,86 @@
+import { StackScreenProps } from '@react-navigation/stack';
+import React, { useState, useCallback, useEffect } from 'react';
+import { Platform, View } from 'react-native';
+import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
+import { GiftedChat, KeyboardAvoidingView } from 'react-native-gifted-chat';
+import { ScrollView } from 'react-native-gesture-handler';
+import * as Localization from 'expo-localization';
+import useModel from 'flooks';
+import User from '../stores/User';
+import IM from './model';
+import { parse } from '../utils/TimeUtils';
+
+import { useRequest } from 'ahooks';
+
+export default function ChatScreen({ navigation, route }: StackScreenProps) {
+  const { params } = route;
+  const { toUserId, toUserName } = params;
+
+  if (toUserName) {
+    navigation.setOptions({
+      title: toUserName,
+    });
+  }
+
+  const { id, userInfo, chatInfo } = useModel(User, [
+    'id',
+    'chatInfo',
+    'userInfo',
+  ]);
+
+  const [messages, setMessages] = useState([]);
+  const { sendMessage } = useModel(IM, []);
+
+  const { loading, run } = useRequest(
+    `/chat/showChat?userOne=${id}&userTwo=${toUserId}`,
+    {
+      defaultLoading: false,
+      initialData: [],
+      onSuccess: (data) => {
+        const list = data.map((item, index) => {
+          return {
+            _id: index,
+            text: item.content,
+            createdAt: parse(item.sendTime),
+            user: {
+              _id: item.sendUserId,
+              name: item.sendNickName,
+              avatar: item.sendAvatar,
+            },
+          };
+        });
+        setMessages(list);
+      },
+    }
+  );
+
+  React.useEffect(() => {
+    if (chatInfo && chatInfo.from === 'toUserId') {
+      run();
+    }
+  }, [chatInfo]);
+
+  const onSend = useCallback((messages = []) => {
+    console.log(messages);
+    sendMessage(messages[0].text, toUserId);
+    setMessages((previousMessages) =>
+      GiftedChat.append(previousMessages, messages)
+    );
+  }, []);
+
+  return (
+    <Div flex={1}>
+      <GiftedChat
+        placeholder="请输入聊天内容"
+        messages={messages}
+        onSend={(messages) => onSend(messages)}
+        showUserAvatar={true}
+        user={{
+          _id: userInfo.id,
+          avatar: userInfo.avatar,
+        }}
+      />
+      {Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />}
+    </Div>
+  );
+}

+ 72 - 0
notice/NoticeCom.tsx

@@ -0,0 +1,72 @@
+import * as React from 'react';
+import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
+
+const logo = require('../assets/images/logo.png');
+import { getChatTime } from '../utils/TimeUtils';
+
+export default function NoticeCom({
+  info = {
+    receiveUserId: 0,
+  },
+  type,
+  userId,
+  onPress,
+  toUserName = '',
+}) {
+  const {
+    receiveUserId,
+    isReader,
+    content,
+    receiveAvatar,
+    sendAvatar,
+    sendTime,
+  } = info;
+  const isReceive = receiveUserId === userId;
+  const active = !isReader && isReceive;
+  const avatar = isReceive ? sendAvatar : receiveAvatar;
+  return (
+    <Button block bg="white" py={0} px={13} rounded="none" onPress={onPress}>
+      <Div
+        flex={1}
+        row
+        py={10}
+        alignItems="center"
+        borderBottomWidth={1}
+        borderBottomColor="gray100"
+      >
+        <Div
+          w={10}
+          h={10}
+          bg={active ? 'yellow500' : 'gray100'}
+          rounded="circle"
+        />
+
+        {type !== 'user' ? (
+          <Div w={33} h={33} bg="green300" rounded="sm" ml={10} />
+        ) : (
+          <Image
+            w={33}
+            h={33}
+            source={avatar ? { uri: avatar } : logo}
+            ml={10}
+            rounded="circle"
+          />
+        )}
+
+        <Div flex={1} justifyContent="space-between" ml={5}>
+          <Div row>
+            <Text fontSize="sm" flex={1}>
+              {toUserName}
+            </Text>
+            <Text fontSize="xs" color="gray400">
+              {getChatTime(sendTime)}
+            </Text>
+          </Div>
+          <Text fontSize="xs" color="gray400" numberOfLines={1}>
+            {content || ''}
+          </Text>
+        </Div>
+      </Div>
+    </Button>
+  );
+}

+ 106 - 10
notice/NoticeScreen.tsx

@@ -1,26 +1,122 @@
 import { StackScreenProps } from '@react-navigation/stack';
 import * as React from 'react';
 import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
-import { ScrollView } from 'react-native-gesture-handler';
+import { ScrollView, FlatList } from 'react-native-gesture-handler';
+import { useNavigation } from '@react-navigation/native';
+import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
+import Constants from 'expo-constants';
+
+import useModel from 'flooks';
+import { useMount } from 'ahooks';
 
 import { RootStackParamList } from '../types';
 import IM from './model';
+import User from '../stores/User';
+
+import { useTranslation } from 'react-i18next';
+
+import NoticeCom from './NoticeCom';
+
+const NoticeTab = createMaterialTopTabNavigator();
 
 export default function NoticeScreen({
   navigation,
 }: StackScreenProps<RootStackParamList, 'Login'>) {
+  const { t } = useTranslation();
+  const webRef = React.useRef();
+  const { initChat, chatList, sysNoticeList } = useModel(IM, [
+    'chatList',
+    'sysNoticeList',
+  ]);
+  useMount(() => {
+    initChat();
+  });
+
   return (
-    <Div bg="gray100">
-      <ScrollView
-        contentContainerStyle={{
-          flexGrow: 1,
-          backgroundColor: '#f2f2f2',
+    <Div bg="gray100" flex={1}>
+      <Div bg="yellow500" pt={Constants.statusBarHeight + 11} pb={11}>
+        <Text color="white" textAlign="center" fontSize="xl" fontWeight="bold">
+          消息中心
+        </Text>
+      </Div>
+      <NoticeTab.Navigator
+        initialRouteName="Chat"
+        style={{ flexGrow: 1 }}
+        tabBarOptions={{
+          inactiveTintColor: '#000',
+          activeTintColor: '#FFC21C',
+          indicatorStyle: { height: 0 },
+          labelStyle: { fontSize: 15 },
+          style: {
+            backgroundColor: '#f2f2f2',
+            elevation: 0,
+            shadowOffset: {
+              width: 0,
+              height: 0,
+            },
+            shadowOpacity: 0,
+            shadowRadius: 0,
+          },
         }}
       >
-        <Div>
-          <Text></Text>
-        </Div>
-      </ScrollView>
+        <NoticeTab.Screen
+          name="Sys"
+          component={SysNoticeScreen}
+          options={{
+            title: '系统消息',
+          }}
+        />
+        <NoticeTab.Screen
+          name="Chat"
+          component={UserChatScreen}
+          options={{
+            title: '用户消息',
+          }}
+        />
+      </NoticeTab.Navigator>
     </Div>
   );
 }
+
+function SysNoticeScreen() {
+  return (
+    <ScrollView
+      contentContainerStyle={{ flexGrow: 1, backgroundColor: '#fff' }}
+    >
+      <NoticeCom />
+    </ScrollView>
+  );
+}
+
+function UserChatScreen({ navigation }) {
+  const { chatList } = useModel(IM, ['chatList']);
+  const { id } = useModel(User, ['id']);
+  return (
+    <FlatList
+      renderItem={({ item }) => {
+        const isReceive = item.receiveUserId === id;
+        const toUserId = isReceive ? item.sendUserId : item.receiveUserId;
+        const toUserName = isReceive ? item.sendNickname : item.receiveNickname;
+        return (
+          <NoticeCom
+            info={item}
+            userId={id}
+            type="user"
+            toUserName={toUserName}
+            onPress={() => {
+              navigation.navigate('NoticeStack', {
+                screen: 'Chat',
+                params: {
+                  toUserId,
+                  toUserName,
+                },
+              });
+            }}
+          />
+        );
+      }}
+      data={chatList}
+      contentContainerStyle={{ flexGrow: 1, backgroundColor: '#fff' }}
+    />
+  );
+}

+ 65 - 0
notice/TimScreen.tsx

@@ -0,0 +1,65 @@
+import { StackScreenProps } from '@react-navigation/stack';
+import * as React from 'react';
+import { useNavigation } from '@react-navigation/native';
+import { WebView } from 'react-native-webview';
+
+import useModel from 'flooks';
+import { useMount } from 'ahooks';
+
+import IM from './model';
+
+import { useTranslation } from 'react-i18next';
+
+export default function NoticeScreen({
+  navigation,
+}: StackScreenProps<RootStackParamList, 'Login'>) {
+  const { t } = useTranslation();
+  const webRef = React.useRef();
+  const {
+    getChat,
+    userID,
+    userSig,
+    tim,
+    setTim,
+    initChat,
+    updateChatInfo,
+  } = useModel(IM, ['userID', 'userSig', 'tim']);
+  useMount(() => {
+    initChat();
+  });
+
+  React.useEffect(() => {
+    if (userSig && tim)
+      tim.injectJavaScript(
+        `window.chatLogin(${JSON.stringify(userID)},${JSON.stringify(userSig)})`
+      );
+  }, [userSig, tim]);
+
+  return (
+    <WebView
+      ref={webRef}
+      source={{
+        uri: `http://dingdong.izouma.com/map/tim`,
+      }}
+      onMessage={({ nativeEvent }) => {
+        console.log(nativeEvent);
+        const info = JSON.parse(nativeEvent.data);
+        switch (info.name) {
+          case 'onConversationListUpdated':
+            getChat();
+            break;
+
+          default:
+            break;
+        }
+
+        if (info.conversationType === 'C2C') {
+          updateChatInfo(info);
+        }
+      }}
+      onLoadEnd={() => {
+        setTim(webRef.current);
+      }}
+    />
+  );
+}

+ 63 - 103
notice/model.ts

@@ -1,115 +1,75 @@
 import TIM from 'tim-js-sdk';
 import COS from 'cos-js-sdk-v5';
+import request from '../utils/RequestUtils';
+import User from '../stores/User';
 
 const IM = (now) => ({
   SDKAppID: 1400401634,
-  userID: 2015,
-  userSig:
-    'eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zIhwoYGplDx4pTsxIKCzBQlK0MTAwMTA0MzYxOITGpFQWZRKlDc1NTUyMDAACJakpkLFrM0Bao1MIGqLc5MBxqbGGqUnZzlFZWiHRoeFaOf45eX6h*j7*nkXZ4XmOIeleYTXBbp7VNUHpqTE*xqq1QLANeJMS4_',
+  userID: 0,
+  userSig: null,
   messages: [],
-  init() {
-    const { SDKAppID, userID, userSig } = now();
-    // 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例
-    let options = {
-      SDKAppID, // 接入时需要将0替换为您的即时通信应用的 SDKAppID
-    };
-    let tim = TIM.create(options); // SDK 实例通常用 tim 表示
-    // 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明
-    tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用
-    // tim.setLogLevel(1); // release级别,SDK 输出关键信息,生产环境时建议使用
-
-    // 将腾讯云对象存储服务 SDK (以下简称 COS SDK)注册为插件,IM SDK 发送文件、图片等消息时,需要用到腾讯云的 COS 服务
-    // HTML5 环境,注册 COS SDK
-    tim.registerPlugin({ 'cos-js-sdk': COS });
-
-    // 监听事件,如:
-    tim.on(TIM.EVENT.SDK_READY, function (event) {
-      // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
-      // event.name - TIM.EVENT.SDK_READY
-    });
-
-    tim.on(TIM.EVENT.MESSAGE_RECEIVED, function (event) {
-      console.log(event);
-      // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
-      // event.name - TIM.EVENT.MESSAGE_RECEIVED
-      // event.data - 存储 Message 对象的数组 - [Message]
-      now({
-        messages: event.data,
-      });
-    });
-
-    tim.on(TIM.EVENT.MESSAGE_REVOKED, function (event) {
-      // 收到消息被撤回的通知。使用前需要将SDK版本升级至v2.4.0或以上。
-      // event.name - TIM.EVENT.MESSAGE_REVOKED
-      // event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isRevoked 属性值为 true
-    });
-
-    tim.on(TIM.EVENT.MESSAGE_READ_BY_PEER, function (event) {
-      // SDK 收到对端已读消息的通知,即已读回执。使用前需要将SDK版本升级至v2.7.0或以上。仅支持单聊会话。
-      // event.name - TIM.EVENT.MESSAGE_READ_BY_PEER
-      // event.data - event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isPeerRead 属性值为 true
+  chatList: [],
+  sysNoticeList: [],
+  chatInfo: {},
+  tim: null,
+  getSysNotice() {
+    request.get('/email/my').then((res) => {
+      now({ sysNoticeList: res });
     });
-
-    tim.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, function (event) {
-      // 收到会话列表更新通知,可通过遍历 event.data 获取会话列表数据并渲染到页面
-      // event.name - TIM.EVENT.CONVERSATION_LIST_UPDATED
-      // event.data - 存储 Conversation 对象的数组 - [Conversation]
-    });
-
-    tim.on(TIM.EVENT.GROUP_LIST_UPDATED, function (event) {
-      // 收到群组列表更新通知,可通过遍历 event.data 获取群组列表数据并渲染到页面
-      // event.name - TIM.EVENT.GROUP_LIST_UPDATED
-      // event.data - 存储 Group 对象的数组 - [Group]
-    });
-
-    tim.on(TIM.EVENT.PROFILE_UPDATED, function (event) {
-      // 收到自己或好友的资料变更通知
-      // event.name - TIM.EVENT.PROFILE_UPDATED
-      // event.data - 存储 Profile 对象的数组 - [Profile]
-    });
-
-    tim.on(TIM.EVENT.BLACKLIST_UPDATED, function (event) {
-      // 收到黑名单列表更新通知
-      // event.name - TIM.EVENT.BLACKLIST_UPDATED
-      // event.data - 存储 userID 的数组 - [userID]
-    });
-
-    tim.on(TIM.EVENT.ERROR, function (event) {
-      // 收到 SDK 发生错误通知,可以获取错误码和错误信息
-      // event.name - TIM.EVENT.ERROR
-      // event.data.code - 错误码
-      // event.data.message - 错误信息
-    });
-
-    tim.on(TIM.EVENT.SDK_NOT_READY, function (event) {
-      // 收到 SDK 进入 not ready 状态通知,此时 SDK 无法正常工作
-      // event.name - TIM.EVENT.SDK_NOT_READY
-    });
-
-    tim.on(TIM.EVENT.KICKED_OUT, function (event) {
-      // 收到被踢下线通知
-      // event.name - TIM.EVENT.KICKED_OUT
-      // event.data.type - 被踢下线的原因,例如 :
-      //   - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢
-      //   - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢
-      //   - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢(v2.4.0起支持)。
-    });
-
-    tim.on(TIM.EVENT.NET_STATE_CHANGE, function (event) {
-      // 网络状态发生改变(v2.5.0 起支持)。
-      // event.name - TIM.EVENT.NET_STATE_CHANGE
-      // event.data.state 当前网络状态,枚举值及说明如下:
-      //   - TIM.TYPES.NET_STATE_CONNECTED - 已接入网络
-      //   - TIM.TYPES.NET_STATE_CONNECTING - 连接中。很可能遇到网络抖动,SDK 在重试。接入侧可根据此状态提示“当前网络不稳定”或“连接中”
-      //   - TIM.TYPES.NET_STATE_DISCONNECTED - 未接入网络。接入侧可根据此状态提示“当前网络不可用”。SDK 仍会继续重试,若用户网络恢复,SDK 会自动同步消息
-    });
-
-    // 开始登录
-    tim.login({
-      userID,
-      userSig,
+  },
+  getChat() {
+    request.get('/chat/my').then((res) => {
+      if (res) {
+        now({ chatList: res });
+      }
     });
   },
+  initChat() {
+    const { getSysNotice, getChat, getUserSig } = now();
+    getUserSig();
+    getSysNotice();
+    getChat();
+  },
+  getUserSig() {
+    const { id } = now(User);
+    request
+      .get('/chat/getUserSig', {
+        params: {
+          userId: id,
+        },
+      })
+      .then((res) => {
+        now({
+          userSig: res,
+          userID: id,
+        });
+      });
+  },
+  updateChatInfo(info) {
+    now({ chatInfo: info });
+  },
+  sendMessage(content, receiveUserId) {
+    const { id } = now(User);
+    request
+      .post('/chat/save', {
+        data: {
+          sendUserId: id,
+          receiveUserId,
+          content,
+        },
+      })
+      .then((res) => {
+        const { timSend } = now();
+        timSend(content, receiveUserId);
+      });
+  },
+  setTim(tim) {
+    now({ tim });
+  },
+  timSend(text, toUserId) {
+    const { tim } = now();
+    if (tim) tim.injectJavaScript(`window.sendMessage(${text},${toUserId})`);
+  },
 });
 
 export default IM;

+ 93 - 0
order/OrderCom.tsx

@@ -0,0 +1,93 @@
+import * as React from 'react';
+import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
+
+export default function OrderCom({ info, goDetail, receiverOrder, goMap }) {
+  const {
+    user,
+    userAddress,
+    merchant,
+    riderStatus,
+    timeOfArrival,
+    deliveryAmount,
+  } = info;
+
+  return (
+    <Button bg="white" p={0} block mb={15} onPress={goDetail}>
+      <Div flex={1}>
+        <Div px={10} py={15}>
+          <Div row alignItems="center">
+            <Text fontSize="xl" color="red500" fontWeight="bold">
+              43分钟内
+            </Text>
+            <Text fontSize="xl">送达</Text>
+            <Text
+              fontSize="xl"
+              color="red500"
+              fontWeight="bold"
+              flex={1}
+              textAlign="right"
+            >
+              {deliveryAmount}
+            </Text>
+          </Div>
+          <Div row mt={10}>
+            <Text fontSize="sm" color="gray600">
+              1.5Km
+            </Text>
+            <Div flex={1} ml={12}>
+              <Text fontSize="sm" pb={3}>
+                {merchant.showName}
+              </Text>
+              <Text fontSize="xs">{merchant.address}</Text>
+            </Div>
+          </Div>
+          <Div row mt={10}>
+            <Text fontSize="sm" color="gray600">
+              1.5Km
+            </Text>
+            <Div flex={1} ml={12}>
+              {user.nickName && (
+                <Text fontSize="sm" pb={5}>
+                  {user.nickName}
+                </Text>
+              )}
+
+              <Text fontSize="xs">{userAddress}</Text>
+            </Div>
+          </Div>
+        </Div>
+        {riderStatus === 'NOT_RECEIVED' && (
+          <Button block mx={15} mb={20} bg="yellow500" onPress={receiverOrder}>
+            接单
+          </Button>
+        )}
+
+        {riderStatus != 'NOT_RECEIVED' && (
+          <Div row mx={15} mb={20}>
+            <Button
+              flex={1}
+              color="black"
+              bg="white"
+              borderColor="yellow500"
+              borderWidth={1}
+              onPress={goMap}
+            >
+              查看导航
+            </Button>
+            {riderStatus === 'RECEIVED' && (
+              <Button ml={20} flex={1} bg="yellow500" onPress={receiverOrder}>
+                我已到店
+              </Button>
+            )}
+
+            {riderStatus === 'ARRIVE' && (
+              <Button ml={20} flex={1} bg="yellow500" onPress={receiverOrder}>
+                拍照取货
+              </Button>
+            )}
+          </Div>
+        )}
+      </Div>
+    </Button>
+  );
+}

+ 179 - 0
order/OrderDetailScreen.tsx

@@ -0,0 +1,179 @@
+import { StackScreenProps } from '@react-navigation/stack';
+import * as React from 'react';
+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';
+
+export default function OrderDetailScreen({
+  navigation,
+  route,
+}: StackScreenProps) {
+  const { params } = route;
+  const { orderId } = params;
+
+  const { data, loading, reload } = useRequest(`/orderInfo/get/${orderId}`, {
+    defaultLoading: false,
+    debounceInterval: 1000,
+    initialData: {},
+  });
+
+  const orderGoodsSpecs = useCreation(() => {
+    return data.orderGoodsSpecs || [];
+  }, [data]);
+
+  const totalNum = useCreation(() => {
+    return orderGoodsSpecs.reduce((total, currentValue) => {
+      return total + currentValue.num;
+    }, 0);
+  }, [orderGoodsSpecs]);
+
+  return (
+    <Div bg="gray100" flex={1}>
+      {data.merchantStatus && data.merchantStatus !== 'NOT_RECEIVED' && (
+        <Div row bg="white" py={12}>
+          <Div flex={1} alignItems="center">
+            <Text fontSize="xl" color="red500">
+              {data.deliveryAmount}
+            </Text>
+            <Text fontSize="sm" color="gray600">
+              本单派送收入
+            </Text>
+          </Div>
+          <Div w={1} bg="gray100" />
+          <Div flex={1} alignItems="center">
+            <Text fontSize="xl" color="red500">
+              {data.timeOfArrival}
+            </Text>
+            <Text fontSize="sm" color="gray600">
+              预计送达时间
+            </Text>
+          </Div>
+        </Div>
+      )}
+
+      <ScrollView
+        contentContainerStyle={{
+          flexGrow: 1,
+          backgroundColor: '#f2f2f2',
+          paddingHorizontal: 15,
+          paddingVertical: 10,
+        }}
+        refreshControl={
+          <RefreshControl refreshing={loading} onRefresh={reload} />
+        }
+      >
+        {data.id && (
+          <Div bg="white" rounded="xs" px={15} py={10}>
+            {data.riderStatus !== 'NOT_RECEIVED' &&
+              data.riderStatus !== 'TAKE_MEAL' && (
+                <Div row py={10}>
+                  <Div flex={1}>
+                    <Text>我已到店</Text>
+                    <Text fontSize="sm" color="gray600" mt={2}>
+                      流水号:{data.id}
+                    </Text>
+                  </Div>
+                  <Button
+                    bg="yellow500"
+                    w={112}
+                    disabled={data.riderStatus != 'RECEIVED'}
+                  >
+                    我已到店
+                  </Button>
+                </Div>
+              )}
+
+            {data.riderStatus === 'ARRIVE' && (
+              <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}>
+                  拍照取货
+                </Button>
+              </Div>
+            )}
+
+            {data.riderStatus !== 'NOT_RECEIVED' && (
+              <Div borderTopColor="gray100" borderTopWidth={1} py={10}>
+                <Text fontSize="sm">商家信息</Text>
+                <Div px={10} mt={10}>
+                  <Text fontSize="sm">{data.merchantShowName}</Text>
+                  <Text fontSize="sm" mt={5}>
+                    {data.merchantShowName}
+                  </Text>
+                </Div>
+                <Button block bg="yellow500" mt={15}>
+                  联系商家
+                </Button>
+              </Div>
+            )}
+            {data.riderStatus !== 'NOT_RECEIVED' && (
+              <Div py={15}>
+                <Div row mt={10}>
+                  <Text fontSize="sm" color="gray600">
+                    1.5Km
+                  </Text>
+                  <Div flex={1} ml={12}>
+                    <Text fontSize="md" pb={3}>
+                      {data.merchantShowName}
+                    </Text>
+                    <Text fontSize="sm">{data.merchantShowName}</Text>
+                  </Div>
+                </Div>
+                <Div row mt={10}>
+                  <Text fontSize="sm" color="gray600">
+                    1.5Km
+                  </Text>
+                  <Div flex={1} ml={12}>
+                    {data.nickName && (
+                      <Text fontSize="md" pb={5}>
+                        {data.nickName}
+                      </Text>
+                    )}
+                    <Text fontSize="sm">{data.userAddress}</Text>
+                  </Div>
+                </Div>
+              </Div>
+            )}
+
+            <Div borderTopColor="gray100" borderTopWidth={1} py={10}>
+              <Div row>
+                <Text fontSize="sm" flex={2}>
+                  商品信息
+                </Text>
+                <Text fontSize="sm" flex={1} textAlign="right">
+                  {totalNum}份
+                </Text>
+                <Text fontSize="sm" flex={1} color="red500" textAlign="right">
+                  ¥{data.totalAmount || 0}
+                </Text>
+              </Div>
+
+              <Div p={15}>
+                {orderGoodsSpecs.map((item) => {
+                  const goods = item.goods;
+                  return (
+                    <Div row key={item.id} mt={5}>
+                      <Text fontSize="sm"> {goods.name}</Text>
+                      <Text fontSize="sm" color="gray500" ml={5}>
+                        {item.specification}
+                      </Text>
+                      <Text fontSize="sm" flex={1} textAlign="right">
+                        X {item.num}
+                      </Text>
+                    </Div>
+                  );
+                })}
+              </Div>
+            </Div>
+          </Div>
+        )}
+      </ScrollView>
+    </Div>
+  );
+}

+ 121 - 8
order/OrderScreen.tsx

@@ -1,21 +1,134 @@
 import { StackScreenProps } from '@react-navigation/stack';
 import * as React from 'react';
+import { RefreshControl } from 'react-native';
 import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
-import { ScrollView } from 'react-native-gesture-handler';
+import { FlatList } from 'react-native-gesture-handler';
+import Constants from 'expo-constants';
+import TimScreen from '../notice/TimScreen';
+
+import useModel from 'flooks';
+import Map from '../map/model';
+import OrderModel from './model';
+import { useMount, useRequest, useCreation } from 'ahooks';
+import { useTranslation } from 'react-i18next';
+
+import moment from 'moment';
+
+import { promot } from '../utils/SystemUtils';
+import { orderRiderStatus } from '../utils/RiderInfoUtils';
+import request from '../utils/RequestUtils';
+import { toastSuccess } from '../utils/SystemUtils';
+
+import OrderCom from './OrderCom';
 
 export default function OrderScreen({ navigation }: StackScreenProps) {
+  const { t } = useTranslation();
+  const { locationInfo, getNowLocation } = useModel(Map, ['locationInfo']);
+
+  const { receiverOrder } = useModel(OrderModel, []);
+
+  const [chooseStatus, setChooseStatus] = React.useState<string>('RECEIVED');
+  useMount(() => {
+    getNowLocation();
+  });
+  const { addressName } = locationInfo;
+
+  const chooseStatusInfo = useCreation(() => {
+    return orderRiderStatus.get(chooseStatus);
+  }, [chooseStatus]);
+
+  const { data, loading, reload } = useRequest(
+    () => {
+      return request.get(chooseStatusInfo.requestUrl, {
+        params: chooseStatusInfo.params,
+      });
+    },
+    {
+      refreshDeps: [chooseStatusInfo],
+      formatResult: chooseStatusInfo.formatResult,
+      defaultLoading: false,
+      debounceInterval: 1000,
+    }
+  );
+
   return (
-    <Div bg="gray100">
-      <ScrollView
+    <Div bg="gray100" flex={1}>
+      <Div
+        pt={Constants.statusBarHeight + 11}
+        pb={11}
+        bg="yellow500"
+        row
+        alignItems="center"
+        px={14}
+        px={15}
+      >
+        <Image w={50} h={50} source={require('../assets/images/logo.png')} />
+        <Text fontSize="xl" color="white" mr={50} textAlign="center" flex={1}>
+          骑手客户端
+        </Text>
+      </Div>
+      <Div row>
+        {[...orderRiderStatus.keys()].map((item) => {
+          const info = orderRiderStatus.get(item);
+          return (
+            <Button
+              key={item}
+              flex={1}
+              bg="transparent"
+              color={chooseStatus === item ? 'yellow500' : 'black'}
+              fontSize="lg"
+              py={15}
+              onPress={() => setChooseStatus(item)}
+            >
+              {t(info.name)}
+            </Button>
+          );
+        })}
+      </Div>
+
+      <FlatList
+        renderItem={({ item }) => {
+          return (
+            <OrderCom
+              info={item}
+              goDetail={() =>
+                navigation.navigate('OrderStack', {
+                  screen: 'OrderDetail',
+                  params: {
+                    orderId: item.id,
+                  },
+                })
+              }
+              receiverOrder={() => {
+                receiverOrder(item.id, (res) => {
+                  toastSuccess('接单成功');
+                });
+              }}
+              goMap={() =>
+                navigation.navigate('OrderStack', {
+                  screen: 'OrderMap',
+                  params: {
+                    orderId: item.id,
+                  },
+                })
+              }
+            />
+          );
+        }}
+        data={data}
         contentContainerStyle={{
           flexGrow: 1,
+          paddingHorizontal: 15,
           backgroundColor: '#f2f2f2',
         }}
-      >
-        <Div>
-          <Text></Text>
-        </Div>
-      </ScrollView>
+        refreshControl={
+          <RefreshControl refreshing={loading} onRefresh={reload} />
+        }
+      />
+
+      <Div position="absolute" w={0} h={0} bottom={0} left={0} zIndex={0}>
+        <TimScreen />
+      </Div>
     </Div>
   );
 }

+ 25 - 0
order/model.ts

@@ -0,0 +1,25 @@
+import request from '../utils/RequestUtils';
+import { toastShow, toastInfo, toastSuccess } from '../utils/SystemUtils';
+
+const OrderMap = (now, successEvent) => ({
+  receiverOrder(orderId) {
+    toastShow();
+    request
+      .get('/rider/receiver', {
+        params: {
+          orderId,
+          pass: true,
+        },
+      })
+      .then((res) => {
+        if (successEvent) {
+          successEvent(res);
+        }
+      })
+      .catch((e) => {
+        toastInfo(e.error);
+      });
+  },
+});
+
+export default OrderMap;

+ 82 - 5
package-lock.json

@@ -1310,6 +1310,25 @@
         }
       }
     },
+    "@expo/react-native-action-sheet": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/@expo/react-native-action-sheet/-/react-native-action-sheet-3.8.0.tgz",
+      "integrity": "sha512-tCfwysuqy0sfaN+aA98IKUrwCLKsbDHSYLcnHrx9wNbawOHNez8rSeFtieAS48/HyrPI75yg/ZGvxe6UsJRS8Q==",
+      "requires": {
+        "@types/hoist-non-react-statics": "^3.3.1",
+        "hoist-non-react-statics": "^3.3.0"
+      },
+      "dependencies": {
+        "hoist-non-react-statics": {
+          "version": "3.3.2",
+          "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+          "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+          "requires": {
+            "react-is": "^16.7.0"
+          }
+        }
+      }
+    },
     "@expo/vector-icons": {
       "version": "10.2.0",
       "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-10.2.0.tgz",
@@ -3317,6 +3336,25 @@
       "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.36.tgz",
       "integrity": "sha512-7TUK/k2/QGpEAv/BCwSHlYu3NXZhQ9ZwBYpzr9tjlPIL2C5BeGhH3DmVavRx3ZNyELX5TLC91JTz/cen6AAtIQ=="
     },
+    "@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "requires": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      },
+      "dependencies": {
+        "hoist-non-react-statics": {
+          "version": "3.3.2",
+          "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+          "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+          "requires": {
+            "react-is": "^16.7.0"
+          }
+        }
+      }
+    },
     "@types/istanbul-lib-coverage": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
@@ -3366,14 +3404,12 @@
     "@types/prop-types": {
       "version": "15.7.3",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
-      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
-      "dev": true
+      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
     },
     "@types/react": {
       "version": "16.9.43",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.43.tgz",
       "integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==",
-      "dev": true,
       "requires": {
         "@types/prop-types": "*",
         "csstype": "^2.2.0"
@@ -4811,8 +4847,7 @@
     "csstype": {
       "version": "2.6.11",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz",
-      "integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw==",
-      "dev": true
+      "integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw=="
     },
     "currency-codes": {
       "version": "1.5.1",
@@ -12823,6 +12858,11 @@
         "use-subscription": "^1.0.0"
       }
     },
+    "react-native-communications": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/react-native-communications/-/react-native-communications-2.2.1.tgz",
+      "integrity": "sha1-eIO1ayCgAu63kMET+GFuqGksp5U="
+    },
     "react-native-gesture-handler": {
       "version": "1.6.1",
       "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.6.1.tgz",
@@ -12834,6 +12874,22 @@
         "prop-types": "^15.7.2"
       }
     },
+    "react-native-gifted-chat": {
+      "version": "0.16.3",
+      "resolved": "https://registry.npmjs.org/react-native-gifted-chat/-/react-native-gifted-chat-0.16.3.tgz",
+      "integrity": "sha512-7EJKQPzzg1yIbLFNq9n5bGJWZ7Woi2bTeT7M4EVSChmFF/qyNos+gFxEcafPkEihEeIxeOne6hBQlYNKmDABgA==",
+      "requires": {
+        "@expo/react-native-action-sheet": "^3.6.0",
+        "dayjs": "^1.8.26",
+        "prop-types": "^15.7.2",
+        "react-native-communications": "^2.2.1",
+        "react-native-iphone-x-helper": "^1.2.1",
+        "react-native-lightbox": "^0.8.1",
+        "react-native-parsed-text": "0.0.22",
+        "react-native-typing-animation": "^0.1.7",
+        "uuid": "3.4.0"
+      }
+    },
     "react-native-iphone-x-helper": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.2.1.tgz",
@@ -12883,6 +12939,14 @@
         }
       }
     },
+    "react-native-lightbox": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/react-native-lightbox/-/react-native-lightbox-0.8.1.tgz",
+      "integrity": "sha512-TFZA6iKEEHpAUIXjMTRb6vx0/9rHgEKy3ZBiRAy295PwldYg5c8opwnbyURLIl522ykeqhVx9uGdXjSMIowLvA==",
+      "requires": {
+        "prop-types": "^15.7.2"
+      }
+    },
     "react-native-magnus": {
       "version": "1.0.40",
       "resolved": "https://registry.npmjs.org/react-native-magnus/-/react-native-magnus-1.0.40.tgz",
@@ -12906,6 +12970,14 @@
         "react-native-animatable": "1.3.3"
       }
     },
+    "react-native-parsed-text": {
+      "version": "0.0.22",
+      "resolved": "https://registry.npmjs.org/react-native-parsed-text/-/react-native-parsed-text-0.0.22.tgz",
+      "integrity": "sha512-hfD83RDXZf9Fvth3DowR7j65fMnlqM9PpxZBGWkzVcUTFtqe6/yPcIoIAgrJbKn6YmtzkivmhWE2MCE4JKBXrQ==",
+      "requires": {
+        "prop-types": "^15.7.x"
+      }
+    },
     "react-native-reanimated": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-1.9.0.tgz",
@@ -12929,6 +13001,11 @@
       "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-2.15.0.tgz",
       "integrity": "sha512-rCQPNp0N4t2IZHTVpdb/eddJ9kTLC8QlD/8Ce1+z2Fk3Evk0HPhuhTAW3mfa+thzRXkXYxxsS7QcIjJKs2Wu3w=="
     },
+    "react-native-typing-animation": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/react-native-typing-animation/-/react-native-typing-animation-0.1.7.tgz",
+      "integrity": "sha512-4H3rF9M+I2yAZpYJcY0Mb29TXkn98QK12rrKSY6LZj1BQD9NNmRZuNXzwX4XHapsIz+N/J8M3p27FOQPbfzqeg=="
+    },
     "react-native-vector-icons": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-7.0.0.tgz",

+ 1 - 0
package.json

@@ -49,6 +49,7 @@
     "react-native": "https://github.com/expo/react-native/archive/sdk-38.0.2.tar.gz",
     "react-native-animatable": "^1.3.3",
     "react-native-gesture-handler": "~1.6.0",
+    "react-native-gifted-chat": "^0.16.3",
     "react-native-magnus": "^1.0.40",
     "react-native-masked-text": "^1.13.0",
     "react-native-modal": "^11.5.6",

+ 1 - 2
stores/User.ts

@@ -10,7 +10,6 @@ import {
   toastInfo,
   toastSuccess,
 } from '../utils/SystemUtils';
-import IM from '../im/model';
 
 import i18n from '../i18n';
 
@@ -132,7 +131,7 @@ const user = (now) => ({
         } else if (res) {
           now({ initialRouteName: res });
         } else {
-          now({ initialRouteName: 'Main' });
+          now({ initialRouteName: 'MainStack' });
         }
       })
       .catch(() => {});

+ 51 - 1
utils/RiderInfoUtils.ts

@@ -40,4 +40,54 @@ const riderScore = new Map([
   [3, { name: 'chao-zan', img: require('../assets/images/appra1.png') }],
 ]);
 
-export { RiderMap, riderScore };
+const orderRiderStatus = new Map([
+  [
+    'NOT_RECEIVED',
+    {
+      name: 'wei-jie-dan',
+      requestUrl: '/orderInfo/riderReceived',
+      params: {},
+      formatResult: (res) => {
+        return res;
+      },
+    },
+  ],
+  [
+    'RECEIVED',
+    {
+      name: 'dai-qu-can',
+      requestUrl: '/orderInfo/my',
+      status: ['ARRIVE', 'RECEIVED'],
+      params: {
+        query: {
+          riderStatus: 'RECEIVED',
+        },
+      },
+      formatResult: (res) => {
+        return res.content;
+      },
+    },
+  ],
+  [
+    'TAKE_MEAL',
+    {
+      name: 'dai-song-da',
+      requestUrl: '/orderInfo/my',
+      params: {
+        query: {
+          riderStatus: 'TAKE_MEAL',
+        },
+      },
+      formatResult: (res) => {
+        return res;
+      },
+      formatResult: (res) => {
+        return res.content;
+      },
+    },
+  ],
+]);
+
+
+
+export { RiderMap, riderScore, orderRiderStatus };

+ 6 - 4
utils/SystemUtils.ts

@@ -24,6 +24,8 @@ function promot(
     title: '',
     submitEvent: (val) => {},
     hasCancel: true,
+    tips: '',
+    secureTextEntry: false,
   }
 ) {
   navigation.navigate('Modal', {
@@ -48,22 +50,22 @@ function alert(
 }
 
 function toastShow() {
-  if (Platform.OS === 'web') return;
+  if (__DEV__) return;
   ModalIndicator.show(i18n.t('jia-zai-zhong'));
 }
 function toastHide() {
-  if (Platform.OS === 'web') return;
+  if (__DEV__) return;
   ModalIndicator.hide();
 }
 
 function toastSuccess(title) {
   toastHide();
-  if (Platform.OS === 'web') return;
+  if (__DEV__) return;
   Toast.success(title);
 }
 function toastInfo(title) {
   toastHide();
-  if (Platform.OS === 'web') return;
+  if (__DEV__) return;
   Toast.message(title);
 }
 

+ 14 - 1
utils/TimeUtils.ts

@@ -35,4 +35,17 @@ class MonthDate {
   }
 }
 
-export { today, MonthDate, getSearchDate };
+function parse(date, formatStr = 'yyyy-MM-DD HH:mm:ss') {
+  return moment(date, formatStr);
+}
+
+function getChatTime(date, formatStr = 'yyyy-MM-DD HH:mm:ss') {
+  if (parse(date).format('yyyy-MM-DD') === moment().format('yyyy-MM-DD')) {
+    return parse(date).format('HH:mm');
+  } else {
+    return parse(date).format('MM-DD HH:mm');
+  }
+}
+
+
+export { today, MonthDate, getSearchDate, parse, getChatTime };

+ 1 - 1
wallet/BankCardScreen.tsx

@@ -14,7 +14,7 @@ export default function BankCardScreen({ navigation }: StackScreenProps) {
   const { data, loading } = useRequest('/bankCard/my', {
     formatResult: (response) => response.content,
     initialData: [],
-    defaultLoading: true,
+    defaultLoading: false,
   });
 
   navigation.setOptions({

+ 1 - 1
wallet/MineRecordScreen.tsx

@@ -65,7 +65,7 @@ export default function MineRecordScreen({ navigation }: StackScreenProps) {
           return false;
         }
       },
-      defaultLoading: true,
+      defaultLoading: false,
       debounceInterval: 1000,
       loadMore: true,
     }

+ 1 - 1
wallet/MineWalletScreen.tsx

@@ -35,7 +35,7 @@ export default function MineWalletScreen({
     {
       formatResult: (response) => response.content,
       initialData: [],
-      defaultLoading: true,
+      defaultLoading: false,
     }
   );
 

+ 1 - 1
wallet/WithdrawResultScreen.tsx

@@ -21,7 +21,7 @@ export default function WithdrawResultScreen({
   const { params } = route;
   const { id } = params || {};
   const { data, loading, refresh } = useRequest('/withdrawApply/get/' + id, {
-    defaultLoading: true,
+    defaultLoading: false,
   });
 
   const statusInfo = useCreation(() => {