林旭祥 6 dienas atpakaļ
vecāks
revīzija
2f14fadab1
100 mainītis faili ar 1347 papildinājumiem un 61 dzēšanām
  1. 53 38
      App.tsx
  2. 412 20
      package-lock.json
  3. 11 3
      package.json
  4. 9 0
      src/api/env.js
  5. 21 0
      src/api/index.ts
  6. 26 0
      src/api/module/analysis.js
  7. 65 0
      src/api/module/common.js
  8. 5 0
      src/api/module/course.js
  9. 46 0
      src/api/module/enter.js
  10. 34 0
      src/api/module/ranking.js
  11. 15 0
      src/api/module/score.js
  12. 31 0
      src/api/module/set.js
  13. 20 0
      src/api/module/test.js
  14. 31 0
      src/api/module/train.js
  15. 123 0
      src/api/request.ts
  16. 36 0
      src/pages/Custom/index.tsx
  17. 22 0
      src/pages/Face/index.tsx
  18. 28 0
      src/pages/Home/index.tsx
  19. 175 0
      src/pages/Login/index.tsx
  20. 184 0
      src/pages/Udp/index.tsx
  21. BIN
      src/static/images/analysis/badminton.png
  22. BIN
      src/static/images/analysis/basketball.png
  23. BIN
      src/static/images/analysis/close.png
  24. BIN
      src/static/images/analysis/football.png
  25. BIN
      src/static/images/analysis/grade1.png
  26. BIN
      src/static/images/analysis/grade2.png
  27. BIN
      src/static/images/analysis/grade3.png
  28. BIN
      src/static/images/analysis/grade4.png
  29. BIN
      src/static/images/analysis/gymnastics.png
  30. BIN
      src/static/images/analysis/headPortrait.png
  31. BIN
      src/static/images/analysis/highknees.png
  32. BIN
      src/static/images/analysis/jump.png
  33. BIN
      src/static/images/analysis/jumpingjack.png
  34. BIN
      src/static/images/analysis/jumprope.png
  35. BIN
      src/static/images/analysis/lockClose.png
  36. BIN
      src/static/images/analysis/lockOpen.png
  37. BIN
      src/static/images/analysis/longjump.png
  38. BIN
      src/static/images/analysis/pingpong.png
  39. BIN
      src/static/images/analysis/pullUp.png
  40. BIN
      src/static/images/analysis/rankingIcon.png
  41. BIN
      src/static/images/analysis/resultIcon.png
  42. BIN
      src/static/images/analysis/run1000.png
  43. BIN
      src/static/images/analysis/run800.png
  44. BIN
      src/static/images/analysis/shotput.png
  45. BIN
      src/static/images/analysis/sidepullup.png
  46. BIN
      src/static/images/analysis/sitUp.png
  47. BIN
      src/static/images/analysis/skiprope.png
  48. BIN
      src/static/images/analysis/solidBall.png
  49. BIN
      src/static/images/analysis/swim.png
  50. BIN
      src/static/images/analysis/tennis.png
  51. BIN
      src/static/images/analysis/trijump.png
  52. BIN
      src/static/images/analysis/trops.png
  53. BIN
      src/static/images/analysis/verticaljump.png
  54. BIN
      src/static/images/analysis/volleyball.png
  55. BIN
      src/static/images/analysis/wushu.png
  56. BIN
      src/static/images/common/close.png
  57. BIN
      src/static/images/common/icon.png
  58. BIN
      src/static/images/common/loading.png
  59. BIN
      src/static/images/common/shine.png
  60. BIN
      src/static/images/home/back.png
  61. BIN
      src/static/images/home/btnbg1.png
  62. BIN
      src/static/images/home/btnbg1a.png
  63. BIN
      src/static/images/home/btnbg2.png
  64. BIN
      src/static/images/home/btnbg3.png
  65. BIN
      src/static/images/home/course.png
  66. BIN
      src/static/images/home/enter.png
  67. BIN
      src/static/images/home/pe.png
  68. BIN
      src/static/images/home/ranking.png
  69. BIN
      src/static/images/home/score.png
  70. BIN
      src/static/images/home/setbg.png
  71. BIN
      src/static/images/home/test.png
  72. BIN
      src/static/images/home/train.png
  73. BIN
      src/static/images/login/bg.png
  74. BIN
      src/static/images/login/btn.png
  75. BIN
      src/static/images/login/logo.png
  76. BIN
      src/static/images/login/xian.png
  77. BIN
      src/static/images/ranking/arrow.png
  78. BIN
      src/static/images/ranking/logo.png
  79. BIN
      src/static/images/ranking/mao1.png
  80. BIN
      src/static/images/ranking/mao2.png
  81. BIN
      src/static/images/ranking/mao3.png
  82. BIN
      src/static/images/ranking/noData.png
  83. BIN
      src/static/images/ranking/rankingBg.png
  84. BIN
      src/static/images/set/bug.png
  85. BIN
      src/static/images/set/camera.png
  86. BIN
      src/static/images/set/face.png
  87. BIN
      src/static/images/set/guanbi.png
  88. BIN
      src/static/images/set/guding.png
  89. BIN
      src/static/images/set/tuichu.png
  90. BIN
      src/static/images/set/zhuan.png
  91. BIN
      src/static/images/train/areabg1.png
  92. BIN
      src/static/images/train/areabg2.png
  93. BIN
      src/static/images/train/arrow.png
  94. BIN
      src/static/images/train/close.png
  95. BIN
      src/static/images/train/exitbg.png
  96. BIN
      src/static/images/train/greenbg.png
  97. BIN
      src/static/images/train/headbg.png
  98. BIN
      src/static/images/train/noImg.png
  99. BIN
      src/static/images/train/select.png
  100. BIN
      src/static/images/train/tanhao.png

+ 53 - 38
App.tsx

@@ -1,45 +1,60 @@
-/**
- * Sample React Native App
- * https://github.com/facebook/react-native
- *
- * @format
- */
+import React from 'react';
+import { NavigationContainer } from '@react-navigation/native';
+import { createNativeStackNavigator } from '@react-navigation/native-stack';
+import LoginScreen from './src/pages/Login';
+import HomeScreen from './src/pages/Home';
+import FaceScreen from './src/pages/Face';
+import CustomScreen from './src/pages/Custom';
+import UdpScreen from './src/pages/Udp';
 
-import { NewAppScreen } from '@react-native/new-app-screen';
-import { StatusBar, StyleSheet, useColorScheme, View } from 'react-native';
-import {
-  SafeAreaProvider,
-  useSafeAreaInsets,
-} from 'react-native-safe-area-context';
-
-function App() {
-  const isDarkMode = useColorScheme() === 'dark';
+const Stack = createNativeStackNavigator();
 
+function App(): React.JSX.Element {
   return (
-    <SafeAreaProvider>
-      <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
-      <AppContent />
-    </SafeAreaProvider>
+    <NavigationContainer>
+      <Stack.Navigator initialRouteName="Udp">
+        <Stack.Screen
+          name="Udp"
+          component={UdpScreen}
+          options={{
+            title: '测试udp',
+          }}
+        />
+        <Stack.Screen
+          name="Login"
+          component={LoginScreen}
+          options={{
+            title: '登录',
+            headerBackVisible: false,
+            headerShown: false,
+          }}
+        />
+        <Stack.Screen
+          name="Home"
+          component={HomeScreen}
+          options={{
+            title: '首页',
+            headerBackVisible: false,
+            headerShown: false,
+          }}
+        />
+        <Stack.Screen
+          name="Face"
+          component={FaceScreen}
+          options={{
+            title: '人脸识别',
+          }}
+        />
+        <Stack.Screen
+          name="Custom"
+          component={CustomScreen}
+          options={{
+            title: '自定义SDK',
+          }}
+        />
+      </Stack.Navigator>
+    </NavigationContainer>
   );
 }
 
-function AppContent() {
-  const safeAreaInsets = useSafeAreaInsets();
-
-  return (
-    <View style={styles.container}>
-      <NewAppScreen
-        templateFileName="App.tsx"
-        safeAreaInsets={safeAreaInsets}
-      />
-    </View>
-  );
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-  },
-});
-
 export default App;

+ 412 - 20
package-lock.json

@@ -9,9 +9,17 @@
       "version": "0.0.1",
       "dependencies": {
         "@react-native/new-app-screen": "0.81.0",
+        "@react-navigation/native": "^7.1.17",
+        "@react-navigation/native-stack": "^7.3.25",
+        "axios": "^1.11.0",
+        "dayjs": "^1.11.13",
         "react": "19.1.0",
         "react-native": "0.81.0",
-        "react-native-safe-area-context": "^5.5.2"
+        "react-native-fs": "^2.20.0",
+        "react-native-safe-area-context": "^5.6.1",
+        "react-native-screens": "^4.15.2",
+        "react-native-toast-message": "^2.3.3",
+        "react-native-udp": "^4.1.7"
       },
       "devDependencies": {
         "@babel/core": "^7.25.2",
@@ -3209,6 +3217,96 @@
         }
       }
     },
+    "node_modules/@react-navigation/core": {
+      "version": "7.12.4",
+      "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.12.4.tgz",
+      "integrity": "sha512-xLFho76FA7v500XID5z/8YfGTvjQPw7/fXsq4BIrVSqetNe/o/v+KAocEw4ots6kyv3XvSTyiWKh2g3pN6xZ9Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-navigation/routers": "^7.5.1",
+        "escape-string-regexp": "^4.0.0",
+        "nanoid": "^3.3.11",
+        "query-string": "^7.1.3",
+        "react-is": "^19.1.0",
+        "use-latest-callback": "^0.2.4",
+        "use-sync-external-store": "^1.5.0"
+      },
+      "peerDependencies": {
+        "react": ">= 18.2.0"
+      }
+    },
+    "node_modules/@react-navigation/core/node_modules/react-is": {
+      "version": "19.1.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz",
+      "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
+      "license": "MIT"
+    },
+    "node_modules/@react-navigation/elements": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.6.3.tgz",
+      "integrity": "sha512-hcPXssZg5bFD5oKX7FP0D9ZXinRgPUHkUJbTegpenSEUJcPooH1qzWJkEP22GrtO+OPDLYrCVZxEX8FcMrn4pA==",
+      "license": "MIT",
+      "dependencies": {
+        "color": "^4.2.3",
+        "use-latest-callback": "^0.2.4",
+        "use-sync-external-store": "^1.5.0"
+      },
+      "peerDependencies": {
+        "@react-native-masked-view/masked-view": ">= 0.2.0",
+        "@react-navigation/native": "^7.1.17",
+        "react": ">= 18.2.0",
+        "react-native": "*",
+        "react-native-safe-area-context": ">= 4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@react-native-masked-view/masked-view": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@react-navigation/native": {
+      "version": "7.1.17",
+      "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.17.tgz",
+      "integrity": "sha512-uEcYWi1NV+2Qe1oELfp9b5hTYekqWATv2cuwcOAg5EvsIsUPtzFrKIasgUXLBRGb9P7yR5ifoJ+ug4u6jdqSTQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-navigation/core": "^7.12.4",
+        "escape-string-regexp": "^4.0.0",
+        "fast-deep-equal": "^3.1.3",
+        "nanoid": "^3.3.11",
+        "use-latest-callback": "^0.2.4"
+      },
+      "peerDependencies": {
+        "react": ">= 18.2.0",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-navigation/native-stack": {
+      "version": "7.3.25",
+      "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.3.25.tgz",
+      "integrity": "sha512-jGcgUpif0dDGwuqag6rKTdS78MiAVAy8vmQppyaAgjS05VbCfDX+xjhc8dUxSClO5CoWlDoby1c8Hw4kBfL2UA==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-navigation/elements": "^2.6.3",
+        "warn-once": "^0.1.1"
+      },
+      "peerDependencies": {
+        "@react-navigation/native": "^7.1.17",
+        "react": ">= 18.2.0",
+        "react-native": "*",
+        "react-native-safe-area-context": ">= 4.0.0",
+        "react-native-screens": ">= 4.0.0"
+      }
+    },
+    "node_modules/@react-navigation/routers": {
+      "version": "7.5.1",
+      "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.1.tgz",
+      "integrity": "sha512-pxipMW/iEBSUrjxz2cDD7fNwkqR4xoi0E/PcfTQGCcdJwLoaxzab5kSadBLj1MTJyT0YRrOXL9umHpXtp+Dv4w==",
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.11"
+      }
+    },
     "node_modules/@sideway/address": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
@@ -4022,6 +4120,12 @@
       "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
       "license": "MIT"
     },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
     "node_modules/available-typed-arrays": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -4038,6 +4142,17 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/axios": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
+      "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.15.6",
+        "form-data": "^4.0.4",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
     "node_modules/babel-jest": {
       "version": "29.7.0",
       "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
@@ -4211,6 +4326,11 @@
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
       "license": "MIT"
     },
+    "node_modules/base-64": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
+      "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
+    },
     "node_modules/base64-js": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -4352,7 +4472,6 @@
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
       "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
-      "devOptional": true,
       "funding": [
         {
           "type": "github",
@@ -4412,7 +4531,6 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
       "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
-      "devOptional": true,
       "license": "MIT",
       "dependencies": {
         "es-errors": "^1.3.0",
@@ -4683,6 +4801,19 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/color": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+      "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1",
+        "color-string": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=12.5.0"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -4701,6 +4832,16 @@
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
       "license": "MIT"
     },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
     "node_modules/colorette": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
@@ -4708,6 +4849,18 @@
       "devOptional": true,
       "license": "MIT"
     },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/command-exists": {
       "version": "1.2.9",
       "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
@@ -4968,7 +5121,6 @@
       "version": "1.11.13",
       "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
       "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
-      "devOptional": true,
       "license": "MIT"
     },
     "node_modules/debug": {
@@ -4998,6 +5150,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/decode-uri-component": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+      "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
     "node_modules/dedent": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz",
@@ -5079,6 +5240,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/depd": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -5148,7 +5318,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
       "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
-      "devOptional": true,
       "license": "MIT",
       "dependencies": {
         "call-bind-apply-helpers": "^1.0.1",
@@ -5327,7 +5496,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
       "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
-      "devOptional": true,
       "license": "MIT",
       "engines": {
         "node": ">= 0.4"
@@ -5337,7 +5505,6 @@
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
       "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
-      "devOptional": true,
       "license": "MIT",
       "engines": {
         "node": ">= 0.4"
@@ -5375,7 +5542,6 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
       "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
-      "devOptional": true,
       "license": "MIT",
       "dependencies": {
         "es-errors": "^1.3.0"
@@ -5388,7 +5554,6 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
       "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "es-errors": "^1.3.0",
@@ -6050,6 +6215,15 @@
         "node": ">=6"
       }
     },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
     "node_modules/execa": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -6110,7 +6284,6 @@
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
       "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-      "dev": true,
       "license": "MIT"
     },
     "node_modules/fast-glob": {
@@ -6219,6 +6392,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/filter-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
+      "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/finalhandler": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -6309,6 +6491,26 @@
       "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==",
       "license": "MIT"
     },
+    "node_modules/follow-redirects": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+      "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/for-each": {
       "version": "0.3.5",
       "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@@ -6325,6 +6527,22 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/form-data": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+      "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "es-set-tostringtag": "^2.1.0",
+        "hasown": "^2.0.2",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -6431,7 +6649,6 @@
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
       "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
-      "devOptional": true,
       "license": "MIT",
       "dependencies": {
         "call-bind-apply-helpers": "^1.0.2",
@@ -6465,7 +6682,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
       "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
-      "devOptional": true,
       "license": "MIT",
       "dependencies": {
         "dunder-proto": "^1.0.1",
@@ -6620,7 +6836,6 @@
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
       "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
-      "devOptional": true,
       "license": "MIT",
       "engines": {
         "node": ">= 0.4"
@@ -6697,7 +6912,6 @@
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
       "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
-      "devOptional": true,
       "license": "MIT",
       "engines": {
         "node": ">= 0.4"
@@ -6710,7 +6924,6 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
       "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "has-symbols": "^1.0.3"
@@ -6821,7 +7034,6 @@
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
       "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-      "devOptional": true,
       "funding": [
         {
           "type": "github",
@@ -8624,7 +8836,6 @@
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
       "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
-      "devOptional": true,
       "license": "MIT",
       "engines": {
         "node": ">= 0.4"
@@ -9158,6 +9369,24 @@
       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
       "license": "MIT"
     },
+    "node_modules/nanoid": {
+      "version": "3.3.11",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
     "node_modules/natural-compare": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -9805,6 +10034,12 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "license": "MIT"
+    },
     "node_modules/punycode": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -9848,6 +10083,24 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/query-string": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
+      "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
+      "license": "MIT",
+      "dependencies": {
+        "decode-uri-component": "^0.2.2",
+        "filter-obj": "^1.1.0",
+        "split-on-first": "^1.0.0",
+        "strict-uri-encode": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/queue": {
       "version": "6.0.2",
       "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
@@ -9943,6 +10196,18 @@
         }
       }
     },
+    "node_modules/react-freeze": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz",
+      "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "react": ">=17.0.0"
+      }
+    },
     "node_modules/react-is": {
       "version": "18.3.1",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
@@ -10006,16 +10271,80 @@
         }
       }
     },
+    "node_modules/react-native-fs": {
+      "version": "2.20.0",
+      "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz",
+      "integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==",
+      "license": "MIT",
+      "dependencies": {
+        "base-64": "^0.1.0",
+        "utf8": "^3.0.0"
+      },
+      "peerDependencies": {
+        "react-native": "*",
+        "react-native-windows": "*"
+      },
+      "peerDependenciesMeta": {
+        "react-native-windows": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-native-is-edge-to-edge": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz",
+      "integrity": "sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
     "node_modules/react-native-safe-area-context": {
-      "version": "5.6.0",
-      "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.0.tgz",
-      "integrity": "sha512-tJas3YOdsuCg3kepCTGF3LWZp9onMbb9Agju2xfs2kRX8d/5TMUPmupBpjerk/B7Tv/zeJnk+qp5neA96Y0otQ==",
+      "version": "5.6.1",
+      "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.1.tgz",
+      "integrity": "sha512-/wJE58HLEAkATzhhX1xSr+fostLsK8Q97EfpfMDKo8jlOc1QKESSX/FQrhk7HhQH/2uSaox4Y86sNaI02kteiA==",
       "license": "MIT",
       "peerDependencies": {
         "react": "*",
         "react-native": "*"
       }
     },
+    "node_modules/react-native-screens": {
+      "version": "4.15.2",
+      "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.15.2.tgz",
+      "integrity": "sha512-RA9fUT/5OTPJ2ML3BNUbe8UtfcU7iufE+r9sLr/IesFdBDj38bZiqmH88iorI5Vfgp7O3zf2aK390Tbkfp9Xfw==",
+      "license": "MIT",
+      "dependencies": {
+        "react-freeze": "^1.0.0",
+        "react-native-is-edge-to-edge": "^1.2.1",
+        "warn-once": "^0.1.0"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/react-native-toast-message": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/react-native-toast-message/-/react-native-toast-message-2.3.3.tgz",
+      "integrity": "sha512-4IIUHwUPvKHu4gjD0Vj2aGQzqPATiblL1ey8tOqsxOWRPGGu52iIbL8M/mCz4uyqecvPdIcMY38AfwRuUADfQQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/react-native-udp": {
+      "version": "4.1.7",
+      "resolved": "https://registry.npmjs.org/react-native-udp/-/react-native-udp-4.1.7.tgz",
+      "integrity": "sha512-NUE3zewu61NCdSsLlj+l0ad6qojcVEZPT4hVG/x6DU9U4iCzwtfZSASh9vm7teAcVzLkdD+cO3411LHshAi/wA==",
+      "license": "MIT",
+      "dependencies": {
+        "buffer": "^5.6.0",
+        "events": "^3.1.0"
+      }
+    },
     "node_modules/react-native/node_modules/commander": {
       "version": "12.1.0",
       "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
@@ -10711,6 +11040,21 @@
       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "license": "ISC"
     },
+    "node_modules/simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "license": "MIT",
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
+    "node_modules/simple-swizzle/node_modules/is-arrayish": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+      "license": "MIT"
+    },
     "node_modules/sisteransi": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -10792,6 +11136,15 @@
         "source-map": "^0.6.0"
       }
     },
+    "node_modules/split-on-first": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
+      "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -10869,6 +11222,15 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/strict-uri-encode": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+      "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/string_decoder": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -11514,6 +11876,30 @@
         "punycode": "^2.1.0"
       }
     },
+    "node_modules/use-latest-callback": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.4.tgz",
+      "integrity": "sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": ">=16.8"
+      }
+    },
+    "node_modules/use-sync-external-store": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
+      "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/utf8": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
+      "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==",
+      "license": "MIT"
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -11570,6 +11956,12 @@
         "makeerror": "1.0.12"
       }
     },
+    "node_modules/warn-once": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz",
+      "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==",
+      "license": "MIT"
+    },
     "node_modules/wcwidth": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",

+ 11 - 3
package.json

@@ -10,10 +10,18 @@
     "test": "jest"
   },
   "dependencies": {
+    "@react-native/new-app-screen": "0.81.0",
+    "@react-navigation/native": "^7.1.17",
+    "@react-navigation/native-stack": "^7.3.25",
+    "axios": "^1.11.0",
+    "dayjs": "^1.11.13",
     "react": "19.1.0",
     "react-native": "0.81.0",
-    "@react-native/new-app-screen": "0.81.0",
-    "react-native-safe-area-context": "^5.5.2"
+    "react-native-fs": "^2.20.0",
+    "react-native-safe-area-context": "^5.6.1",
+    "react-native-screens": "^4.15.2",
+    "react-native-toast-message": "^2.3.3",
+    "react-native-udp": "^4.1.7"
   },
   "devDependencies": {
     "@babel/core": "^7.25.2",
@@ -38,4 +46,4 @@
   "engines": {
     "node": ">=18"
   }
-}
+}

+ 9 - 0
src/api/env.js

@@ -0,0 +1,9 @@
+//环境切换在文件目录:/public/constant.js。
+const current = "dev";
+
+const api = {
+	dev: "https://api-aiexamtst.tropsx.com",
+	prod: "https://api-aiexam.tropsx.com",
+};
+
+export default api[current];

+ 21 - 0
src/api/index.ts

@@ -0,0 +1,21 @@
+import common from './module/common';
+import analysis from './module/analysis';
+import course from './module/course';
+import enter from './module/enter';
+import ranking from './module/ranking';
+import score from './module/score';
+import set from './module/set';
+import test from './module/test';
+import train from './module/train';
+
+export default {
+    common,
+    analysis,
+    course,
+    enter,
+    ranking,
+    score,
+    set,
+    test,
+	train,
+}

+ 26 - 0
src/api/module/analysis.js

@@ -0,0 +1,26 @@
+import req from '../request'
+
+module.exports = {
+
+	trainExamDetails: data => {
+		return req({
+			url: `/report/onev2`,
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		})
+	},
+
+	testExamDetails: data => {
+		return req({
+			url: `/task/indivi_exam_detail`,
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		})
+	},
+}

+ 65 - 0
src/api/module/common.js

@@ -0,0 +1,65 @@
+import req from '../request'
+
+module.exports = {
+
+	//获取token
+	getLogin: data => {
+		return req({
+			url: '/user/login',
+			method: 'post',
+			data: data,
+			headers: {
+				auth: false, //不要鉴权
+			}
+		});
+	},
+
+	//获取登录信息
+	getUserInfo: data => {
+		return req({
+			url: '/user/userinfo',//新接口/user/login
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+
+	//百度语音token
+	baiduToken: data => {
+		return req({
+			url: '/bdapi_token',
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+	
+	//获取APP
+	getApp: data => {
+		return req({
+			url: '/appversion',
+			method: 'get',
+			data: data,
+			header: JSON.stringify({
+				"Content-Type": "application/x-www-form-urlencoded",
+			}),
+			headers: {
+				auth: false, //不要鉴权
+				showLoading: false,
+			}
+		});
+	},
+	
+	//退出登录
+	getLogout: data => {
+		return req({
+			url: '/user/logout',
+			method: 'get',
+			data: data,
+		});
+	},
+}

+ 5 - 0
src/api/module/course.js

@@ -0,0 +1,5 @@
+import req from '../request'
+
+module.exports = {
+
+}

+ 46 - 0
src/api/module/enter.js

@@ -0,0 +1,46 @@
+import req from '../request'
+
+module.exports = {
+
+	//自由任务
+	freeTasksList: data => {
+		return req({
+			url: '/task/task_list',
+			method: 'get',
+			data: data,
+		});
+	},
+	//常规任务
+	conventionTasksList: data => {
+		return req({
+			url: '/task/common_list',
+			method: 'get',
+			data: data,
+		});
+	},
+	//获取测试项目
+	getTaskProject: data => {
+		return req({
+			url: '/exam/ccconfig_grade_view',
+			method: 'get',
+			data: data,
+		});
+	},
+	//学生成绩列表
+	taskStudents: data => {
+		return req({
+			url: '/spro/task_students',
+			method: 'post',
+			data: data,
+		});
+	},
+	//学生成绩录入
+	taskResultRecordIn: data => {
+		return req({
+			url: '/spro/task_result_record_in',
+			method: 'post',
+			data: data,
+		});
+	},
+
+}

+ 34 - 0
src/api/module/ranking.js

@@ -0,0 +1,34 @@
+import req from '../request'
+
+module.exports = {
+	projectList: data => {
+		return req({
+			url: '/exam/examlist_show',
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+	studentRanking: data => {
+		return req({
+			url: '/schpanel/student_rank_list',
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+	classRanking: data => {
+		return req({
+			url: '/schpanel/class_rank_list',
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+}

+ 15 - 0
src/api/module/score.js

@@ -0,0 +1,15 @@
+import req from '../request'
+
+module.exports = {
+	//人脸库
+	studentList: data => {
+		return req({
+			url: '/user/student_list',
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+}

+ 31 - 0
src/api/module/set.js

@@ -0,0 +1,31 @@
+import req from '../request'
+
+module.exports = {
+	//绑定百度人脸识别
+	binding: data => {
+		return req({
+			url: '/log/bdface_actv',
+			method: 'post',
+			data: data,
+		});
+	},
+	//获取绑定信息
+	bindingInfo: data => {
+		return req({
+			url: '/log/bdface_actv_lists',
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+	//密码校验
+	checkPassword: data => {
+		return req({
+			url: '/device/config/check_password',
+			method: 'post',
+			data: data,
+		});
+	},
+}

+ 20 - 0
src/api/module/test.js

@@ -0,0 +1,20 @@
+import req from '../request'
+
+module.exports = {
+	//长跑未识别成绩候选数据
+	runTidinfo: data => {
+		return req({
+			url: '/exam/run/tidinfo',
+			method: 'get',
+			data: data,
+		});
+	},
+	//长跑项目修正某同学的成绩
+	modifyRunData: data => {
+		return req({
+			url: '/exam/run/result',
+			method: 'post',
+			data: data,
+		});
+	},
+}

+ 31 - 0
src/api/module/train.js

@@ -0,0 +1,31 @@
+import req from '../request'
+
+module.exports = {
+	//获取测试项目
+	projectList: data => {
+		return req({
+			url: '/exam',
+			method: 'get',
+			data: data,
+			headers: {
+				showLoading: false,
+			}
+		});
+	},
+	//获取班级列表
+	classList: data => {
+		return req({
+			url: '/school/classes_list',
+			method: 'get',
+			data: data,
+		});
+	},
+	//获取学生成绩
+	studentReport: data => {
+		return req({
+			url: '/report/index',
+			method: 'get',
+			data: data,
+		});
+	},
+}

+ 123 - 0
src/api/request.ts

@@ -0,0 +1,123 @@
+import { ToastAndroid } from 'react-native';
+import { NavigationActions, StackActions } from '@react-navigation/native';
+import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
+import env from './env';
+import utils from '../utils/index';
+
+function jumpTo(){
+  //不直接用navigation.navigate是因为登录重新开始之前的页面消除
+  const resetAction = StackActions.replace('Login');
+  navigation.dispatch(resetAction);
+};
+
+function tansParams(params){
+  let result = '';
+  for (const propName of Object.keys(params)) {
+    const value = params[propName];
+    const part = encodeURIComponent(propName) + '=';
+    if (value !== null && value !== '' && typeof value !== 'undefined') {
+      if (typeof value === 'object') {
+        for (const key of Object.keys(value)) {
+          if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
+            const params = propName + '[' + key + ']';
+            const subPart = encodeURIComponent(params) + '=';
+            result += subPart + encodeURIComponent(value[key]) + '&';
+          }
+        }
+      } else {
+        result += part + encodeURIComponent(value) + '&';
+      }
+    }
+  }
+  return result;
+};
+
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
+axios.defaults.headers['auth'] = true;
+// 创建 axios 实例
+const service = axios.create({
+  baseURL: env,
+  timeout: 20000
+});
+
+// 请求拦截器
+service.interceptors.request.use(
+  (config: InternalAxiosRequestConfig) => {
+    //console.log("config", config)
+    const token = '';
+    if (token && Boolean(config.headers['auth']) == true) {
+      config.headers['Authorization'] = 'JWT ' + token;
+    }
+    if (!token && Boolean(config.headers['auth']) == true) {
+      delete config.headers['auth'];
+      const message = '缺少凭证,请重新登录!';
+      ToastAndroid.show(message, 5 * 1000);
+      jumpTo();
+      return Promise.reject(message);
+    }
+    // get请求修改Content-Type
+    if (config.method?.toLowerCase() === 'get') {
+      config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
+    }
+    // get请求映射params参数
+    if (config.method === 'get' && config.data) {
+      let url = config.url + '?' + utils.tansParams(config.data);
+      url = url.slice(0, -1);
+      config.data = {};
+      config.url = url;
+    }
+    // FormData数据去请求头Content-Type
+    if (config.data instanceof FormData) {
+      delete config.headers['Content-Type'];
+    }
+    delete config.headers['auth'];
+    return config;
+  },
+  (error: any) => {
+    console.log("333",error);
+    return Promise.reject(error);
+  }
+);
+
+// 响应拦截器
+service.interceptors.response.use(
+  (res: AxiosResponse) => {
+    console.log("res1111111",res)
+    const code = res.data.code;
+    const status = res.data.status;
+    const message = res.data.message;
+    console.log("111111111111")
+    if (code === 401) {
+      jumpTo();
+      ToastAndroid.show(message, 5 * 1000);
+      return Promise.reject('凭证已过期,请重新登录!');
+    } else if (status == 500) {
+      ToastAndroid.show(message, 5 * 1000);
+      return Promise.reject(message);
+    } else {
+      return Promise.resolve(res);
+    }
+  },
+  (error: any) => {
+    let { message, response } = error;
+    if (message == 'Network Error') {
+      message = '网络异常';
+    } else if (message.includes('timeout')) {
+      message = '请求超时';
+    } else if (response.status == 401) {
+      jumpTo();
+      ToastAndroid.show('请重新登录', 5 * 1000);
+      return Promise.reject('凭证已过期,请重新登录!');
+    } else if (message.includes('Request failed with status code')) {
+      if (response.data.status) {
+        message = response.data.message;
+      } else {
+        message = '系统接口' + message.substr(message.length - 3) + '异常';
+      }
+    }
+    ToastAndroid.show(message, 5 * 1000);
+    return Promise.reject(error);
+  }
+);
+
+export default service;

+ 36 - 0
src/pages/Custom/index.tsx

@@ -0,0 +1,36 @@
+import React from 'react';
+import { View, Button, NativeModules, StyleSheet, Text } from 'react-native';
+
+const { ToastModule } = NativeModules;
+
+const CustomScreen = () => {
+  const showToast = () => {
+    ToastModule.showToast('Hello from Kotlin!', 1); // 1=长时,0=短时
+  };
+
+  const getDeviceName = () => {
+    const device = ToastModule.getDeviceName();
+    alert(`Device: ${device}`);
+  };
+
+  return (
+    <View style={styles.container}>
+      <Button title="显示 Toast" onPress={showToast} />
+      <View style={styles.space} />
+      <Button title="获取设备名称" onPress={getDeviceName} />
+    </View>
+  );
+};
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    justifyContent: 'center',
+    padding: 20
+  },
+  space: {
+    height: 10
+  }
+});
+
+export default CustomScreen;

+ 22 - 0
src/pages/Face/index.tsx

@@ -0,0 +1,22 @@
+import React, { useEffect } from 'react';
+import { StyleSheet, Button, View, TouchableOpacity} from 'react-native';
+import { useNavigation } from '@react-navigation/native';
+// import { initFaceSDK, detectFace } from '../../utils/FaceRecognition';
+
+function FaceScreen() {
+  const navigation = useNavigation();
+  const handleDetect = async () => {
+    // const result = await detectFace();
+    // console.log('人脸识别结果:', result);
+  };
+
+  return (
+    <View style={{ flex: 1, justifyContent: 'center' }}>
+      <TouchableOpacity onPress={handleDetect}>
+        <Button title="检测人脸" />
+      </TouchableOpacity>
+    </View>
+  );
+}
+
+export default FaceScreen;

+ 28 - 0
src/pages/Home/index.tsx

@@ -0,0 +1,28 @@
+import React from 'react';
+import {StyleSheet, View, Text, TouchableOpacity} from 'react-native';
+import { useNavigation } from '@react-navigation/native';
+
+const HomeScreen = () => {
+  const navigation = useNavigation();
+  const getJump = async (data) => {
+    navigation.navigate(data);
+  };
+  return (
+    <View style={styles.main}>
+      <TouchableOpacity onPress={()=>getJump('Face')}>
+        <Text>1、进入人脸识别</Text>
+      </TouchableOpacity>
+      <TouchableOpacity onPress={()=>getJump('Custom')}>
+        <Text>2、自定义SDK</Text>
+      </TouchableOpacity>
+    </View>
+  );
+};
+
+const styles = StyleSheet.create({
+  main: {
+    paddingTop: 50,
+  },
+});
+
+export default HomeScreen;

+ 175 - 0
src/pages/Login/index.tsx

@@ -0,0 +1,175 @@
+import React, {useState} from 'react';
+import {
+  View,
+  Text,
+  TextInput,
+  TouchableOpacity,
+  StyleSheet,
+  Alert,
+  KeyboardAvoidingView,
+  Platform,
+  StatusBar,
+  ActivityIndicator,
+  ToastAndroid
+} from 'react-native';
+import { useNavigation } from '@react-navigation/native';
+
+const LoginScreen = ({}) => {
+  const navigation = useNavigation();
+  const [username, setUsername] = useState('manage1');
+  const [password, setPassword] = useState('trops@2022');
+  const [isLoading, setIsLoading] = useState(false);
+  const [secureTextEntry, setSecureTextEntry] = useState(true);
+
+  const handleLogin = async () => {
+    if (!username || !password) {
+      ToastAndroid.show('请输入用户名和密码',2000);
+      return;
+    }
+    setIsLoading(true);
+    try {
+      let params = {
+        username,
+        password,
+      };
+      global.$http.common.getLogin(params).then((res:any) => {
+        console.log("eeeeeee",res)
+        if (res.data.access_token) {
+          // let token = "JWT " + res.data.access_token;
+          ToastAndroid.show('登录成功',2000);
+          navigation.navigate('Home'); // 登录成功后跳转到主页
+        }
+      })
+    } catch (error:any) {
+      console.log(error);
+      ToastAndroid.show(error.response?.data?.message || '网络请求失败',2000);
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <KeyboardAvoidingView
+      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
+      style={styles.container}>
+      <StatusBar backgroundColor="#1E90FF" barStyle="light-content" />
+
+      <View style={styles.logoContainer}>
+        <Text style={styles.logoText}>欢迎登录</Text>
+      </View>
+
+      <View style={styles.formContainer}>
+        <TextInput
+          style={styles.input}
+          placeholder="用户名"
+          placeholderTextColor="#999"
+          value={username}
+          onChangeText={setUsername}
+          autoCapitalize="none"
+          autoCorrect={false}
+        />
+
+        <View style={styles.passwordInputContainer}>
+          <TextInput
+            style={styles.input}
+            placeholder="密码"
+            placeholderTextColor="#999"
+            secureTextEntry={secureTextEntry}
+            value={password}
+            onChangeText={setPassword}
+            autoCapitalize="none"
+            autoCorrect={false}
+          />
+          <TouchableOpacity
+            style={styles.togglePassword}
+            onPress={() => setSecureTextEntry(!secureTextEntry)}>
+            <Text style={styles.togglePasswordText}>
+              {secureTextEntry ? '显示' : '隐藏'}
+            </Text>
+          </TouchableOpacity>
+        </View>
+
+        <TouchableOpacity
+          style={styles.loginButton}
+          onPress={handleLogin}
+          disabled={isLoading}>
+          {isLoading ? (
+            <ActivityIndicator size="small" color="#fff" />
+          ) : (
+            <Text style={styles.loginButtonText}>登录</Text>
+          )}
+        </TouchableOpacity>
+      </View>
+    </KeyboardAvoidingView>
+  );
+};
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: '#fff',
+    paddingHorizontal: 30,
+  },
+  logoContainer: {
+    flex: 1,
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+  logoText: {
+    fontSize: 32,
+    fontWeight: 'bold',
+    color: '#1E90FF',
+  },
+  formContainer: {
+    flex: 2,
+    justifyContent: 'center',
+  },
+  input: {
+    height: 50,
+    backgroundColor: '#f5f5f5',
+    borderRadius: 8,
+    paddingHorizontal: 15,
+    marginBottom: 15,
+    fontSize: 16,
+  },
+  passwordInputContainer: {
+    position: 'relative',
+  },
+  togglePassword: {
+    position: 'absolute',
+    right: 15,
+    top: 15,
+  },
+  togglePasswordText: {
+    color: '#1E90FF',
+    fontSize: 14,
+  },
+  loginButton: {
+    height: 50,
+    backgroundColor: '#1E90FF',
+    borderRadius: 8,
+    justifyContent: 'center',
+    alignItems: 'center',
+    marginTop: 10,
+  },
+  loginButtonText: {
+    color: '#fff',
+    fontSize: 18,
+    fontWeight: 'bold',
+  },
+  footer: {
+    flexDirection: 'row',
+    justifyContent: 'center',
+    marginTop: 20,
+  },
+  footerText: {
+    color: '#666',
+  },
+  registerText: {
+    color: '#1E90FF',
+    marginLeft: 5,
+    fontWeight: 'bold',
+  },
+});
+
+export default LoginScreen;

+ 184 - 0
src/pages/Udp/index.tsx

@@ -0,0 +1,184 @@
+import React, { useState } from 'react';
+import {
+  View,
+  Text,
+  TextInput,
+  TouchableOpacity,
+  StyleSheet,
+  Alert,
+  KeyboardAvoidingView,
+  Platform,
+  StatusBar,
+  ActivityIndicator,
+  ToastAndroid
+} from 'react-native';
+import { useNavigation } from '@react-navigation/native';
+import { NativeModules } from 'react-native';
+import dgram from 'react-native-udp';
+console.log("dgram", dgram)
+
+
+
+
+
+const UdpScreen = ({ }) => {
+  const navigation = useNavigation();
+  const [username, setUsername] = useState('');
+  const [password, setPassword] = useState('');
+  const [isLoading, setIsLoading] = useState(false);
+  const [secureTextEntry, setSecureTextEntry] = useState(true);
+
+  const handleLogin = async () => {
+    if (!username || !password) {
+      ToastAndroid.show('请输入信息', 2000);
+      return;
+    }
+    setIsLoading(true);
+    try {
+      // 创建 UDP Socket 实例
+      const socket = dgram.createSocket('udp4');
+      // 检查实例是否创建成功
+      if (socket) {
+        console.log(password, username)
+        // 绑定端口、监听事件等操作
+        socket.bind(password, username, (err) => {
+          if (err) {
+            ToastAndroid.show('绑定失败', 2000);
+          } else { 
+            ToastAndroid.show('初始化成功', 2000);
+          }
+        });
+        // 监听绑定成功事件
+        socket.on('listening', () => {
+          const address = socket.address();
+          console.log("address",address)
+          ToastAndroid.show(`${address.address}:${address.port}`, 2000)
+        });
+      } else {
+        ToastAndroid.show('创建失败', 2000);
+      }
+
+    } catch (error: any) {
+      console.log(error);
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <KeyboardAvoidingView
+      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
+      style={styles.container}>
+      <StatusBar backgroundColor="#1E90FF" barStyle="light-content" />
+
+      <View style={styles.logoContainer}>
+        <Text style={styles.logoText}>测试UDP</Text>
+      </View>
+
+      <View style={styles.formContainer}>
+        <TextInput
+          style={styles.input}
+          placeholder="地址"
+          placeholderTextColor="#999"
+          value={username}
+          onChangeText={setUsername}
+          autoCapitalize="none"
+          autoCorrect={false}
+        />
+
+        <View style={styles.passwordInputContainer}>
+          <TextInput
+            style={styles.input}
+            placeholder="端口"
+            placeholderTextColor="#999"
+            value={password}
+            onChangeText={setPassword}
+            autoCapitalize="none"
+            autoCorrect={false}
+          />
+        </View>
+
+        <TouchableOpacity
+          style={styles.loginButton}
+          onPress={handleLogin}
+          disabled={isLoading}>
+          {isLoading ? (
+            <ActivityIndicator size="small" color="#fff" />
+          ) : (
+            <Text style={styles.loginButtonText}>连 接</Text>
+          )}
+        </TouchableOpacity>
+      </View>
+    </KeyboardAvoidingView>
+  );
+};
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: '#fff',
+    paddingHorizontal: 30,
+  },
+  logoContainer: {
+    flex: 1,
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+  logoText: {
+    fontSize: 32,
+    fontWeight: 'bold',
+    color: '#1E90FF',
+  },
+  formContainer: {
+    flex: 2,
+    justifyContent: 'center',
+  },
+  input: {
+    height: 50,
+    backgroundColor: '#f5f5f5',
+    borderRadius: 8,
+    paddingHorizontal: 15,
+    marginBottom: 15,
+    fontSize: 16,
+  },
+  passwordInputContainer: {
+    position: 'relative',
+  },
+  togglePassword: {
+    position: 'absolute',
+    right: 15,
+    top: 15,
+  },
+  togglePasswordText: {
+    color: '#1E90FF',
+    fontSize: 14,
+  },
+  loginButton: {
+    height: 50,
+    backgroundColor: '#1E90FF',
+    borderRadius: 8,
+    justifyContent: 'center',
+    alignItems: 'center',
+    marginTop: 10,
+  },
+  loginButtonText: {
+    color: '#fff',
+    fontSize: 18,
+    fontWeight: 'bold',
+  },
+  footer: {
+    flexDirection: 'row',
+    justifyContent: 'center',
+    marginTop: 20,
+  },
+  footerText: {
+    color: '#666',
+  },
+  registerText: {
+    color: '#1E90FF',
+    marginLeft: 5,
+    fontWeight: 'bold',
+  },
+});
+
+export default UdpScreen;

BIN
src/static/images/analysis/badminton.png


BIN
src/static/images/analysis/basketball.png


BIN
src/static/images/analysis/close.png


BIN
src/static/images/analysis/football.png


BIN
src/static/images/analysis/grade1.png


BIN
src/static/images/analysis/grade2.png


BIN
src/static/images/analysis/grade3.png


BIN
src/static/images/analysis/grade4.png


BIN
src/static/images/analysis/gymnastics.png


BIN
src/static/images/analysis/headPortrait.png


BIN
src/static/images/analysis/highknees.png


BIN
src/static/images/analysis/jump.png


BIN
src/static/images/analysis/jumpingjack.png


BIN
src/static/images/analysis/jumprope.png


BIN
src/static/images/analysis/lockClose.png


BIN
src/static/images/analysis/lockOpen.png


BIN
src/static/images/analysis/longjump.png


BIN
src/static/images/analysis/pingpong.png


BIN
src/static/images/analysis/pullUp.png


BIN
src/static/images/analysis/rankingIcon.png


BIN
src/static/images/analysis/resultIcon.png


BIN
src/static/images/analysis/run1000.png


BIN
src/static/images/analysis/run800.png


BIN
src/static/images/analysis/shotput.png


BIN
src/static/images/analysis/sidepullup.png


BIN
src/static/images/analysis/sitUp.png


BIN
src/static/images/analysis/skiprope.png


BIN
src/static/images/analysis/solidBall.png


BIN
src/static/images/analysis/swim.png


BIN
src/static/images/analysis/tennis.png


BIN
src/static/images/analysis/trijump.png


BIN
src/static/images/analysis/trops.png


BIN
src/static/images/analysis/verticaljump.png


BIN
src/static/images/analysis/volleyball.png


BIN
src/static/images/analysis/wushu.png


BIN
src/static/images/common/close.png


BIN
src/static/images/common/icon.png


BIN
src/static/images/common/loading.png


BIN
src/static/images/common/shine.png


BIN
src/static/images/home/back.png


BIN
src/static/images/home/btnbg1.png


BIN
src/static/images/home/btnbg1a.png


BIN
src/static/images/home/btnbg2.png


BIN
src/static/images/home/btnbg3.png


BIN
src/static/images/home/course.png


BIN
src/static/images/home/enter.png


BIN
src/static/images/home/pe.png


BIN
src/static/images/home/ranking.png


BIN
src/static/images/home/score.png


BIN
src/static/images/home/setbg.png


BIN
src/static/images/home/test.png


BIN
src/static/images/home/train.png


BIN
src/static/images/login/bg.png


BIN
src/static/images/login/btn.png


BIN
src/static/images/login/logo.png


BIN
src/static/images/login/xian.png


BIN
src/static/images/ranking/arrow.png


BIN
src/static/images/ranking/logo.png


BIN
src/static/images/ranking/mao1.png


BIN
src/static/images/ranking/mao2.png


BIN
src/static/images/ranking/mao3.png


BIN
src/static/images/ranking/noData.png


BIN
src/static/images/ranking/rankingBg.png


BIN
src/static/images/set/bug.png


BIN
src/static/images/set/camera.png


BIN
src/static/images/set/face.png


BIN
src/static/images/set/guanbi.png


BIN
src/static/images/set/guding.png


BIN
src/static/images/set/tuichu.png


BIN
src/static/images/set/zhuan.png


BIN
src/static/images/train/areabg1.png


BIN
src/static/images/train/areabg2.png


BIN
src/static/images/train/arrow.png


BIN
src/static/images/train/close.png


BIN
src/static/images/train/exitbg.png


BIN
src/static/images/train/greenbg.png


BIN
src/static/images/train/headbg.png


BIN
src/static/images/train/noImg.png


BIN
src/static/images/train/select.png


BIN
src/static/images/train/tanhao.png


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels