diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f6ae89b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,44 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+/linux/
+/windows/
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/.metadata b/.metadata
new file mode 100644
index 0000000..9c0232e
--- /dev/null
+++ b/.metadata
@@ -0,0 +1,36 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "b0850beeb25f6d5b10426284f506557f66181b36"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: b0850beeb25f6d5b10426284f506557f66181b36
+ base_revision: b0850beeb25f6d5b10426284f506557f66181b36
+ - platform: android
+ create_revision: b0850beeb25f6d5b10426284f506557f66181b36
+ base_revision: b0850beeb25f6d5b10426284f506557f66181b36
+ - platform: linux
+ create_revision: b0850beeb25f6d5b10426284f506557f66181b36
+ base_revision: b0850beeb25f6d5b10426284f506557f66181b36
+ - platform: windows
+ create_revision: b0850beeb25f6d5b10426284f506557f66181b36
+ base_revision: b0850beeb25f6d5b10426284f506557f66181b36
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/.vs/CMakeWorkspaceSettings.json b/.vs/CMakeWorkspaceSettings.json
new file mode 100644
index 0000000..d3e1057
--- /dev/null
+++ b/.vs/CMakeWorkspaceSettings.json
@@ -0,0 +1,3 @@
+{
+ "enableCMake": false
+}
\ No newline at end of file
diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json
new file mode 100644
index 0000000..f8b4888
--- /dev/null
+++ b/.vs/ProjectSettings.json
@@ -0,0 +1,3 @@
+{
+ "CurrentProjectSetting": null
+}
\ No newline at end of file
diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json
new file mode 100644
index 0000000..6b61141
--- /dev/null
+++ b/.vs/VSWorkspaceState.json
@@ -0,0 +1,6 @@
+{
+ "ExpandedNodes": [
+ ""
+ ],
+ "PreviewInSolutionExplorer": false
+}
\ No newline at end of file
diff --git a/.vs/cpnav/FileContentIndex/7799ca13-2a7a-49c4-8d88-22a4a0c5fbe5.vsidx b/.vs/cpnav/FileContentIndex/7799ca13-2a7a-49c4-8d88-22a4a0c5fbe5.vsidx
new file mode 100644
index 0000000..0812968
Binary files /dev/null and b/.vs/cpnav/FileContentIndex/7799ca13-2a7a-49c4-8d88-22a4a0c5fbe5.vsidx differ
diff --git a/.vs/cpnav/v17/.wsuo b/.vs/cpnav/v17/.wsuo
new file mode 100644
index 0000000..ecc08aa
Binary files /dev/null and b/.vs/cpnav/v17/.wsuo differ
diff --git a/.vs/cpnav/v17/Browse.VC.db b/.vs/cpnav/v17/Browse.VC.db
new file mode 100644
index 0000000..f12b81e
Binary files /dev/null and b/.vs/cpnav/v17/Browse.VC.db differ
diff --git a/.vs/cpnav/v17/DocumentLayout.json b/.vs/cpnav/v17/DocumentLayout.json
new file mode 100644
index 0000000..df10507
--- /dev/null
+++ b/.vs/cpnav/v17/DocumentLayout.json
@@ -0,0 +1,23 @@
+{
+ "Version": 1,
+ "WorkspaceRootPath": "D:\\Android\\2\\cpnav\\",
+ "Documents": [],
+ "DocumentGroupContainers": [
+ {
+ "Orientation": 0,
+ "VerticalTabListWidth": 256,
+ "DocumentGroups": [
+ {
+ "DockedWidth": 200,
+ "SelectedChildIndex": -1,
+ "Children": [
+ {
+ "$type": "Bookmark",
+ "Name": "ST:0:0:{cce594b6-0c39-4442-ba28-10c64ac7e89f}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
new file mode 100644
index 0000000..d1f9079
Binary files /dev/null and b/.vs/slnx.sqlite differ
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..6f56801
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 0000000..09c3c8e
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,58 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file("local.properties")
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader("UTF-8") { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
+if (flutterVersionCode == null) {
+ flutterVersionCode = "1"
+}
+
+def flutterVersionName = localProperties.getProperty("flutter.versionName")
+if (flutterVersionName == null) {
+ flutterVersionName = "1.0"
+}
+
+android {
+ namespace = "cn.mcxa.cpnav"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "cn.mcxa.cpnav"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+ minSdk = flutter.minSdkVersion
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutterVersionCode.toInteger()
+ versionName = flutterVersionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..87ff801
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/java/io/flutter/plugins/BootCompleteReceiver.java b/android/app/src/main/java/io/flutter/plugins/BootCompleteReceiver.java
new file mode 100644
index 0000000..1f4dc71
--- /dev/null
+++ b/android/app/src/main/java/io/flutter/plugins/BootCompleteReceiver.java
@@ -0,0 +1,19 @@
+package cn.mcxa.cpnav;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class BootCompleteReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if(Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())){
+ Intent thisIntent = new Intent(context, MainActivity.class);
+ thisIntent.setAction("android.intent.action.MAIN");
+ thisIntent.addCategory("android.intent.category.LAUNCHER");
+ thisIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(thisIntent);
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/cn/mcxa/cpnav/MainActivity.kt b/android/app/src/main/kotlin/cn/mcxa/cpnav/MainActivity.kt
new file mode 100644
index 0000000..4f03b03
--- /dev/null
+++ b/android/app/src/main/kotlin/cn/mcxa/cpnav/MainActivity.kt
@@ -0,0 +1,5 @@
+package cn.mcxa.cpnav
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..d2ffbff
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,18 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = "../build"
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..3b5b324
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e1ca574
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..536165d
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1,25 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }()
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+ id "com.android.application" version "7.3.0" apply false
+ id "org.jetbrains.kotlin.android" version "1.7.10" apply false
+}
+
+include ":app"
diff --git a/images/navi_pointer.png b/images/navi_pointer.png
new file mode 100644
index 0000000..2906654
Binary files /dev/null and b/images/navi_pointer.png differ
diff --git a/images/pilerCar.png b/images/pilerCar.png
new file mode 100644
index 0000000..799a54a
Binary files /dev/null and b/images/pilerCar.png differ
diff --git a/images/satellite.png b/images/satellite.png
new file mode 100644
index 0000000..6dc2ab4
Binary files /dev/null and b/images/satellite.png differ
diff --git a/lib/appbar.dart b/lib/appbar.dart
new file mode 100644
index 0000000..c4e0b3b
--- /dev/null
+++ b/lib/appbar.dart
@@ -0,0 +1,165 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+// import '../login_in/connect/bluetooth_page.dart';
+// import '../login_in/connect/connect_type.dart';
+// import '../login_in/getx/real_data.dart';
+// import 'main.dart';
+
+// final RealController controller1 = Get.find();
+
+class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
+ final double appBarHeight;
+ final RxInt _currentIndex;
+ final isDarkMode = false.obs;
+ final isCardVisible = false.obs;
+ final isDataVisible = false.obs;
+ CustomAppBar({required this.appBarHeight, required RxInt currentIndex})
+ : _currentIndex = currentIndex;
+
+ @override
+ Widget build(BuildContext context) {
+ const textStyle = TextStyle(fontSize: 16);
+ return AppBar(
+ toolbarHeight: 40,
+ centerTitle: true, // 标题居中
+ title: Obx(() {
+ if (_currentIndex.value == 0) {
+ return const Text("桩点:", style: textStyle);
+ } else if (_currentIndex.value == 1) {
+ return const Text("设备:", style: textStyle);
+ } else {
+ return const Text("系统:", style: textStyle);
+ }
+ }),
+ // title: _currentIndex.value == 0
+ // ? Obx(() => Text("桩点:${realController.pileId.value}",
+ // style: textStyle))
+ // : const Text("设备:", style: textStyle),
+ // // const Center(
+ // // child: Obx(() => Text("设备:", style: textStyle)),
+ // // ),
+ // title: Obx(() {
+ // if (_currentIndex.value == 1) {
+ // return const Text("设备:", style: textStyle);
+ // } else if (_currentIndex.value == 0) {
+ // return Text("桩点:${realController.pileId.value}",
+ // style: textStyle);
+ // } else {
+ // return const Text("系统:", style: textStyle);
+ // }
+ // }),
+
+ actions: [
+ InkWell(
+ onTap: () {
+ isDarkMode.value = !isDarkMode.value;
+ },
+ child: Icon(
+ isDarkMode.value ? Icons.dark_mode : Icons.sunny,
+ size: 35,
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ InkWell(
+ onTap: () {
+ // Navigator.push(context,
+ // MaterialPageRoute(builder: (context) => const ScenceMap())),
+ },
+ child: Image(
+ image: const AssetImage('images/satellite.png'),
+ // width: 40,
+ color: isDarkMode.value
+ ? Colors.white70
+ : const Color.fromARGB(200, 29, 28, 28),
+ height: 40,
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ _currentIndex.value == 1
+ ? Row(
+ children: [
+ Obx(
+ () => InkWell(
+ onTap: () {
+ // 点击图标时显示对点卡片
+ // sight.isCardVisible.value =
+ // !sight.isCardVisible.value; // 确保控制器已定义
+ },
+ child: Icon(
+ Icons.my_location_sharp,
+ size: 35,
+ color: isCardVisible.value
+ ? Colors.blue
+ // : const Color.fromARGB(200, 29, 28, 28),
+ : (isDarkMode.value
+ ? Colors.white70
+ : const Color.fromARGB(200, 29, 28, 28)),
+ ), // 新增图标
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Obx(
+ () => InkWell(
+ onTap: () {
+ // final RealController controller1 = Get.find(); // 获取控制器
+ // controller1.isDataVisible.value =
+ // !controller1.isDataVisible.value; // 更新控制器中的值
+ },
+ child: Icon(
+ Icons.date_range_rounded,
+ size: 35,
+ color: isDataVisible.value
+ ? Colors.blue
+ : (isDarkMode.value
+ ? Colors.white70
+ : const Color.fromARGB(200, 29, 28, 28)),
+ ), // 新增图标
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ UnconstrainedBox(
+ child: SizedBox(
+ height: 30,
+ child: Builder(
+ builder: (context) => InkWell(
+ child: Icon(
+ Icons.settings_outlined,
+ size: 35,
+ color: isDarkMode.value
+ ? Colors.white70
+ : const Color.fromARGB(200, 29, 28, 28),
+ ),
+ onTap: () => Scaffold.of(context).openEndDrawer(),
+ ),
+ ),
+ ),
+ )
+ ],
+ )
+ : const Text(""),
+ // Obx(() => Icon(
+ // blueToothController.connectedType.value == ConnectType.wifi
+ // ? Icons.wifi
+ // : (blueToothController.connectedType.value ==
+ // ConnectType.bluetooth
+ // ? Icons.bluetooth
+ // : Icons.close),
+ // color: Colors.green,
+ // size: 30,
+ // ))
+ ],
+ );
+ }
+
+ @override
+ Size get preferredSize => Size.fromHeight(appBarHeight);
+}
diff --git a/lib/constants.dart b/lib/constants.dart
new file mode 100644
index 0000000..107fa7a
--- /dev/null
+++ b/lib/constants.dart
@@ -0,0 +1,12 @@
+import 'package:flutter/material.dart';
+
+enum Themes { device, light, dark, oled }
+
+enum DayType { clear, check, fail, skip }
+
+class HaboColors {
+ static const Color primary = Color(0xFF09BF30);
+ static const Color red = Color(0xFFF44336);
+ static const Color skip = Color(0xFFFBC02D);
+ static const Color orange = Color(0xFFFF9800);
+}
diff --git a/lib/helpers.dart b/lib/helpers.dart
new file mode 100644
index 0000000..0eada58
--- /dev/null
+++ b/lib/helpers.dart
@@ -0,0 +1,21 @@
+import 'package:flutter/material.dart';
+
+TimeOfDay parseTimeOfDay(String? value) {
+ if (value != null) {
+ var times = value.split(':');
+ if (times.length == 2) {
+ return TimeOfDay(hour: int.parse(times[0]), minute: int.parse(times[1]));
+ }
+ }
+
+ return const TimeOfDay(hour: 12, minute: 0);
+}
+
+DateTime transformDate(DateTime date) {
+ return DateTime.utc(
+ date.year,
+ date.month,
+ date.day,
+ 12,
+ );
+}
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..9733d20
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,336 @@
+import 'package:cpnav/appbar.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:get/get.dart';
+import 'pages/pass_track/view.dart';
+
+void main() {
+ WidgetsFlutterBinding.ensureInitialized();
+ SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); //设置全屏
+ runApp(const MyApp());
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ // This widget is the root of your application.
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Demo',
+ theme: ThemeData(
+ // This is the theme of your application.
+ //
+ // TRY THIS: Try running your application with "flutter run". You'll see
+ // the application has a purple toolbar. Then, without quitting the app,
+ // try changing the seedColor in the colorScheme below to Colors.green
+ // and then invoke "hot reload" (save your changes or press the "hot
+ // reload" button in a Flutter-supported IDE, or press "r" if you used
+ // the command line to start the app).
+ //
+ // Notice that the counter didn't reset back to zero; the application
+ // state is not lost during the reload. To reset the state, use hot
+ // restart instead.
+ //
+ // This works for code too, not just values: Most code changes can be
+ // tested with just a hot reload.
+ colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+ useMaterial3: true,
+ ),
+ home: const MyHomePage(title: 'Flutter Demo Home Page'),
+ );
+ }
+}
+
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({super.key, required this.title});
+
+ // This widget is the home page of your application. It is stateful, meaning
+ // that it has a State object (defined below) that contains fields that affect
+ // how it looks.
+
+ // This class is the configuration for the state. It holds the values (in this
+ // case the title) provided by the parent (in this case the App widget) and
+ // used by the build method of the State. Fields in a Widget subclass are
+ // always marked "final".
+
+ final String title;
+
+ @override
+ State createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State {
+ late bool isPortrait;
+ late double appBarHeight = 34.0;
+
+ final _currentIndex = 0.obs;
+ final List _pages = [
+ PassTrack(),
+ Container(
+ color: Colors.green,
+ ),
+ Container(
+ color: Colors.blue,
+ ),
+ Container(
+ color: Colors.yellow,
+ ),
+ Container(
+ color: Colors.purple,
+ ),
+ ];
+ @override
+ Widget build(BuildContext context) {
+ // This method is rerun every time setState is called, for instance as done
+ // by the _incrementCounter method above.
+ //
+ // The Flutter framework has been optimized to make rerunning build methods
+ // fast, so that you can just rebuild anything that needs updating rather
+ // than having to individually change instances of widgets.
+ return Scaffold(
+ appBar: PreferredSize(
+ // TRY THIS: Try changing the color here to a specific color (to
+ // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
+ // change color while the other colors stay the same.
+ // backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+ // Here we take the value from the MyHomePage object that was created by
+ // the App.build method, and use it to set our appbar title.
+ preferredSize: Size.fromHeight(appBarHeight),
+ child: CustomAppBar(appBarHeight: 56, currentIndex: _currentIndex),
+ ),
+ body: OrientationBuilder(
+ builder: (context, orientation) {
+ // final size = MediaQuery.of(context).size;
+ appBarHeight = Orientation.portrait == orientation ? 56.0 : 34.0;
+ isPortrait = Orientation.portrait == orientation ? true : false;
+ appBarHeight = Orientation.portrait == orientation ? 56.0 : 34.0;
+ if (!isPortrait) {
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Expanded(
+ child: _pages[_currentIndex.value],
+ ),
+ const VerticalDivider(
+ width: 1, // 设置高度为1
+ thickness: 1,
+ ),
+ SizedBox(
+ width: 48,
+ child: SafeArea(
+ child: LayoutBuilder(builder: (context, constraints) {
+ // 根据屏幕宽度判断横屏或竖屏
+ // if (!isPortrait) {
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Column(
+ children: [
+ IconButton(
+ onPressed: () {
+ setState(() {
+ _currentIndex.value = 0;
+ });
+ },
+ icon:
+ const Icon(Icons.date_range_rounded),
+ color: _currentIndex.value == 0
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ Align(
+ alignment: Alignment.center,
+ child: Text(
+ '实时',
+ style: TextStyle(
+ fontSize: 12,
+ color: _currentIndex.value == 0
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ ),
+ ),
+ ],
+ ),
+ const Divider(
+ height: 1, // 设置高度为1
+ thickness: 1,
+ ),
+ //
+ Column(
+ children: [
+ IconButton(
+ onPressed: () {
+ setState(() {
+ _currentIndex.value = 1;
+ });
+ },
+ icon: const Icon(Icons.map_outlined),
+ color: _currentIndex.value == 1
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ Align(
+ alignment: Alignment.center,
+ child: Text(
+ '桩点',
+ style: TextStyle(
+ fontSize: 12,
+ color: _currentIndex.value == 1
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ ),
+ ),
+ ],
+ ),
+ const Divider(),
+ Column(
+ children: [
+ IconButton(
+ onPressed: () {
+ setState(() {
+ _currentIndex.value = 2;
+ });
+ },
+ icon: const Icon(Icons.my_location_sharp),
+ color: _currentIndex.value == 2
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ Align(
+ alignment: Alignment.center,
+ child: Text(
+ '任务',
+ style: TextStyle(
+ fontSize: 12,
+ color: _currentIndex.value == 2
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ ),
+ ),
+ ],
+ ),
+ const Divider(),
+ Column(
+ children: [
+ IconButton(
+ onPressed: () {
+ setState(() {
+ _currentIndex.value = 3;
+ });
+ },
+ icon: const Icon(
+ Icons.table_chart_outlined),
+ color: _currentIndex.value == 3
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ Align(
+ alignment: Alignment.center,
+ child: Text(
+ '历史',
+ style: TextStyle(
+ fontSize: 12,
+ color: _currentIndex.value == 3
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ ),
+ ),
+ ],
+ ),
+ const Divider(),
+ Column(
+ children: [
+ IconButton(
+ onPressed: () {
+ setState(() {
+ _currentIndex.value = 4;
+ });
+ },
+ icon: const Icon(Icons.settings),
+ color: _currentIndex.value == 4
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ Align(
+ alignment: Alignment.center,
+ child: Text(
+ '设置',
+ style: TextStyle(
+ fontSize: 12,
+ color: _currentIndex.value == 4
+ ? const Color.fromARGB(
+ 255, 60, 95, 123)
+ : Colors.grey,
+ ),
+ ),
+ ),
+ ],
+ )
+ ]);
+ //
+ }),
+ ),
+ )
+ ]);
+ } //
+
+ else {
+ // 竖屏布局,保持原有底部导航栏样式
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Expanded(
+ flex: 12,
+ child: _pages[_currentIndex.value],
+ ),
+ // VerticalDivider(),
+ Expanded(
+ flex: 1,
+ child: SizedBox(
+ height: 48,
+ child: BottomNavigationBar(
+ type: BottomNavigationBarType.fixed,
+ currentIndex: _currentIndex.value,
+ onTap: (index) {
+ setState(() {
+ _currentIndex.value = index;
+ });
+ },
+ items: const [
+ BottomNavigationBarItem(
+ icon: Icon(Icons.date_range_rounded),
+ label: "实时"),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.map_outlined), label: "计划"),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.my_location_sharp),
+ label: "对点"),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.table_chart_outlined),
+ label: "历史"),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.settings), label: "设置"),
+ ]),
+ ),
+ )
+ ]);
+ }
+ },
+ ));
+ }
+}
diff --git a/lib/models/coord_trans.dart b/lib/models/coord_trans.dart
new file mode 100644
index 0000000..8921f90
--- /dev/null
+++ b/lib/models/coord_trans.dart
@@ -0,0 +1,63 @@
+class CoordTrans {
+ int id;
+ // ignore: non_constant_identifier_names
+ double L0;
+ String belt;
+ String? calibs;
+ String dstEllipsoid;
+ double dx;
+ double dy;
+ double dz;
+ double wx;
+ double wy;
+ double wz;
+ double k;
+ double elevation;
+ int isMain;
+ String name;
+ double rota;
+ String srcEllipsoid;
+ CoordTrans({
+ required this.name,
+ // ignore: non_constant_identifier_names
+ required this.L0,
+ required this.belt,
+ this.calibs,
+ required this.dstEllipsoid,
+ required this.dx,
+ required this.dy,
+ required this.dz,
+ required this.id,
+ required this.wx,
+ required this.wy,
+ required this.wz,
+ required this.k,
+ required this.elevation,
+ required this.isMain,
+ required this.rota,
+ required this.srcEllipsoid,
+ });
+ factory CoordTrans.fromJson(Map data) {
+ return CoordTrans(
+ name: data['name'],
+ id: data['id'],
+ L0: data['L0'].toDouble(),
+ belt: data['belt'],
+ calibs: data['calibs'],
+ dstEllipsoid: data['dstEllipsoid'],
+ dx: data['dx'].toDouble(),
+ dy: data['dy'].toDouble(),
+ dz: data['dz'].toDouble(),
+ wx: data['wx'].toDouble(),
+ wy: data['wy'].toDouble(),
+ wz: data['wz'].toDouble(),
+ rota: data['rota'].toDouble(),
+ k: data['k'].toDouble(),
+ isMain: data['is_main'],
+ elevation: data['elevation'].toDouble(),
+ srcEllipsoid: data['srcEllipsoid'],
+ );
+ }
+
+ void forEach(Null Function(dynamic key, dynamic value) param0) {}
+}
diff --git a/lib/models/login.dart b/lib/models/login.dart
new file mode 100644
index 0000000..6a33920
--- /dev/null
+++ b/lib/models/login.dart
@@ -0,0 +1,75 @@
+import 'package:get/get.dart';
+import 'package:get_storage/get_storage.dart';
+
+import 'package:cpnav/models/user.dart';
+
+class LoginPrefs extends GetxController {
+ static const String expireStr = "expire"; //用户名
+ static const String tokenStr = "token"; //token
+ static const String phoneStr = "phone";
+ final box = GetStorage(); // 实例化 GetStorage
+
+ Future init() async {
+ await GetStorage.init(); // 初始化 GetStorage
+ return 'ok';
+ }
+
+ void saveExpire(int expire) {
+ box.write(expireStr, expire);
+ update();
+ }
+
+ int getExpire() {
+ return box.read(expireStr) ?? 0;
+ }
+
+ void saveToken(String token) {
+ box.write(tokenStr, token);
+ update();
+ }
+
+ String getToken() {
+ return box.read(tokenStr) ?? "";
+ }
+
+ void removeExpire() {
+ box.remove(expireStr);
+ update();
+ }
+
+ void removeToken() {
+ box.remove(tokenStr);
+ update();
+ }
+
+ void savePhone(String phone) {
+ box.write(phoneStr, phone);
+ update();
+ }
+
+ String getPhone() {
+ return box.read(phoneStr) ?? "";
+ }
+
+ void clearLogin() {
+ box.erase(); // 清除所有数据
+ update();
+ }
+}
+
+class UserController extends GetxController {
+ final box = GetStorage(); // 实例化 GetStorage
+
+ UserModel? getUser() {
+ final userMap = box.read('user');
+ if (userMap != null) {
+ return UserModel.fromJson(userMap);
+ }
+ return null;
+ }
+
+ void setUser(Map user) {
+ box.write('user', user);
+ update();
+ }
+}
diff --git a/lib/models/user.dart b/lib/models/user.dart
new file mode 100644
index 0000000..5d94f09
--- /dev/null
+++ b/lib/models/user.dart
@@ -0,0 +1,53 @@
+class UserModel {
+ int id;
+ String updateTime;
+ String departmentId;
+ String name;
+ int passwordV;
+ String nickName;
+ String headImg;
+ String phone;
+ String email;
+ int status;
+ String remark;
+ String orgCode;
+ String title;
+ String titleImg;
+ String username;
+ UserModel({
+ required this.name,
+ required this.departmentId,
+ required this.email,
+ required this.headImg,
+ required this.nickName,
+ required this.phone,
+ required this.title,
+ required this.titleImg,
+ required this.id,
+ required this.updateTime,
+ required this.orgCode,
+ required this.status,
+ required this.passwordV,
+ required this.remark,
+ required this.username,
+ });
+ factory UserModel.fromJson(Map data) {
+ return UserModel(
+ name: data['name'],
+ departmentId: data['departmentId'],
+ email: data['email'] ?? "",
+ headImg: data['headImg'] ?? "",
+ nickName: data['nickName'] ?? "",
+ passwordV: data['passwordV'],
+ phone: data['phone'] ?? "",
+ title: data['title'] ?? "",
+ titleImg: data['title_img'] ?? "",
+ id: data['id'],
+ updateTime: data['updateTime'],
+ orgCode: data['org_code'],
+ status: data['status'],
+ remark: data['remark'] ?? "",
+ username: data['username'],
+ );
+ }
+}
diff --git a/lib/pages/login/login_page.dart b/lib/pages/login/login_page.dart
new file mode 100644
index 0000000..d54d404
--- /dev/null
+++ b/lib/pages/login/login_page.dart
@@ -0,0 +1,392 @@
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/scheduler.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:cpnav/pages/login/loginprefs.dart';
+import 'package:cpnav/service/base.dart';
+
+class Login extends StatefulWidget {
+ const Login({super.key});
+
+ @override
+ State createState() => _LoginState();
+}
+
+class _LoginState extends State with SingleTickerProviderStateMixin {
+ //with SingleTickerProviderStateMixin 使this 不报错
+ late TabController _tabController;
+ //初始化实例
+ @override
+ void initState() {
+ _tabController = TabController(length: 2, vsync: this);
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ _tabController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('欢迎登录'),
+ ),
+ body: Column(
+ children: [
+ TabBar(
+ labelColor: Colors.black, // 设置选中标签的字体颜色为黑色
+ unselectedLabelColor: Colors.grey, // 设置未选中标签的字体颜色为灰色
+ labelStyle: const TextStyle(color: Colors.black), // 设置选中标签的字体颜色为黑色
+ unselectedLabelStyle:
+ const TextStyle(color: Colors.grey), // 设置未选中标签的字体颜色为灰色
+ controller: _tabController,
+ tabs: const [
+ Tab(text: '手机号登录', icon: Icon(Icons.phone_android)),
+ Tab(text: '账号登录', icon: Icon(Icons.account_box_outlined)),
+ ],
+ ),
+ Expanded(
+ child: TabBarView(
+ controller: _tabController,
+ children: const [
+ PhoneLoginPage(),
+ AccountLoginPage(),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class AccountLoginPage extends StatefulWidget {
+ const AccountLoginPage({super.key});
+
+ @override
+ State createState() => _AccountLoginPageState();
+}
+
+class _AccountLoginPageState extends State {
+ //初始化FormState
+ final _formKey = GlobalKey();
+ String username = "";
+ String password = "";
+ String verifyCode = "";
+ String svgString = "";
+ String captchaId = "";
+ @override
+ void initState() {
+ super.initState();
+ SchedulerBinding.instance.addPostFrameCallback((_) async {
+ await changeCaptcha();
+ });
+ }
+
+ changeCaptcha() async {
+ var captcha = await GetServices().getCaptcha();
+ setState(() {
+ svgString = captcha['data'];
+ captchaId = captcha['captchaId'];
+ });
+ }
+
+ showErrorSnackbar(BuildContext context, String text) {
+ final snackBar = SnackBar(
+ content: Text(text),
+ backgroundColor: Colors.red,
+ );
+
+ ScaffoldMessenger.of(context).showSnackBar(snackBar);
+ }
+
+ LoginPrefs loginPrefs = LoginPrefs();
+ bool _obscureText = false;
+ @override
+ Widget build(BuildContext context) {
+ return SingleChildScrollView(
+ child: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ Form(
+ key: _formKey,
+ child: Column(
+ children: [
+ // 账号输入框
+ TextFormField(
+ decoration: const InputDecoration(
+ labelText: '用户名:',
+ ),
+ onSaved: (String? value) => username = value!,
+ validator: (String? value) {
+ String str = "";
+
+ RegExp regex = RegExp(r'^[a-zA-Z0-9]+$');
+ if (value!.isEmpty) {
+ str = '用户名不能为空';
+ } else if (!regex.hasMatch(value)) {
+ str = '请输入有效的账号';
+ }
+
+ return str == "" ? null : str;
+ },
+ ),
+ const SizedBox(height: 16.0),
+
+ // 密码输入框
+ TextFormField(
+ decoration: InputDecoration(
+ labelText: '密码:',
+ suffixIcon: IconButton(
+ icon: Icon(
+ _obscureText
+ ? Icons.visibility
+ : Icons.visibility_off,
+ ),
+ onPressed: () {
+ setState(() {
+ _obscureText = !_obscureText; // 切换密码可见状态
+ });
+ }),
+ ),
+ obscureText: _obscureText,
+ onSaved: (String? value) => password = value!,
+ validator: (String? value) {
+ String str = "";
+ RegExp regex = RegExp(r'^[a-zA-Z0-9@#$]+$');
+
+ if (value!.isEmpty) {
+ str = '密码不能为空';
+ } else if (!regex.hasMatch(value)) {
+ str = '请输入有效的密码';
+ }
+
+ return str == "" ? null : str;
+ },
+ ),
+ const SizedBox(height: 24.0),
+ Row(
+ children: [
+ Expanded(
+ child: TextFormField(
+ decoration: const InputDecoration(
+ labelText: '验证码:',
+ ),
+ keyboardType: TextInputType.phone,
+ validator: (String? value) {
+ String str = "";
+
+ if (value!.isEmpty) {
+ str = '验证码不能为空';
+ }
+
+ return str == "" ? null : str;
+ },
+ onSaved: (String? value) => verifyCode = value!,
+ ),
+ ),
+ ElevatedButton(
+ onPressed: () async {
+ changeCaptcha();
+ },
+ child: svgString.isNotEmpty
+ ? SvgPicture.string(
+ svgString,
+ width: 70, // 设置宽度
+ height: 40, // 设置高度
+ color: Colors.black,
+ )
+ : const Text(""))
+ ],
+ ),
+ // 登录按钮
+ ElevatedButton(
+ onPressed: () async {
+ if (_formKey.currentState!.validate()) {
+ _formKey.currentState!.save(); //必须
+ var res = await GetServices().getAccountLogin(
+ captchaId, password, username, verifyCode);
+ setState(() {
+ if (res['code'] != 1000) {
+ changeCaptcha();
+ showErrorSnackbar(context, res["message"]);
+ } else {
+ loginPrefs.saveExpire((res["data"]["expire"]));
+ loginPrefs.saveToken((res["data"]["token"]));
+ Navigator.pushNamed(context, 'home'); //跳转至首页
+ }
+ });
+ }
+ },
+ child: const Text('登录'),
+ ),
+ ],
+ ))
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class PhoneLoginPage extends StatefulWidget {
+ const PhoneLoginPage({super.key});
+
+ @override
+ State createState() => _PhoneLoginPageState();
+}
+
+class _PhoneLoginPageState extends State {
+ String phoneNumber = "";
+ String smsCode = "";
+ bool issmsCode = false;
+ String smsText = "获取验证码";
+ int _seconds = 60;
+ late Timer _timer;
+ //初始化FormState
+ final _formKey = GlobalKey();
+ LoginPrefs loginPrefs = LoginPrefs();
+ @override
+ void initState() {
+ super.initState();
+
+ phoneNumber = loginPrefs.getPhone();
+ }
+
+ void startTimer() {
+ _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
+ if (_seconds > 0) {
+ _seconds -= 1;
+ smsText = "重新获取(${_seconds}s)";
+ } else {
+ _timer.cancel(); // 到0时关闭定时器
+ smsText = "获取验证码";
+ }
+ });
+ }
+
+ showErrorSnackbar(BuildContext context, String text) {
+ final snackBar = SnackBar(
+ content: Text(text),
+ backgroundColor: Colors.red,
+ );
+
+ ScaffoldMessenger.of(context).showSnackBar(snackBar);
+ }
+
+ final GlobalKey _scaffoldKey = GlobalKey();
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ key: _scaffoldKey,
+ padding: const EdgeInsets.all(16.0),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ Form(
+ key: _formKey,
+ child:
+ // 手机号输入框
+ Column(
+ children: [
+ TextFormField(
+ maxLength: 11,
+ initialValue: phoneNumber,
+ decoration: const InputDecoration(
+ labelText: '手机号',
+ ),
+ keyboardType: TextInputType.phone,
+ validator: (String? value) {
+ String str = "";
+ final RegExp phoneRegex = RegExp(r'^[1-9]\d{10}$');
+ if (value!.isEmpty) {
+ str = '手机号不能为空';
+ } else if (!phoneRegex.hasMatch(value)) {
+ str = '请输入有效的手机号';
+ }
+
+ return str == "" ? null : str;
+ },
+ onSaved: (String? value) => phoneNumber = value!,
+ ),
+ Row(
+ children: [
+ Expanded(
+ child: TextFormField(
+ maxLength: 6,
+ decoration: const InputDecoration(
+ labelText: '验证码',
+ ),
+ keyboardType: TextInputType.phone,
+ validator: (String? value) {
+ String str = "";
+ if (value!.isEmpty) {
+ str = '验证码不能为空';
+ }
+
+ if (issmsCode) {
+ return null;
+ }
+ return str == "" ? null : str;
+ },
+ onSaved: (val) => smsCode = val!,
+ ),
+ ),
+ // 获取验证码按钮
+ ElevatedButton(
+ onPressed: () async {
+ issmsCode = true;
+ if (_formKey.currentState!.validate()) {
+ _formKey.currentState!.save();
+ // 收回键盘
+ FocusScope.of(context).unfocus();
+ await GetServices().getsmsCode(phoneNumber);
+ startTimer(); // 开始定时器
+ }
+ },
+ child: Text(smsText),
+ ),
+ ],
+ ),
+ const SizedBox(height: 16.0),
+
+ // 登录按钮
+ ElevatedButton(
+ onPressed: () async {
+ issmsCode = false;
+ if (_formKey.currentState!.validate()) {
+ _formKey.currentState!.save();
+ // 表单校验通过,执行提交逻辑...
+ // 收回键盘
+ FocusScope.of(context).unfocus();
+ var res = await GetServices()
+ .phoneLogin(phoneNumber, smsCode);
+ setState(() {
+ if (res['code'] != 1000) {
+ showErrorSnackbar(
+ _scaffoldKey.currentContext!, res["message"]);
+ } else {
+ loginPrefs.savePhone(phoneNumber);
+ loginPrefs.saveExpire(res["data"]["expire"]);
+ loginPrefs.saveToken(res["data"]["token"]);
+ Navigator.pushNamed(
+ _scaffoldKey.currentContext!, 'home'); //跳转至首页
+ }
+ });
+ }
+ },
+ child: const Text('登录'),
+ ),
+ ],
+ )),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages/login/loginprefs.dart b/lib/pages/login/loginprefs.dart
new file mode 100644
index 0000000..6a33920
--- /dev/null
+++ b/lib/pages/login/loginprefs.dart
@@ -0,0 +1,75 @@
+import 'package:get/get.dart';
+import 'package:get_storage/get_storage.dart';
+
+import 'package:cpnav/models/user.dart';
+
+class LoginPrefs extends GetxController {
+ static const String expireStr = "expire"; //用户名
+ static const String tokenStr = "token"; //token
+ static const String phoneStr = "phone";
+ final box = GetStorage(); // 实例化 GetStorage
+
+ Future init() async {
+ await GetStorage.init(); // 初始化 GetStorage
+ return 'ok';
+ }
+
+ void saveExpire(int expire) {
+ box.write(expireStr, expire);
+ update();
+ }
+
+ int getExpire() {
+ return box.read(expireStr) ?? 0;
+ }
+
+ void saveToken(String token) {
+ box.write(tokenStr, token);
+ update();
+ }
+
+ String getToken() {
+ return box.read(tokenStr) ?? "";
+ }
+
+ void removeExpire() {
+ box.remove(expireStr);
+ update();
+ }
+
+ void removeToken() {
+ box.remove(tokenStr);
+ update();
+ }
+
+ void savePhone(String phone) {
+ box.write(phoneStr, phone);
+ update();
+ }
+
+ String getPhone() {
+ return box.read(phoneStr) ?? "";
+ }
+
+ void clearLogin() {
+ box.erase(); // 清除所有数据
+ update();
+ }
+}
+
+class UserController extends GetxController {
+ final box = GetStorage(); // 实例化 GetStorage
+
+ UserModel? getUser() {
+ final userMap = box.read('user');
+ if (userMap != null) {
+ return UserModel.fromJson(userMap);
+ }
+ return null;
+ }
+
+ void setUser(Map user) {
+ box.write('user', user);
+ update();
+ }
+}
diff --git a/lib/pages/pass_track/controller.dart b/lib/pages/pass_track/controller.dart
new file mode 100644
index 0000000..63081f6
--- /dev/null
+++ b/lib/pages/pass_track/controller.dart
@@ -0,0 +1,74 @@
+import 'dart:ui';
+
+import 'package:get/get.dart';
+import 'package:scence_map/controller.dart';
+import 'package:cpnav/service/base.dart';
+
+class PassTrackController extends GetxController {
+ final mapController = Get.put(ScenceMapController());
+
+ String projCode;
+ String projType;
+ late final GetServices service;
+
+ PassTrackController(this.projCode, this.projType);
+
+ @override
+ void onInit() {
+ super.onInit();
+ service = GetServices(projCode: projCode, projType: projType);
+ loadProject();
+ loadSideLine();
+ loadBindDevice();
+ }
+
+ loadBindDevice() async {
+ var binddevices = await service.getDeviceBind();
+ for (var device in binddevices) {
+ var dev = DeviceItem.fromJson(device);
+ mapController.deviceList[dev.TID] = dev;
+ }
+ }
+
+ loadCoorTrans() async {}
+
+ loadProject() async {}
+
+ loadSideLine() async {
+ var data = await service.getSideLine();
+ double maxX = -double.infinity;
+ double maxY = -double.infinity;
+ double minX = double.infinity;
+ double minY = double.infinity;
+ var sideLineData = data as Map;
+ sideLineData.forEach((group, items) {
+ for (var item in items) {
+ SideLineItem sideLineItem = SideLineItem.fromJson(item);
+ var sideLineList = mapController.sideLinListeMap[group];
+ if (sideLineList == null) {
+ sideLineList = [];
+ mapController.sideLinListeMap[group] = sideLineList;
+ }
+ sideLineList.add(sideLineItem);
+ if (sideLineItem.x > maxX) {
+ maxX = sideLineItem.x;
+ }
+ if (sideLineItem.y > maxY) {
+ maxY = sideLineItem.y;
+ }
+ if (sideLineItem.x < minX) {
+ minX = sideLineItem.x;
+ }
+ if (sideLineItem.y < minY) {
+ minY = sideLineItem.y;
+ }
+ }
+ });
+ if (maxX != -double.infinity &&
+ maxY != -double.infinity &&
+ minX != double.infinity &&
+ minY != double.infinity) {
+ mapController.centerXY = Offset((maxX + minX) / 2, (maxY + minY) / 2);
+ }
+ }
+}
diff --git a/lib/pages/pass_track/view.dart b/lib/pages/pass_track/view.dart
new file mode 100644
index 0000000..b76c775
--- /dev/null
+++ b/lib/pages/pass_track/view.dart
@@ -0,0 +1,30 @@
+//字体
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
+import 'package:scence_map/scence_map.dart';
+import "controller.dart";
+// import '../login_in/connect/bluetooth_page.dart';
+// import '../login_in/connect/config.dart';
+// import '../login_in/connect/connect_type.dart';
+// import '../login_in/getx/blue_tooth.dart';
+// import '../setting/antenna_setting.dart';
+// import '../setting/person_details.dart';
+// import '../setting/wifi_page.dart';
+// import '../setting/xy_change.dart';
+
+class PassTrack extends StatelessWidget {
+ final controller = Get.put(PassTrackController("WXLMB", "cp_orad"));
+
+ PassTrack();
+
+ @override
+ Widget build(BuildContext context) {
+ return ScenceMapView(
+ children: [],
+ onUpdate: (Offset center, double scale, double rotation) {
+ print("center:$center scale:$scale rotation:$rotation");
+ },
+ );
+ }
+}
diff --git a/lib/service/base.dart b/lib/service/base.dart
new file mode 100644
index 0000000..5e16114
--- /dev/null
+++ b/lib/service/base.dart
@@ -0,0 +1,198 @@
+import 'dart:convert';
+import 'dart:io';
+import 'package:http/http.dart' as http;
+import 'loginprefs.dart';
+
+LoginPrefs loginPrefs = LoginPrefs();
+
+class BaseService {
+ //创建client实例
+ final _client = http.Client();
+ final String token =
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc1IiOjAsInJvbGVJZHMiOlsiMSIsIjI0Il0sInVzZXJuYW1lIjoiYWRtaW4iLCJ1c2VySWQiOjEsIlBWIjo1LCJvcmciOiJhIiwiaWF0IjoxNzIyODY1MTE0LCJleHAiOjE3MjQxNjExMTR9.zuY366ldKkbtd1TTfcYIZfvhrovMlXLzzRk3j65Ua7o";
+
+ // String baseUrl = "http://192.168.1.189:8001";//本地
+ String baseUrl = "http://1.82.251.83:8001"; //线上
+ String loginstatus = "登录失效";
+ //发送GET请求
+ getClient(String url, [bool useBaseUrl = true]) async {
+ try {
+ http.Response response = await _client
+ .get(Uri.parse(useBaseUrl ? baseUrl + url : url), headers: {
+ HttpHeaders.contentTypeHeader: "application/json",
+ HttpHeaders.authorizationHeader: token,
+ });
+ var res = json.decode(response.body);
+ if (res['message'].contains(loginstatus)) {
+ loginPrefs.clearLogin();
+ return;
+ }
+ return res;
+ } catch (e) {
+ print(e);
+ return {};
+ }
+ }
+
+ //发送POST请求
+ postClient(String url, body) async {
+ try {
+ var data = json.encode(body);
+ http.Response response = await _client.post(Uri.parse(baseUrl + url),
+ headers: {
+ HttpHeaders.contentTypeHeader: "application/json",
+ HttpHeaders.authorizationHeader: token,
+ },
+ body: data);
+ var res = json.decode(response.body);
+ if (res['message'].contains(loginstatus)) {
+ loginPrefs.clearLogin();
+ return;
+ }
+ return res;
+ } catch (e) {
+ print(e);
+ return {};
+ }
+ }
+}
+
+class GetServices {
+ BaseService service = BaseService();
+ // String projCode = 'CJGKJEBYYB';
+ // int tid = 109;
+ String projType;
+ String projCode;
+ GetServices({this.projCode = "", this.projType = ""});
+ // int tid = 1000;
+ // String projType = "pile_cm";
+// 道路边线
+ Future getSideLine() async {
+ try {
+ Map res = await service.getClient(
+ '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType');
+ return res['data'];
+ } catch (e) {
+ return {};
+ }
+ }
+
+// 设备绑定 --- 获取设备
+ Future getDeviceBind() async {
+ Map res = await service.getClient(
+ '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode');
+ if (res['code'] == 1000) {
+ return res['data'];
+ } else {
+ return [];
+ }
+ }
+
+ // 项目列表
+ getproject() async {
+ Map res = await service
+ .getClient('/api/sys/project/list?org_code=a&proj_type=$projType');
+ return res['data'];
+ }
+
+ // 液压夯
+ getRcordData(int page, int size, String date,
+ [String sort = "desc", String order = "tp_id"]) async {
+ Map res = await service.getClient(
+ "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&date=$date&sort=$sort&order=$order");
+ return res['data'];
+ }
+
+ //获取水泥搅拌桩点数据
+ // getRcordData(int page, int size, String date,
+ // [String sort = "desc", String order = "pile_id"]) async {
+ // Map res = await service.getClient(
+ // "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order");
+ // return res['data'];
+ // }
+
+ // getRcordList(String date, String? dateEnd) async {
+ // dateEnd ??= date;
+ // Map res = await service.getClient(
+ // "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd");
+ // return res['data'];
+ // }
+ getRcordList(String date, [String? dateEnd]) async {
+ dateEnd ??= date;
+ Map res = await service.getClient(
+ "/api/$projType/record/list?org_code=a&proj_code=$projCode&date=$date&dateEnd=$dateEnd");
+ if (res['code'] == 1000) {
+ return res['data'];
+ } else {
+ return [];
+ }
+ }
+
+ //获取施工记录的日期
+ getworkDateData() async {
+ Map res = await service.getClient(
+ "/api/$projType/record/work_date?org_code=a&proj_code=$projCode");
+ if (res['code'] == 1000) {
+ return res['data'] ?? [];
+ } else {
+ return [];
+ }
+ }
+
+ //施工详细记录
+ getProcessData(int pileId) async {
+ Map res = await service.getClient(
+ "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode");
+ return res['data'];
+ }
+
+ // 验证码
+ getsmsCode(String phone) async {
+ Map res =
+ await service.postClient("/admin/base/open/smsCode", {"phone": phone});
+ return res;
+ }
+
+ // 手机号登录
+ phoneLogin(String phone, String smsCode) async {
+ Map res = await service.postClient(
+ "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode});
+ return res;
+ }
+
+ // 获取用户信息
+ getPerson() async {
+ Map res = await service.getClient("/admin/base/comm/person");
+ return res['data'];
+ }
+
+ // 验证码
+ getCaptcha() async {
+ Map res =
+ await service.getClient("/admin/base/open/captcha?height=40&width=150");
+ return res['data'];
+ }
+
+ getAccountLogin(String captchaId, String password, String username,
+ String verifyCode) async {
+ Map res = await service.postClient("/admin/base/open/login", {
+ "captchaId": captchaId,
+ "password": password,
+ "username": username,
+ "verifyCode": verifyCode
+ });
+ return res;
+ }
+
+ getRtuLast() async {
+ Map res = await service.getClient(
+ "/api/t2n/rtu/rtu_last?proj_type=$projType&proj_code=$projCode");
+ return res['data'];
+ }
+
+ getCoordTrans() async {
+ Map res = await service.getClient(
+ "/api/comm/coord_trans/list?proj_type=$projType&proj_code=$projCode");
+ return res['data'];
+ }
+}
diff --git a/lib/service/cp_road.dart b/lib/service/cp_road.dart
new file mode 100644
index 0000000..33ee69b
--- /dev/null
+++ b/lib/service/cp_road.dart
@@ -0,0 +1,244 @@
+import 'package:get/get.dart';
+import 'base.dart';
+
+// String projCode = 'CJGKJEBYYB';
+// String tid = "109";
+// String projType = "hydraulic_tamping";
+String projCode = 'TEST';
+String tid = "1000";
+String projType = "pile_cm";
+BaseService service = BaseService();
+
+class ProjController extends GetxController {
+ ProjController();
+// 道路边线
+ Future getSideLine() async {
+ Map res = await service.getClient(
+ '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType');
+ return res['data'];
+ }
+
+// 设备绑定 --- 获取设备
+ Future getDeviceBind() async {
+ Map res = await service.getClient(
+ '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode');
+ return res['data'];
+ }
+
+ // 项目列表
+ getproject() async {
+ Map res = await service.getClient(
+ '/api/sys/project/list?org_code=a&proj_type=$projType&proj_code=$projCode');
+ return res['data'];
+ }
+}
+
+class LoginController {
+ // 验证码
+ getsmsCode(String phone) async {
+ Map res =
+ await service.postClient("/admin/base/open/smsCode", {"phone": phone});
+ return res;
+ }
+
+ // 手机号登录
+ phoneLogin(String phone, String smsCode) async {
+ Map res = await service.postClient(
+ "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode});
+ return res;
+ }
+
+ // 获取用户信息
+ getPerson() async {
+ Map res = await service.getClient("/admin/base/comm/person");
+ return res['data'];
+ }
+
+ // 验证码
+ getCaptcha() async {
+ Map res =
+ await service.getClient("/admin/base/open/captcha?height=40&width=150");
+ return res['data'];
+ }
+
+ getAccountLogin(String captchaId, String password, String username,
+ String verifyCode) async {
+ Map res = await service.postClient("/admin/base/open/login", {
+ "captchaId": captchaId,
+ "password": password,
+ "username": username,
+ "verifyCode": verifyCode
+ });
+ return res;
+ }
+}
+
+class PileCmController {
+ //获取水泥搅拌桩点数据
+ getRcordData(int page, int size, String date,
+ [String sort = "desc", String order = "pile_id"]) async {
+ Map res = await service.getClient(
+ "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order");
+ return res['data'];
+ }
+
+ getRcordList(String date, String? dateEnd) async {
+ dateEnd ??= date;
+ Map res = await service.getClient(
+ "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd");
+ return res['data'];
+ }
+
+ //获取施工记录的日期
+ getworkDateData() async {
+ Map res = await service.getClient(
+ "/api/$projType/record/work_date?org_code=a&proj_code=$projCode&tid=$tid");
+ if (res['code'] == 1000) {
+ return res['data'] ?? [];
+ } else {
+ return [];
+ }
+ }
+
+ //施工详细记录
+ getProcessData(int pileId) async {
+ Map res = await service.getClient(
+ "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode&tid=$tid");
+ return res['data'];
+ }
+}
+
+class GetServices {
+ BaseService service = BaseService();
+ // String projCode = 'CJGKJEBYYB';
+ // int tid = 109;
+ // String projType = "hydraulic_tamping";
+ String projCode = 'TEST';
+ int tid = 1000;
+ String projType = "pile_cm";
+// 道路边线
+ Future getSideLine() async {
+ try {
+ Map res = await service.getClient(
+ '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType');
+ return res['data'];
+ } catch (e) {
+ return {};
+ }
+ }
+
+// 设备绑定 --- 获取设备
+ Future getDeviceBind() async {
+ Map res = await service.getClient(
+ '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode');
+ return res['data'];
+ }
+
+ // 项目列表
+ getproject() async {
+ Map res = await service
+ .getClient('/api/sys/project/list?org_code=a&proj_type=$projType');
+ return res['data'];
+ }
+
+ // 液压夯
+ getRcordData(int page, int size, String date,
+ [String sort = "desc", String order = "tp_id"]) async {
+ Map res = await service.getClient(
+ "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order");
+ return res['data'];
+ }
+
+ //获取水泥搅拌桩点数据
+ // getRcordData(int page, int size, String date,
+ // [String sort = "desc", String order = "pile_id"]) async {
+ // Map res = await service.getClient(
+ // "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order");
+ // return res['data'];
+ // }
+
+ // getRcordList(String date, String? dateEnd) async {
+ // dateEnd ??= date;
+ // Map res = await service.getClient(
+ // "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd");
+ // return res['data'];
+ // }
+ getRcordList(String date, [String? dateEnd]) async {
+ dateEnd ??= date;
+ Map res = await service.getClient(
+ "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd");
+ if (res['code'] == 1000) {
+ return res['data'];
+ } else {
+ return [];
+ }
+ }
+
+ //获取施工记录的日期
+ getworkDateData() async {
+ Map res = await service.getClient(
+ "/api/$projType/record/work_date?org_code=a&proj_code=$projCode&tid=$tid");
+ if (res['code'] == 1000) {
+ return res['data'] ?? [];
+ } else {
+ return [];
+ }
+ }
+
+ //施工详细记录
+ getProcessData(int pileId) async {
+ Map res = await service.getClient(
+ "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode&tid=$tid");
+ return res['data'];
+ }
+
+ // 验证码
+ getsmsCode(String phone) async {
+ Map res =
+ await service.postClient("/admin/base/open/smsCode", {"phone": phone});
+ return res;
+ }
+
+ // 手机号登录
+ phoneLogin(String phone, String smsCode) async {
+ Map res = await service.postClient(
+ "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode});
+ return res;
+ }
+
+ // 获取用户信息
+ getPerson() async {
+ Map res = await service.getClient("/admin/base/comm/person");
+ return res['data'];
+ }
+
+ // 验证码
+ getCaptcha() async {
+ Map res =
+ await service.getClient("/admin/base/open/captcha?height=40&width=150");
+ return res['data'];
+ }
+
+ getAccountLogin(String captchaId, String password, String username,
+ String verifyCode) async {
+ Map res = await service.postClient("/admin/base/open/login", {
+ "captchaId": captchaId,
+ "password": password,
+ "username": username,
+ "verifyCode": verifyCode
+ });
+ return res;
+ }
+
+ getRtuLast() async {
+ Map res = await service.getClient(
+ "/api/t2n/rtu/rtu_last?proj_type=$projType&proj_code=$projCode");
+ return res['data'];
+ }
+
+ getCoordTrans() async {
+ Map res = await service.getClient(
+ "/api/comm/coord_trans/list?proj_type=$projType&proj_code=$projCode");
+ return res['data'];
+ }
+}
diff --git a/lib/service/loginprefs.dart b/lib/service/loginprefs.dart
new file mode 100644
index 0000000..6516904
--- /dev/null
+++ b/lib/service/loginprefs.dart
@@ -0,0 +1,74 @@
+import 'package:get_storage/get_storage.dart';
+
+import 'package:cpnav/models/user.dart';
+
+class LoginPrefs {
+ static const String expireStr = "expire"; //用户名
+ static const String tokenStr = "token"; //token
+ static const String phoneStr = "phone";
+ final box = GetStorage(); // 实例化 GetStorage
+
+ Future init() async {
+ await GetStorage.init(); // 初始化 GetStorage
+ return 'ok';
+ }
+
+ void saveExpire(int expire) {
+ box.write(expireStr, expire);
+ // update();
+ }
+
+ int getExpire() {
+ return box.read(expireStr) ?? 0;
+ }
+
+ void saveToken(String token) {
+ box.write(tokenStr, token);
+ // update();
+ }
+
+ String getToken() {
+ return box.read(tokenStr) ?? "";
+ }
+
+ void removeExpire() {
+ box.remove(expireStr);
+ // update();
+ }
+
+ void removeToken() {
+ box.remove(tokenStr);
+ // update();
+ }
+
+ void savePhone(String phone) {
+ box.write(phoneStr, phone);
+ // update();
+ }
+
+ String getPhone() {
+ return box.read(phoneStr) ?? "";
+ }
+
+ void clearLogin() {
+ box.erase(); // 清除所有数据
+ // update();
+ }
+}
+
+class UserController {
+ final box = GetStorage(); // 实例化 GetStorage
+
+ UserModel? getUser() {
+ final userMap = box.read('user');
+ if (userMap != null) {
+ return UserModel.fromJson(userMap);
+ }
+ return null;
+ }
+
+ void setUser(Map user) {
+ box.write('user', user);
+ // update();
+ }
+}
diff --git a/lib/service/pile_cm.dart b/lib/service/pile_cm.dart
new file mode 100644
index 0000000..1b79eb8
--- /dev/null
+++ b/lib/service/pile_cm.dart
@@ -0,0 +1,109 @@
+import 'package:get/get.dart';
+import 'base.dart';
+
+// String projCode = 'CJGKJEBYYB';
+// String tid = "109";
+// String projType = "hydraulic_tamping";
+String projCode = 'TEST';
+String tid = "1000";
+String projType = "pile_cm";
+BaseService service = BaseService();
+
+class ProjController extends GetxController {
+ ProjController();
+// 道路边线
+ Future getSideLine() async {
+ Map res = await service.getClient(
+ '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType');
+ return res['data'];
+ }
+
+// 设备绑定 --- 获取设备
+ Future getDeviceBind() async {
+ Map res = await service.getClient(
+ '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode');
+ return res['data'];
+ }
+
+ // 项目列表
+ getproject() async {
+ Map res = await service.getClient(
+ '/api/sys/project/list?org_code=a&proj_type=$projType&proj_code=$projCode');
+ return res['data'];
+ }
+}
+
+class LoginController {
+ // 验证码
+ getsmsCode(String phone) async {
+ Map res =
+ await service.postClient("/admin/base/open/smsCode", {"phone": phone});
+ return res;
+ }
+
+ // 手机号登录
+ phoneLogin(String phone, String smsCode) async {
+ Map res = await service.postClient(
+ "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode});
+ return res;
+ }
+
+ // 获取用户信息
+ getPerson() async {
+ Map res = await service.getClient("/admin/base/comm/person");
+ return res['data'];
+ }
+
+ // 验证码
+ getCaptcha() async {
+ Map res =
+ await service.getClient("/admin/base/open/captcha?height=40&width=150");
+ return res['data'];
+ }
+
+ getAccountLogin(String captchaId, String password, String username,
+ String verifyCode) async {
+ Map res = await service.postClient("/admin/base/open/login", {
+ "captchaId": captchaId,
+ "password": password,
+ "username": username,
+ "verifyCode": verifyCode
+ });
+ return res;
+ }
+}
+
+class PileCmController {
+ //获取水泥搅拌桩点数据
+ getRcordData(int page, int size, String date,
+ [String sort = "desc", String order = "pile_id"]) async {
+ Map res = await service.getClient(
+ "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order");
+ return res['data'];
+ }
+
+ getRcordList(String date, String? dateEnd) async {
+ dateEnd ??= date;
+ Map res = await service.getClient(
+ "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd");
+ return res['data'];
+ }
+
+ //获取施工记录的日期
+ getworkDateData() async {
+ Map res = await service.getClient(
+ "/api/$projType/record/work_date?org_code=a&proj_code=$projCode&tid=$tid");
+ if (res['code'] == 1000) {
+ return res['data'] ?? [];
+ } else {
+ return [];
+ }
+ }
+
+ //施工详细记录
+ getProcessData(int pileId) async {
+ Map res = await service.getClient(
+ "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode&tid=$tid");
+ return res['data'];
+ }
+}
diff --git a/lib/service/user/loginprefs.dart b/lib/service/user/loginprefs.dart
new file mode 100644
index 0000000..6a33920
--- /dev/null
+++ b/lib/service/user/loginprefs.dart
@@ -0,0 +1,75 @@
+import 'package:get/get.dart';
+import 'package:get_storage/get_storage.dart';
+
+import 'package:cpnav/models/user.dart';
+
+class LoginPrefs extends GetxController {
+ static const String expireStr = "expire"; //用户名
+ static const String tokenStr = "token"; //token
+ static const String phoneStr = "phone";
+ final box = GetStorage(); // 实例化 GetStorage
+
+ Future init() async {
+ await GetStorage.init(); // 初始化 GetStorage
+ return 'ok';
+ }
+
+ void saveExpire(int expire) {
+ box.write(expireStr, expire);
+ update();
+ }
+
+ int getExpire() {
+ return box.read(expireStr) ?? 0;
+ }
+
+ void saveToken(String token) {
+ box.write(tokenStr, token);
+ update();
+ }
+
+ String getToken() {
+ return box.read(tokenStr) ?? "";
+ }
+
+ void removeExpire() {
+ box.remove(expireStr);
+ update();
+ }
+
+ void removeToken() {
+ box.remove(tokenStr);
+ update();
+ }
+
+ void savePhone(String phone) {
+ box.write(phoneStr, phone);
+ update();
+ }
+
+ String getPhone() {
+ return box.read(phoneStr) ?? "";
+ }
+
+ void clearLogin() {
+ box.erase(); // 清除所有数据
+ update();
+ }
+}
+
+class UserController extends GetxController {
+ final box = GetStorage(); // 实例化 GetStorage
+
+ UserModel? getUser() {
+ final userMap = box.read('user');
+ if (userMap != null) {
+ return UserModel.fromJson(userMap);
+ }
+ return null;
+ }
+
+ void setUser(Map user) {
+ box.write('user', user);
+ update();
+ }
+}
diff --git a/lib/themes.dart b/lib/themes.dart
new file mode 100644
index 0000000..6788cf6
--- /dev/null
+++ b/lib/themes.dart
@@ -0,0 +1,158 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'constants.dart';
+
+class HaboTheme {
+ static ThemeData get lightTheme {
+ return ThemeData(
+ useMaterial3: true,
+ scaffoldBackgroundColor: const Color(0xFFFAFAFA),
+ dialogTheme: const DialogTheme(surfaceTintColor: Colors.white),
+ brightness: Brightness.light,
+ primaryColor: const Color(0xFF09BF30),
+ timePickerTheme: TimePickerThemeData(
+ hourMinuteColor: Colors.grey[100],
+ dialBackgroundColor: Colors.grey[100],
+ ),
+ colorScheme: ColorScheme.light(
+ primaryContainer: Colors.white,
+ secondaryContainer: Colors.grey[100],
+ tertiaryContainer: HaboColors.primary,
+ onPrimaryContainer: HaboColors.primary,
+ primary: HaboColors.primary,
+ outline: const Color(0xFF505050),
+ ),
+ fontFamily: GoogleFonts.nunito().fontFamily,
+ floatingActionButtonTheme: const FloatingActionButtonThemeData(
+ backgroundColor: Color(0xFF09BF30),
+ ),
+ appBarTheme: const AppBarTheme(
+ elevation: 0,
+ systemOverlayStyle: SystemUiOverlayStyle(
+ statusBarIconBrightness: Brightness.dark,
+ statusBarBrightness: Brightness.light,
+ systemNavigationBarColor: Color(0xFFFAFAFA),
+ systemNavigationBarDividerColor: Color(0xFFFAFAFA),
+ systemNavigationBarIconBrightness: Brightness.dark,
+ ),
+ ),
+ );
+ }
+
+ static ThemeData get darkTheme {
+ return ThemeData(
+ useMaterial3: true,
+ scaffoldBackgroundColor: const Color(0xFF303030),
+ dialogTheme: const DialogTheme(
+ backgroundColor: Color(0xFF505050),
+ surfaceTintColor: Colors.transparent,
+ ),
+ primaryColor: Colors.grey,
+ fontFamily: GoogleFonts.nunito().fontFamily,
+ switchTheme: SwitchThemeData(
+ thumbColor: WidgetStateProperty.resolveWith(getSwitchColorThumb),
+ trackColor: WidgetStateProperty.resolveWith(getSwitchTrackColor),
+ ),
+ timePickerTheme: const TimePickerThemeData(
+ dayPeriodTextColor: Colors.white,
+ hourMinuteColor: Color(0xFF353535),
+ dialBackgroundColor: Color(0xFF353535),
+ dialTextColor: Colors.white,
+ backgroundColor: Color(0xFF505050),
+ ),
+ colorScheme: const ColorScheme.dark(
+ primaryContainer: Color(0xFF505050),
+ secondaryContainer: Color(0xFF353535),
+ onPrimary: HaboColors.primary,
+ tertiaryContainer: HaboColors.primary,
+ primary: HaboColors.primary,
+ outline: Colors.grey,
+ ),
+ floatingActionButtonTheme: const FloatingActionButtonThemeData(
+ backgroundColor: Color(0xFF09BF30),
+ ),
+ appBarTheme: const AppBarTheme(
+ elevation: 0,
+ systemOverlayStyle: SystemUiOverlayStyle(
+ statusBarIconBrightness: Brightness.light,
+ statusBarBrightness: Brightness.dark,
+ systemNavigationBarColor: Color(0xFF303030),
+ systemNavigationBarDividerColor: Color(0xFF303030),
+ systemNavigationBarIconBrightness: Brightness.light,
+ ),
+ ),
+ );
+ }
+
+ static ThemeData get oledTheme {
+ return ThemeData(
+ useMaterial3: true,
+ scaffoldBackgroundColor: Colors.black,
+ dialogTheme: const DialogTheme(
+ backgroundColor: Color(0xFF282828),
+ surfaceTintColor: Colors.transparent,
+ ),
+ primaryColor: Colors.grey,
+ fontFamily: GoogleFonts.nunito().fontFamily,
+ switchTheme: SwitchThemeData(
+ thumbColor: WidgetStateProperty.resolveWith(getSwitchColorThumb),
+ trackColor: WidgetStateProperty.resolveWith(getSwitchTrackColor),
+ ),
+ timePickerTheme: const TimePickerThemeData(
+ dayPeriodTextColor: Colors.white,
+ hourMinuteColor: Color(0xFF191919),
+ dialBackgroundColor: Color(0xFF191919),
+ dialTextColor: Colors.white,
+ backgroundColor: Color(0xFF282828),
+ ),
+ colorScheme: const ColorScheme.dark(
+ primaryContainer: Color(0xFF282828),
+ secondaryContainer: Color(0xFF191919),
+ tertiaryContainer: HaboColors.primary,
+ onPrimary: HaboColors.primary,
+ primary: HaboColors.primary,
+ outline: Colors.grey,
+ ),
+ floatingActionButtonTheme: const FloatingActionButtonThemeData(
+ backgroundColor: Color(0xFF09BF30),
+ ),
+ appBarTheme: const AppBarTheme(
+ elevation: 0,
+ systemOverlayStyle: SystemUiOverlayStyle(
+ statusBarIconBrightness: Brightness.light,
+ statusBarBrightness: Brightness.dark,
+ systemNavigationBarColor: Colors.black,
+ systemNavigationBarDividerColor: Colors.black,
+ systemNavigationBarIconBrightness: Brightness.light,
+ ),
+ ),
+ );
+ }
+}
+
+Color getSwitchColorThumb(Set states) {
+ if (states.contains(WidgetState.selected)) {
+ return const Color(0xFF303030);
+ }
+
+ return Colors.grey;
+}
+
+Color getSwitchTrackColor(Set states) {
+ const Set interactiveStates = {
+ WidgetState.pressed,
+ WidgetState.hovered,
+ WidgetState.focused,
+ };
+
+ if (states.any(interactiveStates.contains)) {
+ return const Color(0xFF505050);
+ }
+
+ if (states.contains(WidgetState.selected)) {
+ return HaboColors.primary;
+ }
+
+ return const Color(0xFF353535);
+}
diff --git a/pubspec.lock b/pubspec.lock
new file mode 100644
index 0000000..0d057ca
--- /dev/null
+++ b/pubspec.lock
@@ -0,0 +1,428 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ args:
+ dependency: transitive
+ description:
+ name: args
+ sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.0"
+ async:
+ dependency: transitive
+ description:
+ name: async
+ sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.11.0"
+ boolean_selector:
+ dependency: transitive
+ description:
+ name: boolean_selector
+ sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.0"
+ clock:
+ dependency: transitive
+ description:
+ name: clock
+ sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.18.0"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.5"
+ cupertino_icons:
+ dependency: "direct main"
+ description:
+ name: cupertino_icons
+ sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.8"
+ fake_async:
+ dependency: transitive
+ description:
+ name: fake_async
+ sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.1"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.3"
+ flutter:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_lints:
+ dependency: "direct dev"
+ description:
+ name: flutter_lints
+ sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.2"
+ flutter_svg:
+ dependency: "direct main"
+ description:
+ name: flutter_svg
+ sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.10+1"
+ flutter_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ get:
+ dependency: "direct main"
+ description:
+ name: get
+ sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.6.6"
+ get_storage:
+ dependency: "direct main"
+ description:
+ name: get_storage
+ sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ google_fonts:
+ dependency: "direct main"
+ description:
+ name: google_fonts
+ sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.2.1"
+ http:
+ dependency: "direct main"
+ description:
+ name: http
+ sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.2"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.2"
+ leak_tracker:
+ dependency: transitive
+ description:
+ name: leak_tracker
+ sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "10.0.4"
+ leak_tracker_flutter_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_flutter_testing
+ sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.3"
+ leak_tracker_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_testing
+ sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.1"
+ lints:
+ dependency: transitive
+ description:
+ name: lints
+ sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.0"
+ matcher:
+ dependency: transitive
+ description:
+ name: matcher
+ sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.12.16+1"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.8.0"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.12.0"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.0"
+ path_parsing:
+ dependency: transitive
+ description:
+ name: path_parsing
+ sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
+ path_provider:
+ dependency: transitive
+ description:
+ name: path_provider
+ sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ path_provider_android:
+ dependency: transitive
+ description:
+ name: path_provider_android
+ sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.10"
+ path_provider_foundation:
+ dependency: transitive
+ description:
+ name: path_provider_foundation
+ sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ path_provider_linux:
+ dependency: transitive
+ description:
+ name: path_provider_linux
+ sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.1"
+ path_provider_platform_interface:
+ dependency: transitive
+ description:
+ name: path_provider_platform_interface
+ sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.2"
+ path_provider_windows:
+ dependency: transitive
+ description:
+ name: path_provider_windows
+ sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.0"
+ petitparser:
+ dependency: transitive
+ description:
+ name: petitparser
+ sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.0.2"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.5"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.8"
+ scence_map:
+ dependency: "direct main"
+ description:
+ path: "plugins/scence_map"
+ relative: true
+ source: path
+ version: "0.0.1"
+ sky_engine:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.99"
+ source_span:
+ dependency: transitive
+ description:
+ name: source_span
+ sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.10.0"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.11.1"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.2"
+ string_scanner:
+ dependency: transitive
+ description:
+ name: string_scanner
+ sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.0"
+ term_glyph:
+ dependency: transitive
+ description:
+ name: term_glyph
+ sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ test_api:
+ dependency: transitive
+ description:
+ name: test_api
+ sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.7.0"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.2"
+ vector_graphics:
+ dependency: transitive
+ description:
+ name: vector_graphics
+ sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.11+1"
+ vector_graphics_codec:
+ dependency: transitive
+ description:
+ name: vector_graphics_codec
+ sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.11+1"
+ vector_graphics_compiler:
+ dependency: transitive
+ description:
+ name: vector_graphics_compiler
+ sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.11+1"
+ vector_math:
+ dependency: transitive
+ description:
+ name: vector_math
+ sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
+ url: "https://pub.dev"
+ source: hosted
+ version: "14.2.1"
+ web:
+ dependency: transitive
+ description:
+ name: web
+ sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.0"
+ xdg_directories:
+ dependency: transitive
+ description:
+ name: xdg_directories
+ sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
+ xml:
+ dependency: transitive
+ description:
+ name: xml
+ sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.5.0"
+sdks:
+ dart: ">=3.4.4 <4.0.0"
+ flutter: ">=3.22.0"
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..aef09f2
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,97 @@
+name: cpnav
+description: "A new Flutter project."
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+# In Windows, build-name is used as the major, minor, and patch parts
+# of the product and file versions while build-number is used as the build suffix.
+version: 1.0.0+1
+
+environment:
+ sdk: '>=3.4.4 <4.0.0'
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+ scence_map:
+ path: plugins/scence_map
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.6
+ get: ^4.6.6
+ get_storage: ^2.1.1
+ http: ^1.2.2
+ flutter_svg: ^2.0.10+1
+ google_fonts: ^6.2.1
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^3.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ assets:
+ - images/pilerCar.png
+ - images/navi_pointer.png
+ - images/satellite.png
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/assets-and-images/#resolution-aware
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/assets-and-images/#from-packages
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/custom-fonts/#from-packages
diff --git a/test/widget_test.dart b/test/widget_test.dart
new file mode 100644
index 0000000..5aff2e9
--- /dev/null
+++ b/test/widget_test.dart
@@ -0,0 +1,30 @@
+// This is a basic Flutter widget test.
+//
+// To perform an interaction with a widget in your test, use the WidgetTester
+// utility in the flutter_test package. For example, you can send tap and scroll
+// gestures. You can also use WidgetTester to find child widgets in the widget
+// tree, read text, and verify that the values of widget properties are correct.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:cpnav/main.dart';
+
+void main() {
+ testWidgets('Counter increments smoke test', (WidgetTester tester) async {
+ // Build our app and trigger a frame.
+ await tester.pumpWidget(const MyApp());
+
+ // Verify that our counter starts at 0.
+ expect(find.text('0'), findsOneWidget);
+ expect(find.text('1'), findsNothing);
+
+ // Tap the '+' icon and trigger a frame.
+ await tester.tap(find.byIcon(Icons.add));
+ await tester.pump();
+
+ // Verify that our counter has incremented.
+ expect(find.text('0'), findsNothing);
+ expect(find.text('1'), findsOneWidget);
+ });
+}