panhui пре 5 година
родитељ
комит
c9eebff680

+ 3 - 0
App.tsx

@@ -15,6 +15,7 @@ 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();
@@ -25,6 +26,8 @@ export default function App() {
     'initialRouteName',
   ]);
 
+  const { messages } = useModel(IM, ['messages']);
+
   const { loading, run } = useRequest(getInit, {
     refreshDeps: [id],
     debounceInterval: 2000,

+ 42 - 40
app.json

@@ -1,42 +1,44 @@
 {
-    "expo": {
-        "name": "DingdongRider",
-        "slug": "DingdongRider",
-        "version": "1.0.0",
-        "orientation": "portrait",
-        "icon": "./assets/images/icon.png",
-        "scheme": "myapp",
-        "userInterfaceStyle": "automatic",
-        "splash": {
-            "image": "./assets/images/splash.png",
-            "resizeMode": "contain",
-            "backgroundColor": "#FFC21C"
-        },
-        "updates": {
-            "fallbackToCacheTimeout": 0
-        },
-        "assetBundlePatterns": ["**/*"],
-        "ios": {
-            "supportsTablet": true,
-            "bundleIdentifier": "com.izouma.dingdongRider",
-            "buildNumber": "1.0.0",
-            "infoPlist": {
-                "UIBackgroundModes": ["audio", "location", "fetch"]
-            }
-        },
-        "android": {
-            "package": "com.izouma.dingdongRider",
-            "versionCode": 1,
-            "permissions": [
-                "ACCESS_COARSE_LOCATION",
-                "ACCESS_FINE_LOCATION",
-                "CAMERA",
-                "READ_EXTERNAL_STORAGE",
-                "WRITE_EXTERNAL_STORAGE"
-            ]
-        },
-        "web": {
-            "favicon": "./assets/images/favicon.png"
-        }
-    }
+  "expo": {
+    "name": "DingdongRider",
+    "slug": "DingdongRider",
+    "version": "1.0.0",
+    "orientation": "portrait",
+    "icon": "./assets/images/icon.png",
+    "scheme": "myapp",
+    "userInterfaceStyle": "automatic",
+    "splash": {
+      "image": "./assets/images/splash.png",
+      "resizeMode": "contain",
+      "backgroundColor": "#FFC21C"
+    },
+    "updates": {
+      "fallbackToCacheTimeout": 0
+    },
+    "assetBundlePatterns": ["**/*"],
+    "ios": {
+      "supportsTablet": true,
+      "bundleIdentifier": "com.izouma.dingdongRider",
+      "buildNumber": "1.0.0",
+      "infoPlist": {
+        "UIBackgroundModes": ["audio", "location", "fetch"]
+      }
+    },
+    "android": {
+      "package": "com.izouma.dingdongRider",
+      "versionCode": 1,
+      "permissions": [
+        "ACCESS_COARSE_LOCATION",
+        "ACCESS_FINE_LOCATION",
+        "CAMERA",
+        "READ_EXTERNAL_STORAGE",
+        "WRITE_EXTERNAL_STORAGE"
+      ],
+      "useNextNotificationsApi": true
+    },
+    "web": {
+      "favicon": "./assets/images/favicon.png"
+    },
+    "description": "叮咚外卖骑手端"
+  }
 }

BIN
assets/images/autoimg2.png


+ 1 - 1
constants/Colors.ts

@@ -1,4 +1,4 @@
-const tintColorLight = '#2f95dc';
+const tintColorLight = '#FFC21C';
 const tintColorDark = '#fff';
 
 export default {

+ 21 - 21
hooks/useCachedResources.ts

@@ -4,29 +4,29 @@ import * as SplashScreen from 'expo-splash-screen';
 import * as React from 'react';
 
 export default function useCachedResources() {
-    const [isLoadingComplete, setLoadingComplete] = React.useState(false);
+  const [isLoadingComplete, setLoadingComplete] = React.useState(false);
 
-    // Load any resources or data that we need prior to rendering the app
-    React.useEffect(() => {
-        async function loadResourcesAndDataAsync() {
-            try {
-                SplashScreen.preventAutoHideAsync();
+  // Load any resources or data that we need prior to rendering the app
+  React.useEffect(() => {
+    async function loadResourcesAndDataAsync() {
+      try {
+        SplashScreen.preventAutoHideAsync();
 
-                // Load fonts
-                await Font.loadAsync({
-                    ...Ionicons.font,
-                    'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf')
-                });
-            } catch (e) {
-                // We might want to provide this error information to an error reporting service
-                console.warn(e);
-            } finally {
-                setLoadingComplete(true);
-            }
-        }
+        // Load fonts
+        await Font.loadAsync({
+          ...Ionicons.font,
+          'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'),
+        });
+      } catch (e) {
+        // We might want to provide this error information to an error reporting service
+        console.warn(e);
+      } finally {
+        setLoadingComplete(true);
+      }
+    }
 
-        loadResourcesAndDataAsync();
-    }, []);
+    loadResourcesAndDataAsync();
+  }, []);
 
-    return isLoadingComplete;
+  return isLoadingComplete;
 }

+ 118 - 0
im/model.ts

@@ -0,0 +1,118 @@
+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;

+ 3 - 1
locales/zh-CN.json

@@ -61,5 +61,7 @@
   "qi-shou-shen-he": "骑手审核",
   "xuan-ze-gong-zuo-di-dian": "选择工作地点",
   "song-can-jiao-tong-gong-ju-xin-xi": "送餐交通工具信息",
-  "shen-fen-ren-zheng-xin-xi": "身份认证信息"
+  "shen-fen-ren-zheng-xin-xi": "身份认证信息",
+  "gong-xi-nin-de-shen-qing-yi-tong-guo": "恭喜!!!您的申请已通过",
+  "nin-de-gong-hao-wei": "您的工号为"
 }

+ 32 - 4
login/AuditResultScreen.tsx

@@ -1,5 +1,6 @@
-import { StackScreenProps } from '@react-navigation/stack';
 import * as React from 'react';
+import { StackScreenProps } from '@react-navigation/stack';
+import { StackActions } from '@react-navigation/native';
 import { RefreshControl } from 'react-native';
 import { Div, Button, Image, Text, Avatar } from 'react-native-magnus';
 import { ScrollView } from 'react-native-gesture-handler';
@@ -14,15 +15,16 @@ import {
 } from '../utils/AsyncStorageUtils';
 
 const img1 = require('../assets/images/autoimg1.png');
+const img2 = require('../assets/images/autoimg2.png');
 
 export default function AuditResultScreen({ navigation }: StackScreenProps) {
   const { t } = useTranslation();
   const { data, refresh, loading } = useRequest('/rider/my');
-  const { status } = data || {};
+  const { status, jobNumber } = data || {};
 
   React.useEffect(() => {
     if (status === 'PENDING') {
-      addAsyncStorage('riderIsApply', true);
+      addAsyncStorage('riderIsApply', 'true');
     }
   }, [status]);
   return (
@@ -37,7 +39,7 @@ export default function AuditResultScreen({ navigation }: StackScreenProps) {
           <RefreshControl refreshing={loading} onRefresh={refresh} />
         }
       >
-        <Image source={img1} w={91} h={78} mt={40} />
+        <Image source={status === 'PASS' ? img2 : img1} w={91} h={78} mt={40} />
         {status === 'PENDING' && (
           <Div alignItems="center" py={30}>
             <Text color="gray600" fontSize="xl">
@@ -74,6 +76,32 @@ export default function AuditResultScreen({ navigation }: StackScreenProps) {
           </>
         )}
 
+        {status === 'PASS' && (
+          <>
+            <Div alignItems="center" py={30}>
+              <Text color="yellow500" fontSize="xl">
+                {t('gong-xi-nin-de-shen-qing-yi-tong-guo')}
+              </Text>
+              <Text color="yellow500" fontSize="xl">
+                {t('nin-de-gong-hao-wei')}:{jobNumber}
+              </Text>
+            </Div>
+
+            <Button
+              bg="yellow500"
+              fontSize="sm"
+              w={112}
+              alignSelf="center"
+              onPress={() => {
+                removeAsyncStorage('riderIsApply');
+                navigation.dispatch(StackActions.replace('Root'));
+              }}
+            >
+              完成
+            </Button>
+          </>
+        )}
+
         <Div flex={1} w={10} />
         <Button
           w={112}

+ 1 - 1
login/RegisterScreen.tsx

@@ -21,7 +21,7 @@ import Login from './model';
 
 import { MainStackParamList } from '../types';
 import { connect } from '../utils/SystemUtils';
-import Navigation from '../navigation/MainStackNavigator';
+import Navigation from '../navigation/LoginStackNavigator';
 export default function RegisterScreen({
   navigation,
 }: StackScreenProps<MainStackParamList, 'Login'>) {

+ 22 - 0
mine/MineScreen.tsx

@@ -0,0 +1,22 @@
+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 { RootStackParamList } from '../types';
+
+export default function RegisterScreen({
+  navigation,
+}: StackScreenProps<RootStackParamList, 'Login'>) {
+  return (
+    <Div bg="gray100">
+      <ScrollView
+        contentContainerStyle={{ flexGrow: 1, backgroundColor: '#f2f2f2' }}
+      >
+        <Div>
+          <Text></Text>
+        </Div>
+      </ScrollView>
+    </Div>
+  );
+}

+ 0 - 78
navigation/BottomTabNavigator.tsx

@@ -1,78 +0,0 @@
-import { Ionicons } from '@expo/vector-icons';
-import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
-import { createStackNavigator } from '@react-navigation/stack';
-import * as React from 'react';
-
-import Colors from '../constants/Colors';
-import useColorScheme from '../hooks/useColorScheme';
-import TabOneScreen from '../screens/TabOneScreen';
-import TabTwoScreen from '../screens/TabTwoScreen';
-import { BottomTabParamList, TabOneParamList, TabTwoParamList } from '../types';
-
-const BottomTab = createBottomTabNavigator<BottomTabParamList>();
-
-export default function BottomTabNavigator() {
-  const colorScheme = useColorScheme();
-
-  return (
-    <BottomTab.Navigator
-      initialRouteName="TabOne"
-      tabBarOptions={{ activeTintColor: Colors[colorScheme].tint }}
-    >
-      <BottomTab.Screen
-        name="TabOne"
-        component={TabOneNavigator}
-        options={{
-          tabBarIcon: ({ color }) => (
-            <TabBarIcon name="ios-code" color={color} />
-          ),
-        }}
-      />
-      <BottomTab.Screen
-        name="TabTwo"
-        component={TabTwoNavigator}
-        options={{
-          tabBarIcon: ({ color }) => (
-            <TabBarIcon name="ios-code" color={color} />
-          ),
-        }}
-      />
-    </BottomTab.Navigator>
-  );
-}
-
-// You can explore the built-in icon families and icons on the web at:
-// https://icons.expo.fyi/
-function TabBarIcon(props: { name: string; color: string }) {
-  return <Ionicons size={30} style={{ marginBottom: -3 }} {...props} />;
-}
-
-// Each tab has its own navigation stack, you can read more about this pattern here:
-// https://reactnavigation.org/docs/tab-based-navigation#a-stack-navigator-for-each-tab
-const TabOneStack = createStackNavigator<TabOneParamList>();
-
-function TabOneNavigator() {
-  return (
-    <TabOneStack.Navigator>
-      <TabOneStack.Screen
-        name="TabOneScreen"
-        component={TabOneScreen}
-        options={{ headerTitle: 'Tab One Title' }}
-      />
-    </TabOneStack.Navigator>
-  );
-}
-
-const TabTwoStack = createStackNavigator<TabTwoParamList>();
-
-function TabTwoNavigator() {
-  return (
-    <TabTwoStack.Navigator>
-      <TabTwoStack.Screen
-        name="TabTwoScreen"
-        component={TabTwoScreen}
-        options={{ headerTitle: 'Tab Two Title' }}
-      />
-    </TabTwoStack.Navigator>
-  );
-}

+ 15 - 2
navigation/LinkingConfiguration.ts

@@ -4,7 +4,21 @@ export default {
   prefixes: [Linking.makeUrl('/')],
   config: {
     screens: {
-      Root: {
+      Main: {
+        screens: {
+          TabOne: {
+            screens: {
+              TabOneScreen: 'one',
+            },
+          },
+          TabTwo: {
+            screens: {
+              TabTwoScreen: 'two',
+            },
+          },
+        },
+      },
+      Login: {
         screens: {
           TabOne: {
             screens: {
@@ -18,7 +32,6 @@ export default {
           },
         },
       },
-      Login: '*',
       NotFound: '*',
     },
   },

+ 7 - 11
navigation/MainStackNavigator.tsx → navigation/LoginStackNavigator.tsx

@@ -23,13 +23,12 @@ import AuditResultScreen from '../login/AuditResultScreen';
 //地图模块
 import SearchMapScreen from '../map/SearchMapScreen';
 
-import { RootStackParamList } from '../types';
-import BottomTabNavigator from './BottomTabNavigator';
+import { LoginStackParamList } from '../types';
 import LinkingConfiguration from './LinkingConfiguration';
 
 import User from '../stores/User';
 
-const MainStack = createStackNavigator<RootStackParamList>();
+const MainStack = createStackNavigator<LoginStackParamList>();
 export default function Navigation({
   colorScheme,
 }: {
@@ -39,11 +38,13 @@ export default function Navigation({
   const { t } = useTranslation();
   return (
     <MainStack.Navigator
-      initialRouteName={initialRouteName}
+      initialRouteName={
+        initialRouteName !== 'Root' ? initialRouteName : 'Login'
+      }
       screenOptions={{
         cardOverlayEnabled: true,
-        cardStyle: { backgroundColor: '#eee', flex: 1 },
-        contentStyle: { backgroundColor: '#eee', flex: 1 },
+        cardStyle: { backgroundColor: '#f2f2f2', flex: 1 },
+        contentStyle: { backgroundColor: '#f2f2f2', flex: 1 },
         gestureEnabled: true,
         stackPresentation: 'push',
         cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
@@ -58,11 +59,6 @@ export default function Navigation({
         headerBackTitleVisible: false,
       }}
     >
-      <MainStack.Screen
-        name="Root"
-        component={BottomTabNavigator}
-        options={{ headerShown: false }}
-      />
       <MainStack.Screen
         name="Login"
         component={LoginScreen}

+ 82 - 0
navigation/MianTabNavigator.tsx

@@ -0,0 +1,82 @@
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { createStackNavigator } from '@react-navigation/stack';
+import * as React from 'react';
+
+import { Icon, Text } from 'react-native-magnus';
+import Colors from '../constants/Colors';
+import useColorScheme from '../hooks/useColorScheme';
+import OrderStackNavigator from './OrderStackNavigator';
+import NoticeStackNavigator from './NoticeStackNavigator';
+import MineStackNavigator from './MineStackNavigator';
+import { MainTabParamList } from '../types';
+
+const MainTab = createBottomTabNavigator<MainTabParamList>();
+
+export default function MainTabNavigator() {
+  const colorScheme = useColorScheme();
+
+  return (
+    <MainTab.Navigator
+      initialRouteName="Mine"
+      tabBarOptions={{ activeTintColor: Colors[colorScheme].tint }}
+    >
+      <MainTab.Screen
+        name="Order"
+        component={OrderStackNavigator}
+        options={{
+          tabBarIcon: ({ color }) => (
+            <Icon
+              name="clipboard"
+              fontFamily="Feather"
+              fontSize="5xl"
+              color={color}
+            />
+          ),
+          tabBarLabel: ({ focused }) => (
+            <Text fontSize="xs" color={focused ? 'yellow500' : 'black'}>
+              订单
+            </Text>
+          ),
+        }}
+      />
+      <MainTab.Screen
+        name="Notice"
+        component={NoticeStackNavigator}
+        options={{
+          tabBarIcon: ({ color }) => (
+            <Icon
+              name="message-circle"
+              fontSize="5xl"
+              fontFamily="Feather"
+              color={color}
+            />
+          ),
+          tabBarLabel: ({ focused }) => (
+            <Text fontSize="xs" color={focused ? 'yellow500' : 'black'}>
+              消息
+            </Text>
+          ),
+        }}
+      />
+      <MainTab.Screen
+        name="Mine"
+        component={MineStackNavigator}
+        options={{
+          tabBarIcon: ({ color }) => (
+            <Icon
+              name="user"
+              fontSize="5xl"
+              fontFamily="Feather"
+              color={color}
+            />
+          ),
+          tabBarLabel: ({ focused }) => (
+            <Text fontSize="xs" color={focused ? 'yellow500' : 'black'}>
+              我的
+            </Text>
+          ),
+        }}
+      />
+    </MainTab.Navigator>
+  );
+}

+ 54 - 0
navigation/MineStackNavigator.tsx

@@ -0,0 +1,54 @@
+import {
+  NavigationContainer,
+  DefaultTheme,
+  DarkTheme,
+} from '@react-navigation/native';
+import {
+  createStackNavigator,
+  CardStyleInterpolators,
+} from '@react-navigation/stack';
+import * as React from 'react';
+import { ColorSchemeName } from 'react-native';
+import useModel from 'flooks';
+import { useTranslation } from 'react-i18next';
+
+import { MineStackParamList } from '../types';
+
+import MineScreen from '../mine/MineScreen';
+
+const MineStack = createStackNavigator<MineStackParamList>();
+export default function Navigation({
+  colorScheme,
+}: {
+  colorScheme: ColorSchemeName;
+}) {
+  const { t } = useTranslation();
+  return (
+    <MineStack.Navigator
+      initialRouteName="Mine"
+      screenOptions={{
+        cardOverlayEnabled: true,
+        cardStyle: { backgroundColor: '#f2f2f2', flex: 1 },
+        contentStyle: { backgroundColor: '#f2f2f2', flex: 1 },
+        gestureEnabled: true,
+        stackPresentation: 'push',
+        cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
+        headerStyle: {
+          backgroundColor: '#FFC21C',
+        },
+        headerTintColor: '#fff',
+        headerTitleStyle: {
+          fontWeight: 'bold',
+        },
+        headerTitleAlign: 'center',
+        headerBackTitleVisible: false,
+      }}
+    >
+      <MineStack.Screen
+        name="Mine"
+        component={MineScreen}
+        options={{ headerShown: false }}
+      />
+    </MineStack.Navigator>
+  );
+}

+ 54 - 0
navigation/NoticeStackNavigator.tsx

@@ -0,0 +1,54 @@
+import {
+  NavigationContainer,
+  DefaultTheme,
+  DarkTheme,
+} from '@react-navigation/native';
+import {
+  createStackNavigator,
+  CardStyleInterpolators,
+} from '@react-navigation/stack';
+import * as React from 'react';
+import { ColorSchemeName } from 'react-native';
+import useModel from 'flooks';
+import { useTranslation } from 'react-i18next';
+
+import { NoticeStackParamList } from '../types';
+
+import NoticeScreen from '../notice/NoticeScreen';
+
+const NoticeStack = createStackNavigator<NoticeStackParamList>();
+export default function Navigation({
+  colorScheme,
+}: {
+  colorScheme: ColorSchemeName;
+}) {
+  const { t } = useTranslation();
+  return (
+    <NoticeStack.Navigator
+      initialRouteName="Notice"
+      screenOptions={{
+        cardOverlayEnabled: true,
+        cardStyle: { backgroundColor: '#f2f2f2', flex: 1 },
+        contentStyle: { backgroundColor: '#f2f2f2', flex: 1 },
+        gestureEnabled: true,
+        stackPresentation: 'push',
+        cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
+        headerStyle: {
+          backgroundColor: '#FFC21C',
+        },
+        headerTintColor: '#fff',
+        headerTitleStyle: {
+          fontWeight: 'bold',
+        },
+        headerTitleAlign: 'center',
+        headerBackTitleVisible: false,
+      }}
+    >
+      <NoticeStack.Screen
+        name="Notice"
+        component={NoticeScreen}
+        options={{ title: t('qi-shou-shen-he') }}
+      />
+    </NoticeStack.Navigator>
+  );
+}

+ 54 - 0
navigation/OrderStackNavigator.tsx

@@ -0,0 +1,54 @@
+import {
+  NavigationContainer,
+  DefaultTheme,
+  DarkTheme,
+} from '@react-navigation/native';
+import {
+  createStackNavigator,
+  CardStyleInterpolators,
+} from '@react-navigation/stack';
+import * as React from 'react';
+import { ColorSchemeName } from 'react-native';
+import useModel from 'flooks';
+import { useTranslation } from 'react-i18next';
+
+import { OrderStackParamList } from '../types';
+
+import OrderScreen from '../order/OrderScreen';
+
+const OrderStack = createStackNavigator<OrderStackParamList>();
+export default function Navigation({
+  colorScheme,
+}: {
+  colorScheme: ColorSchemeName;
+}) {
+  const { t } = useTranslation();
+  return (
+    <OrderStack.Navigator
+      initialRouteName="Order"
+      screenOptions={{
+        cardOverlayEnabled: true,
+        cardStyle: { backgroundColor: '#f2f2f2', flex: 1 },
+        contentStyle: { backgroundColor: '#f2f2f2', flex: 1 },
+        gestureEnabled: true,
+        stackPresentation: 'push',
+        cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
+        headerStyle: {
+          backgroundColor: '#FFC21C',
+        },
+        headerTintColor: '#fff',
+        headerTitleStyle: {
+          fontWeight: 'bold',
+        },
+        headerTitleAlign: 'center',
+        headerBackTitleVisible: false,
+      }}
+    >
+      <OrderStack.Screen
+        name="Order"
+        component={OrderScreen}
+        options={{ title: t('qi-shou-shen-he') }}
+      />
+    </OrderStack.Navigator>
+  );
+}

+ 19 - 7
navigation/index.tsx

@@ -13,8 +13,11 @@ import useModel from 'flooks';
 //弹窗模块
 import AlertModalScreen from '../modals/AlertModalScreen';
 
-//主堆栈
-import MainStackNavigator from './MainStackNavigator';
+//登录模块堆栈
+import LoginStackNavigator from './LoginStackNavigator';
+
+//首页堆栈
+import MainTabNavigator from './MianTabNavigator';
 
 import { RootStackParamList } from '../types';
 import LinkingConfiguration from './LinkingConfiguration';
@@ -35,8 +38,12 @@ export default function Navigation({
           index: 0,
           routes: [
             {
-              name: 'Main',
-              screen: __DEV__ ? 'Certification' : initialRouteName,
+              name: initialRouteName !== 'Main' ? 'Login' : initialRouteName,
+              screen: __DEV__
+                ? 'Certification'
+                : initialRouteName !== 'Main'
+                ? initialRouteName
+                : 'TabOne',
             },
           ],
         })
@@ -61,17 +68,22 @@ function RootNavigator() {
   const { t } = useTranslation();
   return (
     <Stack.Navigator
-      mode="modal"
       initialRouteName="Main"
       screenOptions={{
+        stackPresentation: 'push',
         headerShown: false,
       }}
     >
-      <Stack.Screen name="Main" component={MainStackNavigator} />
+      <Stack.Screen name="Login" component={LoginStackNavigator} />
+
+      <Stack.Screen name="Main" component={MainTabNavigator} />
 
       <Stack.Screen
         name="AlertModal"
-        options={{ cardStyle: { backgroundColor: 'transparent' } }}
+        mode="modals"
+        options={{
+          cardStyle: { backgroundColor: 'transparent' },
+        }}
         component={AlertModalScreen}
       />
     </Stack.Navigator>

+ 23 - 0
notice/NoticeScreen.tsx

@@ -0,0 +1,23 @@
+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 { RootStackParamList } from '../types';
+import IM from './model';
+
+export default function RegisterScreen({
+  navigation,
+}: StackScreenProps<RootStackParamList, 'Login'>) {
+  return (
+    <Div bg="gray100">
+      <ScrollView
+        contentContainerStyle={{ flexGrow: 1, backgroundColor: '#f2f2f2' }}
+      >
+        <Div>
+          <Text></Text>
+        </Div>
+      </ScrollView>
+    </Div>
+  );
+}

+ 115 - 0
notice/model.ts

@@ -0,0 +1,115 @@
+import TIM from 'tim-js-sdk';
+import COS from 'cos-js-sdk-v5';
+
+const IM = (now) => ({
+  SDKAppID: 1400401634,
+  userID: 2015,
+  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,
+    });
+  },
+});
+
+export default IM;

+ 21 - 0
order/OrderScreen.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 OrderScreen({ navigation }: StackScreenProps) {
+  return (
+    <Div bg="gray100">
+      <ScrollView
+        contentContainerStyle={{
+          flexGrow: 1,
+          backgroundColor: '#f2f2f2',
+        }}
+      >
+        <Div>
+          <Text></Text>
+        </Div>
+      </ScrollView>
+    </Div>
+  );
+}

+ 13 - 0
package-lock.json

@@ -4705,6 +4705,14 @@
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
       "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
     },
+    "cos-js-sdk-v5": {
+      "version": "0.5.27",
+      "resolved": "https://registry.npmjs.org/cos-js-sdk-v5/-/cos-js-sdk-v5-0.5.27.tgz",
+      "integrity": "sha512-kq5363l1TpU26AHRZTcWCibPfM5ykQ2zHsdpnP/Ax8SMuYQDNIP/BVWaA55Ks2r5JsELjqXLF516FeXQz3jEZw==",
+      "requires": {
+        "xmldom": "^0.1.27"
+      }
+    },
     "cosmiconfig": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
@@ -14337,6 +14345,11 @@
         "xtend": "~4.0.1"
       }
     },
+    "tim-js-sdk": {
+      "version": "2.7.6",
+      "resolved": "https://registry.npmjs.org/tim-js-sdk/-/tim-js-sdk-2.7.6.tgz",
+      "integrity": "sha512-bpdWM9aIdAfUTjONjMFqx2H6UOs+SCx1AozIL54zqbaYBJhyQL3Hy32BQd/zrTkCpdkO38hotUWy8O5aEy6nvg=="
+    },
     "time-stamp": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",

+ 4 - 2
package.json

@@ -21,6 +21,7 @@
     "ahooks": "^2.2.0",
     "color": "^3.1.2",
     "core-js": "^3.6.5",
+    "cos-js-sdk-v5": "^0.5.27",
     "expo": "~38.0.8",
     "expo-application": "~2.2.1",
     "expo-asset": "~8.1.7",
@@ -55,9 +56,10 @@
     "react-native-tab-view": "^2.15.0",
     "react-native-vector-icons": "^7.0.0",
     "react-native-web": "~0.11.7",
+    "react-native-webview": "9.4.0",
     "teaset": "^0.7.4",
-    "umi-request": "^1.3.5",
-    "react-native-webview": "9.4.0"
+    "tim-js-sdk": "^2.7.6",
+    "umi-request": "^1.3.5"
   },
   "devDependencies": {
     "@babel/core": "^7.8.6",

+ 1 - 1
screens/TabOneScreen.tsx

@@ -10,7 +10,7 @@ export default function TabOneScreen() {
       <Text style={styles.title}>Tab One</Text>
       <View
         style={styles.separator}
-        lightColor="#eee"
+        lightColor="#f2f2f2"
         darkColor="rgba(255,255,255,0.1)"
       />
       <EditScreenInfo path="/screens/TabOneScreen.tsx" />

+ 1 - 1
screens/TabTwoScreen.tsx

@@ -8,7 +8,7 @@ export default function TabTwoScreen() {
   return (
     <View style={styles.container}>
       <Text style={styles.title}>Tab Two</Text>
-      <View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
+      <View style={styles.separator} lightColor="#f2f2f2" darkColor="rgba(255,255,255,0.1)" />
       <EditScreenInfo path="/screens/TabTwoScreen.tsx" />
     </View>
   );

+ 6 - 9
stores/User.ts

@@ -10,6 +10,7 @@ import {
   toastInfo,
   toastSuccess,
 } from '../utils/SystemUtils';
+import IM from '../im/model';
 
 const user = (now) => ({
   id: null,
@@ -57,10 +58,9 @@ const user = (now) => ({
           now({
             verifiedInfo: res,
           });
-          return Promise.reject(userInfo.id);
-        } else {
-          return Promise.reject(userInfo.id);
         }
+
+        return Promise.reject(userInfo.id);
       });
   },
   logout() {
@@ -95,12 +95,8 @@ const user = (now) => ({
   getInit() {
     const { getUser } = now();
     return getUser()
-      .then(() => {
-        now({ initialRouteName: 'Root' });
-      })
       .catch((id) => {
         const { verifiedInfo, riderInfo } = now();
-        console.log(verifiedInfo);
         if (id && riderInfo.id) {
           if (riderInfo.status === 'PENDING') {
             now({ initialRouteName: 'AuditResult' });
@@ -119,14 +115,15 @@ const user = (now) => ({
       })
       .then((res) => {
         const { riderInfo } = now();
-        console.log(res);
         if (
-          (res && riderInfo.status === 'PASS' && res.toString() === 'true') ||
+          (res && riderInfo.status === 'PASS' && res === 'true') ||
           (!res && riderInfo.status === 'DENY')
         ) {
           now({ initialRouteName: 'AuditResult' });
         } else if (res) {
           now({ initialRouteName: res });
+        } else {
+          now({ initialRouteName: 'Main' });
         }
       });
   },

+ 22 - 12
types.tsx

@@ -1,5 +1,6 @@
 export type RootStackParamList = {
   Main: undefined;
+  Login: undefined;
   AlertModal: {
     msg: string;
     title: string;
@@ -7,25 +8,34 @@ export type RootStackParamList = {
     submitEvent: Event;
   };
 };
-export type MainStackParamList = {
+export type LoginStackParamList = {
   Login: undefined;
   Register: undefined;
-  Root: undefined;
+  Certification: undefined;
+  Transportation: undefined;
+  ApplyLocation: undefined;
+  AuditResult: undefined;
+  SearchMap: undefined;
 };
-export type BottomTabParamList = {
-  TabOne: undefined;
-  TabTwo: undefined;
+export type MainTabParamList = {
+  Order: undefined;
+  Notice: undefined;
+  Mine: undefined;
 };
 
-export type LoginTabParamList = {
-  Psd: undefined;
-  Code: undefined;
+export type OrderStackParamList = {
+  Order: undefined;
 };
 
-export type TabOneParamList = {
-  TabOneScreen: undefined;
+export type NoticeStackParamList = {
+  Notice: undefined;
 };
 
-export type TabTwoParamList = {
-  TabTwoScreen: undefined;
+export type MineStackParamList = {
+  Mine: undefined;
+};
+
+export type LoginTabParamList = {
+  Psd: undefined;
+  Code: undefined;
 };

+ 100 - 0
utils/IMutils.ts

@@ -0,0 +1,100 @@
+import TIM from 'tim-js-sdk';
+import COS from 'cos-js-sdk-v5';
+
+// 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例
+let options = {
+  SDKAppID: 1400401634, // 接入时需要将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) {
+  // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
+  // event.name - TIM.EVENT.MESSAGE_RECEIVED
+  // event.data - 存储 Message 对象的数组 - [Message]
+});
+
+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: 2105,
+  userSig:
+    'eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zIhwoYGplDx4pTsxIKCzBQlK0MTAwMTA0MzYxOITGpFQWZRKlDc1NTUyMDAACJakpkLFrM0Bao1MIGqLc5MBxqbGGqUnZzlFZWiHRoeFaOf45eX6h*j7*nkXZ4XmOIeleYTXBbp7VNUHpqTE*xqq1QLANeJMS4_',
+});