1
0

14 Commity 145920dd1a ... c7543596b0

Autor SHA1 Správa Dátum
  Yue c7543596b0 Add 添加V1.0.0编译的app 1 mesiac pred
  Yue 2dbf120c79 Update 优化打包脚本 1 mesiac pred
  Yue 217b4e9098 Fix 修复优化离线数据上传出错停止上传的问题 1 mesiac pred
  Yue 23a94dbd36 Update 代码优化, 1 mesiac pred
  Yue 3b5ae48c6e Update 优化打包脚本 1 mesiac pred
  Yue e33a501742 Fix 修复登录失败没有提示的问题 1 mesiac pred
  Yue e7596d3780 Update 调整安卓构建文件 1 mesiac pred
  Yue 4fef327399 Add 添加安卓打包代码 1 mesiac pred
  Yue 654fb39e12 Update 优化环境变量文件的实现方式 1 mesiac pred
  Yue 875e7b6c6d Add 个人中心增加平台信息显示 1 mesiac pred
  Yue ac24c6bd6f Fix 修复设备不兼容扫码和读卡器时闪退的现象 1 mesiac pred
  Yue 20a8122492 Update 模拟上传恢复为真实接口 1 mesiac pred
  Yue e9e4904b8d Update 优化RFID读卡超时重连的逻辑 1 mesiac pred
  Yue 533110c291 Update 增加数据库路径配置 1 mesiac pred
42 zmenil súbory, kde vykonal 599 pridanie a 197 odobranie
  1. 8 0
      UI/CF.APP/chicken_farm/.env/.env.dev
  2. 8 0
      UI/CF.APP/chicken_farm/.env/.env.dev_no_pda
  3. 8 0
      UI/CF.APP/chicken_farm/.env/.env.dev_offline
  4. 8 0
      UI/CF.APP/chicken_farm/.env/.env.prod
  5. 8 0
      UI/CF.APP/chicken_farm/.env/.env.prod_no_pda
  6. 8 0
      UI/CF.APP/chicken_farm/.env/.env.prod_offline
  7. 97 0
      UI/CF.APP/chicken_farm/.scripts/_build.bat
  8. 15 0
      UI/CF.APP/chicken_farm/.scripts/_build_cmd.txt
  9. 67 0
      UI/CF.APP/chicken_farm/.scripts/build_all_apk.bat
  10. 15 3
      UI/CF.APP/chicken_farm/android/app/build.gradle
  11. 2 2
      UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidConstants.java
  12. 20 6
      UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidManager.java
  13. 3 0
      UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidMethodCallHandler.java
  14. 35 32
      UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidService.java
  15. 13 1
      UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanManager.java
  16. 27 0
      UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanMethodCallHandler.java
  17. 53 1
      UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanService.java
  18. 28 2
      UI/CF.APP/chicken_farm/android/build.gradle
  19. 7 1
      UI/CF.APP/chicken_farm/android/gradle.properties
  20. 9 9
      UI/CF.APP/chicken_farm/lib/apis/breeding/_submit.dart
  21. 13 2
      UI/CF.APP/chicken_farm/lib/components/vb_electronic_id_field.dart
  22. 12 9
      UI/CF.APP/chicken_farm/lib/core/config/app_config.dart
  23. 0 9
      UI/CF.APP/chicken_farm/lib/core/config/env/dev_config.dart
  24. 0 9
      UI/CF.APP/chicken_farm/lib/core/config/env/dev_no_pda_config.dart
  25. 0 9
      UI/CF.APP/chicken_farm/lib/core/config/env/dev_offline_config.dart
  26. 31 0
      UI/CF.APP/chicken_farm/lib/core/config/env/env_config.dart
  27. 0 9
      UI/CF.APP/chicken_farm/lib/core/config/env/prod_config.dart
  28. 0 9
      UI/CF.APP/chicken_farm/lib/core/config/env/prod_no_pda_config.dart
  29. 0 9
      UI/CF.APP/chicken_farm/lib/core/config/env/prod_offline_config.dart
  30. 2 1
      UI/CF.APP/chicken_farm/lib/core/db/sqlite_manager.dart
  31. 1 1
      UI/CF.APP/chicken_farm/lib/core/errors/error_handler.dart
  32. 34 18
      UI/CF.APP/chicken_farm/lib/core/services/pda/rfid_manager.dart
  33. 21 37
      UI/CF.APP/chicken_farm/lib/core/services/upload_service.dart
  34. 6 0
      UI/CF.APP/chicken_farm/lib/main.dart
  35. 3 3
      UI/CF.APP/chicken_farm/lib/pages/account/login_page.dart
  36. 0 3
      UI/CF.APP/chicken_farm/lib/pages/home/_profile/clear_cache_button.dart
  37. 14 0
      UI/CF.APP/chicken_farm/lib/pages/home/profile.dart
  38. 17 11
      UI/CF.APP/chicken_farm/lib/pages/upload/upload_page.dart
  39. 6 1
      UI/CF.APP/chicken_farm/lib/stores/auth_store.dart
  40. BIN
      UI/CF.APP/chicken_farm/release/app/pda_cf-app_V1.0.0.apk
  41. BIN
      UI/CF.APP/chicken_farm/release/app/pda_no_cf-app_V1.0.0.apk
  42. BIN
      UI/CF.APP/chicken_farm/release/app/pda_offline_cf-app_V1.0.0.apk

+ 8 - 0
UI/CF.APP/chicken_farm/.env/.env.dev

@@ -0,0 +1,8 @@
+APP_ENV=dev
+APP_NAME=养殖场管理系统
+APP_VERSION=1.0.0-dev
+BASE_API_URL=http://192.168.0.81:8380
+CLIENT_ID=35aee70ae7224eb9a48bc527955ddedc
+IS_OFFLINE=false
+IS_PDA=true
+WIN_DB_PATH=.demo/data

+ 8 - 0
UI/CF.APP/chicken_farm/.env/.env.dev_no_pda

@@ -0,0 +1,8 @@
+APP_ENV=dev.no_pda
+APP_NAME=养殖场管理系统
+APP_VERSION=1.0.0-dev
+BASE_API_URL=http://192.168.0.81:8380
+CLIENT_ID=35aee70ae7224eb9a48bc527955ddedc
+IS_OFFLINE=false
+IS_PDA=false
+WIN_DB_PATH=.demo/data

+ 8 - 0
UI/CF.APP/chicken_farm/.env/.env.dev_offline

@@ -0,0 +1,8 @@
+APP_ENV=dev.offline
+APP_NAME=养殖场管理系统(脱机)
+APP_VERSION=1.0.0-dev
+BASE_API_URL=http://192.168.0.81:8380
+CLIENT_ID=35aee70ae7224eb9a48bc527955ddedc
+IS_OFFLINE=true
+IS_PDA=true
+WIN_DB_PATH=.demo/data

+ 8 - 0
UI/CF.APP/chicken_farm/.env/.env.prod

@@ -0,0 +1,8 @@
+APP_ENV=prod
+APP_NAME=养殖场管理系统
+APP_VERSION=1.0.0
+BASE_API_URL=http://shvber.com:5068
+CLIENT_ID=35aee70ae7224eb9a48bc527955ddedc
+IS_OFFLINE=false
+IS_PDA=true
+WIN_DB_PATH=data/db

+ 8 - 0
UI/CF.APP/chicken_farm/.env/.env.prod_no_pda

@@ -0,0 +1,8 @@
+APP_ENV=prod.no_pda
+APP_NAME=养殖场管理系统
+APP_VERSION=1.0.0
+BASE_API_URL=http://shvber.com:5068
+CLIENT_ID=35aee70ae7224eb9a48bc527955ddedc
+IS_OFFLINE=false
+IS_PDA=false
+WIN_DB_PATH=data/db

+ 8 - 0
UI/CF.APP/chicken_farm/.env/.env.prod_offline

@@ -0,0 +1,8 @@
+APP_ENV=prod.offline
+APP_NAME=养殖场管理系统(脱机)
+APP_VERSION=1.0.0
+BASE_API_URL=http://shvber.com:5068
+CLIENT_ID=35aee70ae7224eb9a48bc527955ddedc
+IS_OFFLINE=true
+IS_PDA=true
+WIN_DB_PATH=data/db

+ 97 - 0
UI/CF.APP/chicken_farm/.scripts/_build.bat

@@ -0,0 +1,97 @@
+@echo off
+chcp 65001 >nul 2>&1
+setlocal enabledelayedexpansion
+
+:: ========== 1. 项目根目录初始化 ==========
+set "PROJECT_ROOT=%~dp0\.."
+for %%i in ("%PROJECT_ROOT%") do set "PROJECT_ROOT=%%~fi"
+
+:: ========== 2. 参数校验 ==========
+if "%~1"=="" (
+  echo [Error] 请使用命令: _build.bat [prod^|dev] [version] [no_pda^|offline] [appName]
+  echo [示例]  _build.bat prod v1.0.0 no_pda "cf-app-v1.0.0-no_pda"
+  pause
+  exit /b 1
+)
+
+if /i not "%~1"=="prod" if /i not "%~1"=="dev" (
+  echo [Error] 参数1无效,仅支持 prod 或 dev
+  pause
+  exit /b 1
+)
+
+:: 注意:参数2是version,参数3是环境标识(no_pda/offline),参数4是appName
+
+:: ========== 3. 环境变量加载 ==========
+set "ENV=%~1"
+if not "%~3"=="" if /i "%~3"=="no_pda" (
+  set "ENV=%~1_no_pda"
+) else if not "%~3"=="" if /i "%~3"=="offline" (
+  set "ENV=%~1_offline"
+)
+
+set "ANDROID_PLATFORM=android-arm64"
+set "APP_NAME=cf-app"
+
+:: 根据参数组合设置APP_NAME
+if not "%~4"=="" (
+  :: 如果提供了appName(第四个参数)
+  set "APP_NAME=%~4"
+) else (
+  :: 否则按规则构造APP_NAME
+  if not "%~3"=="" (
+    if  "%~3"=="no_pda" (
+      set "APP_NAME=pda_no_cf-app"
+    ) else if  "%~3"=="offline" (
+      set "APP_NAME=pda_offline_cf-app"
+    )
+  ) else (
+    set "APP_NAME=pda_cf-app"
+  )
+  
+  set "APP_VERSION=V1.0.0"
+  :: 添加版本号到APP_NAME
+  if not "%~2"=="" (
+    set "APP_VERSION=%~2"
+  )
+)
+
+set "ENV_FILE=%PROJECT_ROOT%\.env\.env.%ENV%"
+if not exist "%ENV_FILE%" (
+  echo [Error] 环境文件不存在: %ENV_FILE%
+  pause
+  exit /b 1
+)
+
+:: ========== 4. 构建参数生成 ==========
+set "DEFINE_ARGS="
+for /f "tokens=1,* delims==" %%a in ('type "%ENV_FILE%" ^| findstr /v "^#" ^| findstr /v "^$"') do (
+  set "DEFINE_ARGS=!DEFINE_ARGS! --dart-define=%%a=%%b"
+)
+
+:: ========== 5. 执行构建 ==========
+echo ==============================================
+echo [INFO] 开始构建: 环境=%ENV% ^| 平台=%ANDROID_PLATFORM% ^| 应用=%APP_NAME%
+cd /d "%PROJECT_ROOT%"
+call flutter build apk !DEFINE_ARGS! --target-platform !ANDROID_PLATFORM! --no-tree-shake-icons 
+if !errorlevel! neq 0 (
+  echo [Error] Flutter构建失败
+  pause
+  exit /b 1
+)
+
+:: ========== 6. 文件处理优化 ==========
+:: 生成时间戳 (YYYYMMDDHHMMSS)
+@REM for /f %%i in ('powershell -Command "Get-Date -Format yyyyMMddHHmmss"') do set TIMESTAMP=%%i
+
+set "APK_SOURCE=%PROJECT_ROOT%\build\app\outputs\flutter-apk\app-release.apk"
+set "APK_DEST=%PROJECT_ROOT%\release\app\%APP_NAME%_%APP_VERSION%.apk"
+
+if exist "%APK_SOURCE%" (
+  copy /y "%APK_SOURCE%" "%APK_DEST%" >nul
+  echo ==============================================
+  echo [INFO] APK生成成功: %APK_DEST%
+  echo ==============================================
+) else (
+  echo [Error] APK源文件不存在: %APK_SOURCE%
+)

+ 15 - 0
UI/CF.APP/chicken_farm/.scripts/_build_cmd.txt

@@ -0,0 +1,15 @@
+flutter build apk --target-platform android-arm
+
+mkdir -p release/app
+
+flutter build apk --target-platform android-arm --dart-define-from-file .env/.env.prod_no_pda --verbose
+copy build\app\outputs\flutter-apk\app-release.apk release\app\no_pda_cf-app.apk
+
+flutter build apk --target-platform android-arm --dart-define-from-file .env/.env.prod --verbose
+copy build\app\outputs\flutter-apk\app-release.apk release\app\pda_cf-app.apk
+
+flutter build apk --target-platform android-arm --dart-define-from-file .env/.env.prod_offline --verbose
+copy build\app\outputs\flutter-apk\app-release.apk release\app\pda-offline_cf-app.apk
+
+// 安装 app目录下的 apk
+adb install -r release/app/cf-app_20251222111721.apk

+ 67 - 0
UI/CF.APP/chicken_farm/.scripts/build_all_apk.bat

@@ -0,0 +1,67 @@
+@echo off
+chcp 936 >nul 2>&1
+setlocal enabledelayedexpansion
+
+:: ========== 全局配置(修复路径问题) ==========
+:: 当前脚本目录(.scripts)
+set "SCRIPT_DIR=%~dp0"
+:: 项目根目录(.scripts 的上级目录)
+set "PROJECT_ROOT=%SCRIPT_DIR%.."
+:: 编译脚本路径(直接指向当前目录的 build.bat,无需重复拼接 .scripts)
+set "BUILD_SCRIPT=%SCRIPT_DIR%_build.bat"
+set "VERSION=V1.0.0"
+:: ========== 前置检查 ==========
+if not exist "%BUILD_SCRIPT%" (
+  echo [错误] 未找到编译脚本:%BUILD_SCRIPT%
+  pause
+  exit /b 1
+)
+
+:: ========== 依次执行编译命令 ==========
+echo ==============================================
+echo 开始批量编译所有APK(共3个环境)
+echo ==============================================
+
+:: 1. 编译 prod 基础环境
+echo.
+echo [第1个] 开始编译:prod 基础环境
+call "%BUILD_SCRIPT%" prod "%VERSION%"
+if !errorlevel! neq 0 (
+  echo [错误] prod 基础环境编译失败!
+  pause
+  exit /b 1
+)
+echo [第1个] prod 基础环境编译完成 ??
+
+
+:: 2. 编译 prod_offline 环境
+echo.
+echo [第2个] 开始编译:prod offline 环境
+call "%BUILD_SCRIPT%" prod "%VERSION%" offline
+if !errorlevel! neq 0 (
+  echo [错误] prod offline 环境编译失败!
+  pause
+  exit /b 1
+)
+echo [第2个] prod offline 环境编译完成 ??
+
+:: 3. 编译 prod_no_pda 环境
+echo.
+echo [第3个] 开始编译:prod no_pda 环境
+call "%BUILD_SCRIPT%" prod "%VERSION%" no_pda
+if !errorlevel! neq 0 (
+  echo [错误] prod no_pda 环境编译失败!
+  pause
+  exit /b 1
+)
+echo [第3个] prod no_pda 环境编译完成 ??
+
+:: ========== 批量编译完成 ==========
+echo.
+echo ==============================================
+echo 所有APK编译完成!?
+echo 生成的文件位于:%PROJECT_ROOT%\release\app\
+echo ==============================================
+
+pause
+endlocal

+ 15 - 3
UI/CF.APP/chicken_farm/android/app/build.gradle

@@ -21,6 +21,13 @@ android {
         }
     }
 
+    packagingOptions {
+        pickFirst '**/libsqlite3.so'
+        pickFirst '**/libsqlite3.arm.android.so'
+        pickFirst '**/libsqlite3.x64.android.so'
+        pickFirst '**/libsqlite3.arm64.android.so'
+        pickFirst '**/libflutter.so'
+    }
 
     defaultConfig {
         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
@@ -39,10 +46,18 @@ android {
     }
 
     buildTypes {
+        debug {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
         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
+
+             // 禁用代码压缩和混淆
+            minifyEnabled false
+            shrinkResources false
         }
     }
 
@@ -59,6 +74,3 @@ dependencies {
     implementation files('libs\\ScanManager_V202105081630.jar')
 }
 
-flutter {
-    source = "../.."
-}

+ 2 - 2
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidConstants.java

@@ -41,8 +41,8 @@ public final class RfidConstants {
     // 默认连接重试次数
     public static final int DEFAULT_CONNECT_RETRY_TIMES = 3;
 
-    // 扫描空闲超时时间(120分钟)
-    public static final long SCAN_IDLE_TIMEOUT_MS = 120 * 60 * 1000L;
+    // 扫描空闲超时时间(15分钟)
+    public static final long SCAN_IDLE_TIMEOUT_MS = 15 * 60 * 1000L;
 
     private RfidConstants() {
         // 禁止实例化

+ 20 - 6
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidManager.java

@@ -31,12 +31,26 @@ public class RfidManager {
     private final ServiceConnection serviceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(TAG, "RFID服务绑定成功");
-            RfidBinder binder = (RfidBinder) service;
-            rfidService = binder.getService();
-            rfidService.init();
-            rfidService.setListener(listener); // 设置回调监听
-            isBound = true;
+            try {
+                Log.d(TAG, "RFID服务绑定成功");
+                RfidBinder binder = (RfidBinder) service;
+                rfidService = binder.getService();
+                
+                // 初始化服务,如果失败则记录错误但不崩溃
+                boolean initSuccess = rfidService.init();
+                if (!initSuccess) {
+                    Log.e(TAG, "RFID服务初始化失败");
+                }
+                
+                rfidService.setListener(listener); // 设置回调监听
+                isBound = true;
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(TAG, "绑定服务时加载本地库失败", e);
+                isBound = false;
+            } catch (Exception e) {
+                Log.e(TAG, "绑定服务时发生错误", e);
+                isBound = false;
+            }
         }
 
         @Override

+ 3 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidMethodCallHandler.java

@@ -169,6 +169,9 @@ public class RfidMethodCallHandler implements MethodCallHandler, RfidListener, E
             boolean success = rfidManager.connect(retryTimes);
             result.success(success);
             Log.d(TAG, "RFID连接请求已处理。 ");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "连接设备时加载本地库失败", e);
+            result.error("CONNECT_FAILED", "连接RFID设备失败,本地库加载错误: " + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "连接设备失败", e);
             result.error("CONNECT_FAILED", "连接RFID设备失败: " + e.getMessage(), null);

+ 35 - 32
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/rfid/RfidService.java

@@ -75,6 +75,7 @@ public class RfidService extends Service {
     public static int ErrorCount;
     public static int ErrorCRC;
     public boolean isMultipleTag = false;
+    public boolean isScanIdleTimeout = false;
 
     // 读卡器空闲超时处理器
     private Handler idleHandler;
@@ -118,6 +119,9 @@ public class RfidService extends Service {
             initSound();
             registerScreenStateReceiver(); // 注册屏幕状态监听
             return true;
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(RfidConstants.TAG, "加载本地库失败,可能是缺少libSerialPort.so", e);
+            return false;
         } catch (Exception e) {
             Log.e(RfidConstants.TAG, "读卡器初始化失败", e);
             return false;
@@ -138,13 +142,13 @@ public class RfidService extends Service {
         idleDisconnectRunnable = () -> {
             if (isConnected && !isScanning) {
                 Log.d(RfidConstants.TAG, "读卡器空闲超时(" + scanIdleTimeoutMs / 1000 + "秒),自动关闭连接");
+                isScanIdleTimeout = true;
                 disconnect(); // 自动断开连接
                 if (listener != null) {
                     listener.onScanInfo("读卡器空闲超时,已自动断开连接");
                 }
             }
         };
-
     }
 
     /**
@@ -155,8 +159,8 @@ public class RfidService extends Service {
             // 移除之前的任务,重新计时
             idleHandler.removeCallbacks(idleDisconnectRunnable);
             idleHandler.postDelayed(idleDisconnectRunnable, scanIdleTimeoutMs);
-            // Log.d(RfidConstants.TAG, "读卡器空闲计时器已重置,超时时间:" + scanIdleTimeoutMs / 1000 +
-            // "秒");
+            Log.d(RfidConstants.TAG, "读卡器空闲计时器已重置,超时时间:" + scanIdleTimeoutMs / 1000 +
+                    "秒");
         }
     }
 
@@ -197,6 +201,11 @@ public class RfidService extends Service {
             }
             readerParameter = new ReaderParameter();
             Log.d(RfidConstants.TAG, "RFID阅读器初始化成功");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(RfidConstants.TAG, "加载本地库失败,可能是缺少libSerialPort.so", e);
+            if (listener != null) {
+                listener.onScanError("加载本地库失败,请检查设备兼容性:" + e.getMessage());
+            }
         } catch (Exception e) {
             Log.e(RfidConstants.TAG, "Init reader failed", e);
             if (listener != null) {
@@ -279,39 +288,31 @@ public class RfidService extends Service {
     }
 
     /**
-     * 亮屏后恢复读卡(延迟重连避免硬件卡顿)
+     * 亮屏后恢复连接
      */
     private void resumeScanAfterScreenOn() {
-        if (isConnected && !isScanning) {
-            executorService.execute(() -> {
-                try {
-                    Thread.sleep(scanReconnectDelayMs); // 延迟恢复
-                    // rrlib.StartRead();
-                    // isScanning = true;
-                    acquireWakeLock();
-                    if (!isConnected) {
-                        connect();
-                    } else {
-                        if (listener != null) {
-                            listener.onConnectSuccess(curPort, curBaud);
-                        }
-                    }
-                    // stopIdleTimeout(); // 恢复读卡后停止空闲计时
-                    // Log.d(RfidConstants.TAG, "亮屏恢复RFID读卡成功");
-                    // if (listener != null) {
-                    // listener.onTagScanned(rrlib.getInventoryTagMapList()); // 触发一次读卡回调
-                    // }
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                    Log.e(RfidConstants.TAG, "恢复读卡线程被中断", e);
-                } catch (Exception e) {
-                    Log.e(RfidConstants.TAG, "亮屏恢复读卡失败", e);
-                    if (listener != null) {
-                        listener.onScanError("亮屏恢复读卡失败:" + e.getMessage());
-                    }
+        try {
+            Thread.sleep(scanReconnectDelayMs); // 延迟恢复
+            // rrlib.StartRead();
+            // isScanning = true;
+            acquireWakeLock();
+            if (!isConnected) {
+                connect();
+            } else if (isScanIdleTimeout) {
+                if (listener != null) {
+                    listener.onConnectSuccess(curPort, curBaud);
                 }
-            });
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            Log.e(RfidConstants.TAG, "恢复读卡线程被中断", e);
+        } catch (Exception e) {
+            Log.e(RfidConstants.TAG, "亮屏恢复读卡失败", e);
+            if (listener != null) {
+                listener.onScanError("亮屏恢复读卡失败:" + e.getMessage());
+            }
         }
+
     }
 
     @Override
@@ -515,6 +516,7 @@ public class RfidService extends Service {
                             Log.d(RfidConstants.TAG, "Reader Interval: " + readerParameter.Interval);
                             Log.d(RfidConstants.TAG, "Reader TidLen: " + readerParameter.TidLen);
                             Log.d(RfidConstants.TAG, "Reader TidPtr: " + readerParameter.TidPtr);
+                            resetIdleTimeout();
                             break; // 跳出所有循环
                         } else {
                             Log.e(RfidConstants.TAG, "连接[" + i + "]: " + result);
@@ -595,6 +597,7 @@ public class RfidService extends Service {
             setPower();
         }
         Log.d(RfidConstants.TAG, "RFID设备读卡,功率:" + getPower() + "W");
+        isScanIdleTimeout = false;
         return _startScan();
     }
 

+ 13 - 1
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanManager.java

@@ -29,7 +29,19 @@ public class ScanManager {
             ScanBinder binder = (ScanBinder) service;
             scanService = binder.getService();
             scanService.setListener(listener); // 设置回调监听
-            scanService.openScanHead();
+            try {
+                scanService.openScanHead();
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(TAG, "绑定服务时加载本地库失败", e);
+                if (listener != null) {
+                    listener.onScanError("绑定服务时加载本地库失败:" + e.getMessage());
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "绑定服务时发生错误", e);
+                if (listener != null) {
+                    listener.onScanError("绑定服务时发生错误:" + e.getMessage());
+                }
+            }
             isBound = true;
         }
 

+ 27 - 0
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanMethodCallHandler.java

@@ -106,6 +106,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             boolean success = scanManager.openScanHead();
             result.success(success);
             Log.d(TAG, "打开扫描头请求已处理");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "打开扫描头时加载本地库失败", e);
+            result.error("OPEN_SCAN_HEAD_FAILED", "打开扫描头失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "打开扫描头失败", e);
             result.error("OPEN_SCAN_HEAD_FAILED", "打开扫描头失败: " + e.getMessage(), null);
@@ -120,6 +123,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             scanManager.closeScanHead();
             result.success(true);
             Log.d(TAG, "关闭扫描头请求已处理");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "关闭扫描头时加载本地库失败", e);
+            result.error("CLOSE_SCAN_HEAD_FAILED", "关闭扫描头失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "关闭扫描头失败", e);
             result.error("CLOSE_SCAN_HEAD_FAILED", "关闭扫描头失败: " + e.getMessage(), null);
@@ -138,6 +144,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             } else {
                 Log.w(TAG, "开始扫描请求失败");
             }
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "开始扫描时加载本地库失败", e);
+            result.error("START_SCAN_FAILED", "开始扫描失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "开始扫描失败", e);
             result.error("START_SCAN_FAILED", "开始扫描失败: " + e.getMessage(), null);
@@ -152,6 +161,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             scanManager.stopScan();
             result.success(null);
             Log.d(TAG, "停止扫描请求已处理");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "停止扫描时加载本地库失败", e);
+            result.error("STOP_SCAN_FAILED", "停止扫描失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "停止扫描失败", e);
             result.error("STOP_SCAN_FAILED", "停止扫描失败: " + e.getMessage(), null);
@@ -166,6 +178,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             scanManager.resetTimeout();
             result.success(null);
             Log.d(TAG, "重置超时请求已处理");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "重置超时时加载本地库失败", e);
+            result.error("RESET_TIMEOUT_FAILED", "重置超时失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "重置超时失败", e);
             result.error("RESET_TIMEOUT_FAILED", "重置超时失败: " + e.getMessage(), null);
@@ -184,6 +199,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             } else {
                 result.error("INVALID_ARGUMENT", "灯光模式参数不能为空", null);
             }
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "设置灯光模式时加载本地库失败", e);
+            result.error("SET_LIGHTING_MODE_FAILED", "设置灯光模式失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "设置灯光模式失败", e);
             result.error("SET_LIGHTING_MODE_FAILED", "设置灯光模式失败: " + e.getMessage(), null);
@@ -198,6 +216,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             boolean isScanning = scanManager.isScanning();
             result.success(isScanning);
             Log.d(TAG, "检查扫描状态成功: " + isScanning);
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "检查扫描状态时加载本地库失败", e);
+            result.error("CHECK_SCANNING_FAILED", "检查扫描状态失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "检查扫描状态失败", e);
             result.error("CHECK_SCANNING_FAILED", "检查扫描状态失败: " + e.getMessage(), null);
@@ -212,6 +233,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             boolean isOpened = scanManager.isScanHeadOpened();
             result.success(isOpened);
             Log.d(TAG, "检查扫描头状态成功: " + isOpened);
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "检查扫描头状态时加载本地库失败", e);
+            result.error("CHECK_SCAN_HEAD_OPENED_FAILED", "检查扫描头状态失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "检查扫描头状态失败", e);
             result.error("CHECK_SCAN_HEAD_OPENED_FAILED", "检查扫描头状态失败: " + e.getMessage(), null);
@@ -226,6 +250,9 @@ public class ScanMethodCallHandler implements MethodCallHandler, ScanListener {
             scanManager.release();
             result.success(null);
             Log.d(TAG, "释放资源请求已处理");
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "释放资源时加载本地库失败", e);
+            result.error("RELEASE_RESOURCES_FAILED", "释放资源失败,请检查设备兼容性:" + e.getMessage(), null);
         } catch (Exception e) {
             Log.e(TAG, "释放资源失败", e);
             result.error("RELEASE_RESOURCES_FAILED", "释放资源失败: " + e.getMessage(), null);

+ 53 - 1
UI/CF.APP/chicken_farm/android/app/src/main/java/com/vber/chicken_farm/scan/ScanService.java

@@ -212,7 +212,21 @@ public class ScanService extends Service {
     public boolean openScanHead() {
         // 初始化扫描管理器
         if (scanManager == null) {
-            scanManager = ScanManager.getDefaultInstance(this);
+            try {
+                scanManager = ScanManager.getDefaultInstance(this);
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(TAG, "加载本地库失败,可能是缺少so库文件", e);
+                if (listener != null) {
+                    listener.onScanError("加载本地库失败,请检查设备兼容性:" + e.getMessage());
+                }
+                return false;
+            } catch (Exception e) {
+                Log.e(TAG, "获取ScanManager实例失败", e);
+                if (listener != null) {
+                    listener.onScanError("扫描硬件初始化失败: " + e.getMessage());
+                }
+                return false;
+            }
             if (scanManager == null) {
                 Log.e(TAG, "获取ScanManager实例失败");
                 if (listener != null) {
@@ -258,6 +272,12 @@ public class ScanService extends Service {
 
             Log.d(TAG, "扫描头已打开");
             return true;
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "加载本地库失败,可能是缺少so库文件", e);
+            if (listener != null) {
+                listener.onScanError("加载本地库失败,请检查设备兼容性:" + e.getMessage());
+            }
+            return false;
         } catch (Exception e) {
             Log.e(TAG, "打开扫描头失败", e);
             if (listener != null) {
@@ -326,6 +346,11 @@ public class ScanService extends Service {
              * 是否启用所有二维码(true-启用; false-不启用)
              */
             scanManager.enableSYM2D(true);
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "设置默认参数时加载本地库失败", e);
+            if (listener != null) {
+                listener.onScanError("设置默认参数失败,请检查设备兼容性:" + e.getMessage());
+            }
         } catch (Exception e) {
             Log.e(TAG, "设置默认参数失败", e);
         }
@@ -342,6 +367,11 @@ public class ScanService extends Service {
         if (scanManager != null && isScanning) {
             try {
                 scanManager.stopDecode();
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(TAG, "停止解码时加载本地库失败", e);
+                if (listener != null) {
+                    listener.onScanError("停止解码失败,请检查设备兼容性:" + e.getMessage());
+                }
             } catch (Exception e) {
                 Log.e(TAG, "停止解码失败", e);
             }
@@ -352,6 +382,11 @@ public class ScanService extends Service {
             try {
                 scanManager.closeScanner();
                 Log.d(TAG, "扫描头已关闭");
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(TAG, "关闭扫描头时加载本地库失败", e);
+                if (listener != null) {
+                    listener.onScanError("关闭扫描头失败,请检查设备兼容性:" + e.getMessage());
+                }
             } catch (Exception e) {
                 Log.e(TAG, "关闭扫描头失败", e);
             }
@@ -409,6 +444,13 @@ public class ScanService extends Service {
 
             Log.d(TAG, "开始扫描");
             return true;
+        } catch (UnsatisfiedLinkError e) {
+            Log.e(TAG, "开始扫描时加载本地库失败", e);
+            if (listener != null) {
+                listener.onScanError("开始扫描失败,请检查设备兼容性:" + e.getMessage());
+            }
+            isScanning = false;
+            return false;
         } catch (Exception e) {
             Log.e(TAG, "开始扫描失败", e);
             isScanning = false;
@@ -431,6 +473,11 @@ public class ScanService extends Service {
             try {
                 scanManager.stopDecode();
                 Log.d(TAG, "扫描已停止");
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(TAG, "停止扫描时加载本地库失败", e);
+                if (listener != null) {
+                    listener.onScanError("停止扫描失败,请检查设备兼容性:" + e.getMessage());
+                }
             } catch (Exception e) {
                 Log.e(TAG, "停止扫描失败", e);
             }
@@ -487,6 +534,11 @@ public class ScanService extends Service {
                 int[] symValue = { mode };
                 scanManager.setSYMValueInts(paramIDList, symValue);
                 Log.d(TAG, "灯光模式设置为:" + mode);
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(TAG, "设置灯光模式时加载本地库失败", e);
+                if (listener != null) {
+                    listener.onScanError("设置灯光模式失败,请检查设备兼容性:" + e.getMessage());
+                }
             } catch (Exception e) {
                 Log.e(TAG, "设置灯光模式失败", e);
                 if (listener != null) {

+ 28 - 2
UI/CF.APP/chicken_farm/android/build.gradle

@@ -5,7 +5,6 @@ allprojects {
     }
 }
 
-// 注释掉自定义构建目录设置,避免不同磁盘间的路径冲突
 def newBuildDir = rootProject.layout.buildDirectory.dir("../../build").get()
 rootProject.layout.buildDirectory.set(newBuildDir)
 
@@ -14,10 +13,37 @@ subprojects {
     project.layout.buildDirectory.set(newSubprojectBuildDir)
 }
 
+
 subprojects {
     project.evaluationDependsOn(":app")
+
+    plugins.whenPluginAdded { plugin ->
+        // 修复点1:增加空安全判断 + 仅针对Android/Java插件(排除系统插件)
+        def pluginName = plugin.getClass().simpleName
+        if (pluginName in ['AndroidPlugin', 'JavaPlugin', 'JavaLibraryPlugin']) {
+            // 修复点2:仅在任务创建时拦截目标项目的UnitTest任务
+            tasks.whenTaskAdded { task ->
+                // 仅处理flutter_plugin_android_lifecycle项目,忽略其他插件(如audioplayers_android)
+                if (project.path == ':flutter_plugin_android_lifecycle') {
+                    // 精准禁用报错任务,避免波及其他插件
+                    def targetTasks = [
+                        'compileDebugUnitTestSources',
+                        'testDebugUnitTest',
+                        'compileReleaseUnitTestSources',
+                        'testReleaseUnitTest'
+                    ]
+                    if (targetTasks.contains(task.name)) {
+                        task.enabled = false
+                        println("Disabled task: ${task.name} for flutter_plugin_android_lifecycle (resolve path error)")
+                    }
+                }
+            }
+        }
+    }
 }
 
 tasks.register("clean", Delete) {
     delete rootProject.layout.buildDirectory
-}
+    delete project(":app").layout.buildDirectory
+}
+

+ 7 - 1
UI/CF.APP/chicken_farm/android/gradle.properties

@@ -4,4 +4,10 @@ android.enableJetifier=true
 // 添加这些配置以提高构建稳定性
 kotlin.incremental=false
 org.gradle.caching=false
-org.gradle.parallel=false
+org.gradle.parallel=false
+// 解决sqlite3库下载问题
+sqlite3_flutter_libs.use_system_sqlite=true
+sqlite3_flutter_libs.no_download=true
+// 解决Flutter hooks runner锁定问题
+FLUTTER_HOOKS_RUNNER_LOCK_TIMEOUT=60
+org.gradle.unsafe.configuration-cache=false

+ 9 - 9
UI/CF.APP/chicken_farm/lib/apis/breeding/_submit.dart

@@ -36,7 +36,7 @@ class BreedSubmitApi {
       }).toList();
       ResultModel result = ResultModel.offline();
       if (!AppConfig.isOffline &&
-          await _breedingDataService.queryCount(TableConfig.chicken) == 0) {
+          await _breedingDataService.queryTotalCount() == 0) {
         result = await ApiService().post(
           bindChickenUrl,
           data: list,
@@ -69,7 +69,7 @@ class BreedSubmitApi {
       }).toList();
       ResultModel result = ResultModel.offline();
       if (!AppConfig.isOffline &&
-          await _breedingDataService.queryCount(TableConfig.chicken) == 0) {
+          await _breedingDataService.queryTotalCount() == 0) {
         result = await ApiService().post(
           cageChangeUrl,
           data: list,
@@ -100,7 +100,7 @@ class BreedSubmitApi {
       List<Map<String, dynamic>> list = [weightData].toList();
       ResultModel result = ResultModel.offline();
       if (!AppConfig.isOffline &&
-          await _breedingDataService.queryCount(TableConfig.chicken) == 0) {
+          await _breedingDataService.queryTotalCount() == 0) {
         result = await ApiService().post(
           weightUrl,
           data: list,
@@ -130,7 +130,7 @@ class BreedSubmitApi {
       ];
       ResultModel result = ResultModel.offline();
       if (!AppConfig.isOffline &&
-          await _breedingDataService.queryCount(TableConfig.chicken) == 0) {
+          await _breedingDataService.queryTotalCount() == 0) {
         result = await ApiService().post(
           cullUrl,
           data: list,
@@ -161,7 +161,7 @@ class BreedSubmitApi {
       }).toList();
       ResultModel result = ResultModel.offline();
       if (!AppConfig.isOffline &&
-          await _breedingDataService.queryCount(TableConfig.chicken) == 0) {
+          await _breedingDataService.queryTotalCount() == 0) {
         result = await ApiService().post(
           cullUrl,
           data: list,
@@ -200,13 +200,13 @@ class BreedSubmitApi {
   String getUrl(String type) {
     switch (type) {
       case BreedConfig.chicken:
-        return '$apiPrefix/bindChicken';
+        return '$apiPrefix/addChicken';
       case BreedConfig.cageChange:
-        return '$apiPrefix/cageChange';
+        return '$apiPrefix/changeCage';
       case BreedConfig.weight:
-        return '$apiPrefix/weight';
+        return '$apiPrefix/chickenWeight';
       case BreedConfig.cull:
-        return '$apiPrefix/cull';
+        return '$apiPrefix/cullChicken';
       default:
         return '';
     }

+ 13 - 2
UI/CF.APP/chicken_farm/lib/components/vb_electronic_id_field.dart

@@ -100,12 +100,23 @@ class _VberElectronicIdsFieldState extends State<VberElectronicIdsField> {
     }
   }
 
-  void _scanRfid() {
+  void _scanRfid() async {
     setState(() {
       _isScanning = true;
     });
     ToastUtil.show('开始识别电子编号', duration: 1);
-    RfidManager.instance.startScan(isMultiple: _isMultiple);
+    int result = await RfidManager.instance.startRead(isMultiple: _isMultiple);
+    if (result == 1) {
+      ToastUtil.errorAlert('读卡器已自动断开连接!\n现在正在连接中,请稍后重试!');
+      setState(() {
+        _isScanning = false;
+      });
+    } else if (result == 2) {
+      ToastUtil.errorAlert('读卡器读取失败,请检查读卡器是否正常');
+      setState(() {
+        _isScanning = false;
+      });
+    }
   }
 
   @override

+ 12 - 9
UI/CF.APP/chicken_farm/lib/core/config/app_config.dart

@@ -1,27 +1,30 @@
-import 'package:chicken_farm/core/config/env/dev_config.dart';
+// import 'package:chicken_farm/core/config/env/dev_config.dart';
 // import 'package:chicken_farm/core/config/env/dev_no_pda_config.dart';
 // import 'package:chicken_farm/core/config/env/dev_offline_config.dart';
 // import 'package:chicken_farm/core/config/env/prod_config.dart';
+// import 'package:chicken_farm/core/config/env/prod_offline_config.dart';
 // import 'package:chicken_farm/core/config/env/prod_no_pda_config.dart';
+import 'package:chicken_farm/core/config/env/env_config.dart';
 import 'package:chicken_farm/core/utils/storage.dart';
 
 class AppConfig {
   static const String baseUrlKey = 'base_url';
   static const String clientIdKey = 'client_id';
-  static String baseUrl = Config.baseApiUrl; // 默认值
-  static String clientId = Config.clientId; // 默认值
+  static String baseUrl = EnvConfig.baseApiUrl; // 默认值
+  static String clientId = EnvConfig.clientId; // 默认值
 
   /// 是否为开发环境
-  static bool get isDev => Config.appEnv == 'dev';
+  static bool get isDev => EnvConfig.appEnv.contains('dev');
 
   /// 是否为生产环境
-  static bool get isProd => Config.appEnv == 'prod';
+  static bool get isProd => EnvConfig.appEnv.contains('prod');
 
-  static String get appName => Config.appName;
+  static String get appName => EnvConfig.appName;
 
-  static String get appVersion => Config.appVersion;
-  static bool get isOffline => Config.isOffline;
-  static bool get isPda => Config.isPda;
+  static String get appVersion => EnvConfig.appVersion;
+  static bool get isOffline => EnvConfig.isOffline;
+  static bool get isPda => EnvConfig.isPda;
+  static String get winDbPath => EnvConfig.winDbPath;
 
   // 初始化配置
   static Future<void> init() async {

+ 0 - 9
UI/CF.APP/chicken_farm/lib/core/config/env/dev_config.dart

@@ -1,9 +0,0 @@
-class Config {
-  static const String appEnv = 'dev';
-  static const String appName = '养殖场管理系统';
-  static const String baseApiUrl = 'http://192.168.0.81:8380';
-  static const String clientId = '35aee70ae7224eb9a48bc527955ddedc';
-  static const bool isOffline = false;
-  static const bool isPda = true;
-  static const String appVersion = '1.0.0-dev';
-}

+ 0 - 9
UI/CF.APP/chicken_farm/lib/core/config/env/dev_no_pda_config.dart

@@ -1,9 +0,0 @@
-class Config {
-  static const String appEnv = 'dev';
-  static const String appName = '养殖场管理系统';
-  static const String baseApiUrl = 'http://192.168.0.81:8380';
-  static const String clientId = '35aee70ae7224eb9a48bc527955ddedc';
-  static const bool isOffline = false;
-  static const bool isPda = false;
-  static const String appVersion = '1.0.0-dev';
-}

+ 0 - 9
UI/CF.APP/chicken_farm/lib/core/config/env/dev_offline_config.dart

@@ -1,9 +0,0 @@
-class Config {
-  static const String appEnv = 'dev';
-  static const String appName = '养殖场管理系统(脱机)';
-  static const String baseApiUrl = 'http://192.168.0.81:8380';
-  static const String clientId = '35aee70ae7224eb9a48bc527955ddedc';
-  static const bool isOffline = true;
-  static const bool isPda = true;
-  static const String appVersion = '1.0.0-dev';
-}

+ 31 - 0
UI/CF.APP/chicken_farm/lib/core/config/env/env_config.dart

@@ -0,0 +1,31 @@
+class EnvConfig {
+  static const String appEnv = String.fromEnvironment(
+    'APP_ENV',
+    defaultValue: 'dev',
+  );
+  static const String appName = String.fromEnvironment(
+    "APP_NAME",
+    defaultValue: "养殖场管理系统",
+  );
+  static const String appVersion = String.fromEnvironment(
+    "APP_VERSION",
+    defaultValue: "1.0.0-dev",
+  );
+  static const String baseApiUrl = String.fromEnvironment(
+    "BASE_API_URL",
+    defaultValue: "http://192.168.0.81:8380",
+  );
+  static const String clientId = String.fromEnvironment(
+    "CLIENT_ID",
+    defaultValue: "35aee70ae7224eb9a48bc527955ddedc",
+  );
+  static const bool isOffline =
+      String.fromEnvironment("IS_OFFLINE", defaultValue: "false") == "true";
+  static const bool isPda =
+      String.fromEnvironment("IS_PDA", defaultValue: "true") == "true";
+
+  static const String winDbPath = String.fromEnvironment(
+    "WIN_DB_PATH",
+    defaultValue: ".demo/data",
+  );
+}

+ 0 - 9
UI/CF.APP/chicken_farm/lib/core/config/env/prod_config.dart

@@ -1,9 +0,0 @@
-class Config {
-  static const String appEnv = 'prod';
-  static const String appName = '养殖场管理系统';
-  static const String baseApiUrl = 'https://prod-api.example.com';
-  static const String clientId = 'prod_client_id';
-  static const bool isOffline = false;
-  static const bool isPda = true;
-  static const String appVersion = '1.0.0';
-}

+ 0 - 9
UI/CF.APP/chicken_farm/lib/core/config/env/prod_no_pda_config.dart

@@ -1,9 +0,0 @@
-class Config {
-  static const String appEnv = 'prod';
-  static const String appName = '养殖场管理系统';
-  static const String baseApiUrl = 'http://192.168.0.81:8380';
-  static const String clientId = '35aee70ae7224eb9a48bc527955ddedc';
-  static const bool isOffline = false;
-  static const bool isPda = false;
-  static const String appVersion = '1.0.0-dev';
-}

+ 0 - 9
UI/CF.APP/chicken_farm/lib/core/config/env/prod_offline_config.dart

@@ -1,9 +0,0 @@
-class Config {
-  static const String appEnv = 'prod';
-  static const String appName = '养殖场管理系统(脱机)';
-  static const String baseApiUrl = 'https://prod-api.example.com';
-  static const String clientId = 'prod_client_id';
-  static const bool isOffline = true;
-  static const bool isPda = true;
-  static const String appVersion = '1.0.0';
-}

+ 2 - 1
UI/CF.APP/chicken_farm/lib/core/db/sqlite_manager.dart

@@ -1,5 +1,6 @@
 import 'dart:async';
 import 'dart:io';
+import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/core/db/table_config.dart';
 import 'package:chicken_farm/core/utils/datetime_util.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
@@ -96,7 +97,7 @@ class SqliteManager {
       }
     } else if (Platform.isWindows) {
       // Windows 使用应用运行目录下的Data目录
-      dbFolderPath = join(Directory.current.path, 'Data');
+      dbFolderPath = join(Directory.current.path, AppConfig.winDbPath);
       // 检查并创建 Data 文件夹(不存在则创建)
       Directory dbFolder = Directory(dbFolderPath);
       if (!await dbFolder.exists()) {

+ 1 - 1
UI/CF.APP/chicken_farm/lib/core/errors/error_handler.dart

@@ -26,7 +26,7 @@ class ErrorHandler {
         return NetworkError(message: "网络连接错误,请检查网络");
       case DioExceptionType.badResponse:
         final statusCode = error.response?.statusCode;
-        final errorMessage = error.response?.data['message'] ?? "服务器错误";
+        final errorMessage = "服务器错误[$statusCode]";
 
         if (statusCode == 401) {
           return AuthError(message: "认证失败,请重新登录", statusCode: statusCode);

+ 34 - 18
UI/CF.APP/chicken_farm/lib/core/services/pda/rfid_manager.dart

@@ -2,6 +2,7 @@ import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/core/utils/toast.dart';
 import 'package:chicken_farm/modes/rfid/rfid_model.dart';
+import 'package:flutter/services.dart';
 import 'rfid_channel.dart';
 import 'dart:async';
 
@@ -76,25 +77,25 @@ class RfidManager {
               } else {
                 ToastUtil.errorAlert("读卡器连接失败!!!");
               }
-              logger.e("❌ 设备连接失败[$errorCount]: ${event.error}");
+              logger.e("❌ 读卡器连接失败[$errorCount]: ${event.error}");
               break;
             case RfidEventType.tagScanned:
-              logger.i("📶 扫描到标签: ${event.data}");
+              logger.i("📶 读卡器读取到标签: ${event.data}");
               _handleScannedTags(event.data);
               break;
             case RfidEventType.scanError:
-              logger.e("❌ 扫描错误: ${event.error}");
+              logger.e("❌ 读卡器读取错误: ${event.error}");
               // ToastUtil.error("扫描出错");
               _onErrorScanned?.call(event.error ?? "未知错误");
               break;
             case RfidEventType.scanInfo:
-              logger.i("❌ 扫描信息: ${event.info}");
-              // if (event.info != null) {
-              //   ToastUtil.info("${event.info}");
-              // }
+              logger.i("❌ 读卡器信息: ${event.info}");
+              if (event.info != null && event.info!.contains("超时")) {
+                ToastUtil.info("${event.info}");
+              }
               break;
             case RfidEventType.disconnected:
-              logger.i("🔌 设备已断开连接");
+              logger.i("🔌 读卡器已断开连接");
               break;
             case RfidEventType.onKeyPress: // 处理按键事件
               _onKeyPress?.call(event.data);
@@ -138,14 +139,27 @@ class RfidManager {
     _onConnectSuccess = null;
   }
 
-  Future<void> connect() async {
-    if (!(await RfidChannel.isConnected())) {
-      _startConnectionChecking();
+  /// 连接RFID读卡器
+  Future<bool> connect() async {
+    try {
+      final bool connected = await RfidChannel.connect(retryTimes: 3);
+      if (connected) {
+        _startConnectionChecking();
+        logger.i("✅ RFID读卡器连接成功");
+      } else {
+        logger.e("❌ RFID读卡器连接失败");
+      }
+      return connected;
+    } on PlatformException catch (e) {
+      logger.e("❌ RFID读卡器连接异常: ${e.message}");
+      // 显示友好的错误提示而不是让应用崩溃
+      ToastUtil.errorAlert("读卡器连接失败,请检查设备兼容性");
+      return false;
+    } catch (e) {
+      logger.e("❌ RFID读卡器连接未知错误: $e");
+      ToastUtil.errorAlert("读卡器连接出现未知错误");
+      return false;
     }
-    // 在新线程中执行初始化
-    Timer.run(() async {
-      await RfidChannel.connect(retryTimes: 2);
-    });
   }
 
   /// 开始连接状态检查
@@ -200,24 +214,26 @@ class RfidManager {
   }
 
   /// 开始扫描
-  Future<void> startScan({bool isMultiple = false}) async {
+  Future<int> startRead({bool isMultiple = false}) async {
     // 检查连接状态
     final bool isConnected = await _ensureConnected();
     if (!isConnected) {
       logger.e("❌ 无法启动扫描,读卡器未连接");
-      return;
+      return 1;
     }
 
     final bool isStarted = await RfidChannel.startScan(isMultiple);
     if (isStarted) {
       logger.i("▶️ 扫描已启动");
+      return 0;
     } else {
       logger.e("❌ 扫描启动失败");
+      return 2;
     }
   }
 
   /// 停止扫描
-  Future<void> stopScan() async {
+  Future<void> stopRead() async {
     await RfidChannel.stopScan();
     logger.i("⏹️ 扫描已停止");
   }

+ 21 - 37
UI/CF.APP/chicken_farm/lib/core/services/upload_service.dart

@@ -1,15 +1,15 @@
 import 'dart:async';
 
+import 'package:chicken_farm/apis/index.dart';
 import 'package:chicken_farm/core/config/breed_config.dart';
 import 'package:chicken_farm/core/db/table_config.dart';
 import 'package:chicken_farm/core/services/breeding_data_service.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/core/utils/service_checker.dart';
-import 'package:chicken_farm/modes/api/result_model.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 
 typedef UploadProgressCallback =
-    void Function(int uploaded, int total, String status);
+    void Function(int uploaded, int error, int total, String status);
 typedef UploadCompleteCallback = void Function();
 typedef UploadErrorCallback = void Function(String error, {bool isAuthError});
 
@@ -29,6 +29,7 @@ class UploadService {
   bool isAuthErr = false;
   int totalOperations = 0;
   int uploadedCount = 0;
+  int errorCount = 0;
   UploadProgressCallback? _onProgress;
   UploadCompleteCallback? _onComplete;
   UploadErrorCallback? _onError;
@@ -45,7 +46,7 @@ class UploadService {
 
     // 如果上传正在进行中,则立即通知新的进度回调
     if (_isUploading) {
-      _onProgress?.call(uploadedCount, totalOperations, '上传中...');
+      _onProgress?.call(uploadedCount, errorCount, totalOperations, '上传中...');
     }
   }
 
@@ -83,7 +84,7 @@ class UploadService {
       }
 
       logger.i('开始上传 $totalOperations 个离线操作');
-      _onProgress?.call(uploadedCount, totalOperations, '上传中...');
+      _onProgress?.call(uploadedCount, errorCount, totalOperations, '上传中...');
 
       bool flag = true;
       // 上传个体绑定数据
@@ -134,12 +135,15 @@ class UploadService {
         return false;
       }
       int count = 0;
-      // final result = await _breedSubmitApi.upload(breedConfigType, data);
-      ResultModel result = ResultModel.fail("");
-      // 模拟5秒延迟
-      await Future.delayed(Duration(seconds: 2), () {
-        result = ResultModel.success("");
-      });
+      final result = await apis.breeding.submitApi.upload(
+        breedConfigType,
+        data,
+      );
+      // ResultModel result = ResultModel.fail("");
+      // // 模拟5秒延迟
+      // await Future.delayed(Duration(seconds: 2), () {
+      //   result = ResultModel.success("");
+      // });
       if (result.success) {
         // 上传成功,更新导出状态
         await _bdService.delete(tableName, 'id = ?', [data['id']]);
@@ -148,9 +152,10 @@ class UploadService {
         logger.i('$breedConfigType 类型数据 id:${data['id']} 上传成功');
         _onProgress?.call(
           uploadedCount,
+          errorCount,
           totalOperations,
           count == dataList.length
-              ? '${BreedConfig.getName(breedConfigType)}已上传完成!}'
+              ? '${BreedConfig.getName(breedConfigType)}已上传完成!'
               : '上传中...',
         );
       } else if (result.isNetError == true) {
@@ -169,8 +174,12 @@ class UploadService {
         logger.e(
           '$breedConfigType 类型数据 id:${data['id']} 上传失败: ${result.message}',
         );
+        await _bdService.delete(tableName, 'id = ?', [data['id']]);
+        uploadedCount++;
+        errorCount++;
+        count++;
         _onError?.call(result.message);
-        return false;
+        _onProgress?.call(uploadedCount, errorCount, totalOperations, '上传中...');
       }
     }
     return true;
@@ -196,29 +205,4 @@ class UploadService {
   void showUpload() {
     isHideUpload = false;
   }
-
-  // bool _isAuthError(dynamic error) {
-  //   // 检查是否为鉴权错误 (401 或 403)
-  //   if (error is DioException) {
-  //     return error.response?.statusCode == 401 ||
-  //         error.response?.statusCode == 403;
-  //   }
-  //   // 根据错误消息判断是否为鉴权错误
-  //   final errorString = error.toString().toLowerCase();
-  //   return errorString.contains('unauthorized') ||
-  //       errorString.contains('forbidden') ||
-  //       errorString.contains('401') ||
-  //       errorString.contains('403');
-  // }
-
-  // bool _isAuthErrorString(String? message) {
-  //   if (message == null) return false;
-  //   final errorString = message.toLowerCase();
-  //   return errorString.contains('登录') ||
-  //       errorString.contains('权限') ||
-  //       errorString.contains('unauthorized') ||
-  //       errorString.contains('forbidden') ||
-  //       errorString.contains('401') ||
-  //       errorString.contains('403');
-  // }
 }

+ 6 - 0
UI/CF.APP/chicken_farm/lib/main.dart

@@ -1,5 +1,7 @@
+import 'package:chicken_farm/core/config/env/env_config.dart';
 import 'package:chicken_farm/core/db/sqlite_manager.dart';
 import 'package:chicken_farm/core/services/pda/rfid_manager.dart';
+import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/vb_app.dart';
 import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/core/utils/loading.dart';
@@ -8,9 +10,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 
 void main() async {
   WidgetsFlutterBinding.ensureInitialized();
+
   await AppConfig.init(); // 初始化配置
 
+  logger.w("当前环境:  ${EnvConfig.appEnv}");
+
   await SqliteManager().init(dbName: 'breeding.db');
+
   if (AppConfig.isPda) {
     await RfidManager.instance.init();
   }

+ 3 - 3
UI/CF.APP/chicken_farm/lib/pages/account/login_page.dart

@@ -120,10 +120,10 @@ class _LoginPageState extends ConsumerState<LoginPage> {
                                                   password: _passwordCtrl.text,
                                                 ),
                                               )
-                                              .then((_) async {
+                                              .then((success) async {
                                                 // 登录成功后跳转到主页
-                                                if (context.mounted) {
-                                                  logger.d('登录成功');
+                                                if (success &&
+                                                    context.mounted) {
                                                   context.goNamed(
                                                     AppRouteNames.home,
                                                   );

+ 0 - 3
UI/CF.APP/chicken_farm/lib/pages/home/_profile/clear_cache_button.dart

@@ -2,7 +2,6 @@ import 'package:chicken_farm/core/utils/storage.dart';
 import 'package:chicken_farm/core/utils/toast.dart';
 import 'package:chicken_farm/stores/config_store.dart';
 import 'package:chicken_farm/stores/dict_stroe.dart';
-import 'package:chicken_farm/test/test.dart';
 import 'package:flutter/material.dart';
 
 class ClearCacheButton extends StatelessWidget {
@@ -14,8 +13,6 @@ class ClearCacheButton extends StatelessWidget {
       width: double.infinity,
       child: ElevatedButton.icon(
         onPressed: () {
-          Test().insetTestData();
-
           ToastUtil.confirm('确定要清除所有缓存吗?', () async {
             await StorageUtils.removeWithPrefix("vb_");
             ConfigStore().clearAll();

+ 14 - 0
UI/CF.APP/chicken_farm/lib/pages/home/profile.dart

@@ -100,6 +100,11 @@ class ProfilePage extends ConsumerWidget {
                     const LogoutButton(),
                     const SizedBox(height: 20),
                   ],
+                  Text(
+                    _buildVersionText(),
+                    textAlign: TextAlign.center,
+                    style: TextStyle(fontSize: 12, color: Colors.grey),
+                  ),
                 ],
               ],
             ),
@@ -108,4 +113,13 @@ class ProfilePage extends ConsumerWidget {
       ),
     );
   }
+
+  String _buildVersionText() {
+    final deviceType = AppConfig.isPda ? "PDA" : "APP";
+    final mode = AppConfig.isOffline ? "_OFFLINE" : "";
+
+    final deviceInfo = Platform.isAndroid ? "$deviceType$mode" : "WIN$mode";
+
+    return 'ChickenFarm $deviceInfo Powered by IWB ©2025 \nVersion: ${AppConfig.appVersion}';
+  }
 }

+ 17 - 11
UI/CF.APP/chicken_farm/lib/pages/upload/upload_page.dart

@@ -24,8 +24,10 @@ class UploadStatus {
 
 class _UploadPageState extends State<UploadPage> with WidgetsBindingObserver {
   late UploadService _uploadService;
-  int _totalOperations = 0;
-  int _uploadedOperations = 0;
+  int _totalCount = 0;
+  int _uploadedCount = 0;
+  int _errorCount = 0;
+  String _error = "";
   int _status = UploadStatus.preparing; // 改为int类型
   bool _isUploading = false;
   bool _uploadCompleted = false;
@@ -71,7 +73,7 @@ class _UploadPageState extends State<UploadPage> with WidgetsBindingObserver {
       case UploadStatus.completed:
         return '上传完成';
       case UploadStatus.error:
-        return '上传出错,请稍后再试';
+        return '上传出错,请稍后再试($_error)';
       case UploadStatus.exception:
         return '上传异常,请稍后再试';
       default:
@@ -130,8 +132,8 @@ class _UploadPageState extends State<UploadPage> with WidgetsBindingObserver {
       setState(() {
         _isUploading = true;
         _status = UploadStatus.uploading; // 使用状态常量
-        _uploadedOperations = 0;
-        _totalOperations = 0;
+        _uploadedCount = 0;
+        _totalCount = 0;
         _uploadCompleted = false;
       });
     }
@@ -140,11 +142,12 @@ class _UploadPageState extends State<UploadPage> with WidgetsBindingObserver {
     logger.d('开始上传,$t');
     // 注册回调
     _uploadService.registerCallbacks(
-      onProgress: (uploaded, total, status) {
+      onProgress: (uploaded, error, total, status) {
         if (mounted) {
           setState(() {
-            _uploadedOperations = uploaded;
-            _totalOperations = total;
+            _uploadedCount = uploaded;
+            _totalCount = total;
+            _errorCount = error;
           });
         }
         logger.d('上传进度 $t:$uploaded/$total');
@@ -176,6 +179,7 @@ class _UploadPageState extends State<UploadPage> with WidgetsBindingObserver {
         if (mounted) {
           setState(() {
             _isUploading = false;
+            _error = message;
             _status = UploadStatus.error; // 使用状态常量
           });
         }
@@ -215,13 +219,15 @@ class _UploadPageState extends State<UploadPage> with WidgetsBindingObserver {
                             textAlign: TextAlign.center,
                           ),
                           const SizedBox(height: 30),
-                          if (_totalOperations > 0) ...[
+                          if (_totalCount > 0) ...[
                             LinearProgressIndicator(
-                              value: _uploadedOperations / _totalOperations,
+                              value: _uploadedCount / _totalCount,
                               minHeight: 10,
                             ),
                             const SizedBox(height: 10),
-                            Text('$_uploadedOperations / $_totalOperations'),
+                            Text(
+                              '$_uploadedCount / $_totalCount [$_errorCount 错误]',
+                            ),
                             const SizedBox(height: 30),
                           ],
                           if (_isUploading) ...[

+ 6 - 1
UI/CF.APP/chicken_farm/lib/stores/auth_store.dart

@@ -5,6 +5,7 @@ import 'package:chicken_farm/core/services/navigation_service.dart';
 import 'package:chicken_farm/core/utils/jwt_token.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/core/utils/service_checker.dart';
+import 'package:chicken_farm/core/utils/toast.dart';
 import 'package:chicken_farm/modes/auth/login_model.dart';
 import 'package:chicken_farm/modes/user/user_model.dart';
 import 'package:chicken_farm/routes/app_routes.dart';
@@ -181,7 +182,7 @@ class AuthStore extends StateNotifier<AuthInfo> {
   }
 
   /// 登录操作
-  Future<void> login(LoginModel loginModel) async {
+  Future<bool> login(LoginModel loginModel) async {
     state = AuthInfo.loading();
     try {
       loginModel.clientId = AppConfig.clientId;
@@ -204,9 +205,13 @@ class AuthStore extends StateNotifier<AuthInfo> {
         roles: userInfo.roles,
       );
       logger.i('登录成功 state: $state');
+      return true;
     } catch (e) {
+      logger.e('登录失败: $e');
       await JwtToken.clear();
       state = AuthInfo.unauthenticated();
+      ToastUtil.errorAlert(e.toString());
+      return false;
     }
   }
 

BIN
UI/CF.APP/chicken_farm/release/app/pda_cf-app_V1.0.0.apk


BIN
UI/CF.APP/chicken_farm/release/app/pda_no_cf-app_V1.0.0.apk


BIN
UI/CF.APP/chicken_farm/release/app/pda_offline_cf-app_V1.0.0.apk