linee 4 일 전
부모
커밋
edacc21414
35개의 변경된 파일3700개의 추가작업 그리고 1013개의 파일을 삭제
  1. 2 0
      entry/build.gradle
  2. 42 0
      entry/src/main/java/com/fujica/abk/api/AuthResult.java
  3. 69 0
      entry/src/main/java/com/fujica/abk/api/HWResult.java
  4. 296 0
      entry/src/main/java/com/fujica/abk/api/auth.java
  5. 396 18
      entry/src/main/java/com/fujica/abk/api/cache.java
  6. 10 0
      entry/src/main/java/com/fujica/abk/api/config.java
  7. 1 1
      entry/src/main/java/com/fujica/abk/utils/LoadingComponent.java
  8. 101 127
      entry/src/main/java/com/fujica/abk/utils/ParkingItemComponent.java
  9. 475 0
      entry/src/main/java/com/fujica/abk/component/nav/FindParkingPageComponent.java
  10. 222 0
      entry/src/main/java/com/fujica/abk/component/nav/MyPageComponent.java
  11. 39 0
      entry/src/main/java/com/fujica/abk/component/nav/ReserveParkingPageComponent.java
  12. 35 0
      entry/src/main/java/com/fujica/abk/model/response/LoginRes.java
  13. 17 5
      entry/src/main/java/com/fujica/abk/model/response/ParkNearRes.java
  14. 0 5
      entry/src/main/java/com/fujica/abk/slice/MainAbilitySlice copy.java
  15. 48 475
      entry/src/main/java/com/fujica/abk/slice/MainAbilitySlice.java
  16. 53 0
      entry/src/main/java/com/fujica/abk/utils/DialogUtil.java
  17. 60 0
      entry/src/main/java/com/fujica/abk/utils/LicensePlateDialog.java
  18. 906 0
      entry/src/main/java/com/fujica/abk/utils/LicensePlateInputDialog.java
  19. 11 0
      entry/src/main/java/com/fujica/abk/utils/Log.java
  20. 59 0
      entry/src/main/java/com/fujica/abk/utils/ScreenUtil.java
  21. 136 146
      entry/src/main/java/com/fujica/abk/utils/api.java
  22. 10 0
      entry/src/main/resources/base/graphic/background_filter_item.xml
  23. 10 0
      entry/src/main/resources/base/graphic/button.xml
  24. 10 0
      entry/src/main/resources/base/graphic/button_cancel.xml
  25. 7 0
      entry/src/main/resources/base/graphic/container_body.xml
  26. 3 4
      entry/src/main/resources/base/graphic/container_bottom.xml
  27. 1 1
      entry/src/main/resources/base/graphic/container_top.xml
  28. 156 154
      entry/src/main/resources/base/layout/ability_main.xml
  29. 49 36
      entry/src/main/resources/base/layout/item_parking.xml
  30. 74 14
      entry/src/main/resources/base/layout/layout_find_parking.xml
  31. 264 0
      entry/src/main/resources/base/layout/layout_license_plate_dialog.xml
  32. 138 27
      entry/src/main/resources/base/layout/layout_my.xml
  33. BIN
      entry/src/main/resources/base/media/close.png
  34. BIN
      entry/src/main/resources/base/media/nocar.png
  35. BIN
      entry/src/main/resources/base/media/quit.png

+ 2 - 0
entry/build.gradle

@@ -37,6 +37,8 @@ dependencies {
 
     implementation 'com.huawei.hms:hwid-ohos:6.5.0.300'
     implementation 'com.huawei.agconnect:agconnect-core-harmony:1.3.0.300'
+    // Gson JSON 解析库
+    implementation 'com.google.code.gson:gson:2.10.1'
 }
 decc {
     supportType = ['html', 'xml']

+ 42 - 0
entry/src/main/java/com/fujica/abk/api/AuthResult.java

@@ -0,0 +1,42 @@
+package com.fujica.abk.api;
+
+/**
+ * 授权结果
+ */
+public class AuthResult {
+    private boolean success;
+    private String code;
+    private String appId;
+
+    public AuthResult() {
+    }
+
+    public AuthResult(boolean success) {
+        this.success = success;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public void setSuccess(boolean success) {
+        this.success = success;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+}
+

+ 69 - 0
entry/src/main/java/com/fujica/abk/api/HWResult.java

@@ -0,0 +1,69 @@
+package com.fujica.abk.api;
+
+/**
+ * 华为账号授权结果
+ */
+public class HWResult {
+    private String phone;
+    private String code;
+    private String appId;
+    private String unionId;
+    private String openId;
+    private boolean success;
+
+    public HWResult() {
+    }
+
+    public HWResult(boolean success) {
+        this.success = success;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getUnionId() {
+        return unionId;
+    }
+
+    public void setUnionId(String unionId) {
+        this.unionId = unionId;
+    }
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public void setSuccess(boolean success) {
+        this.success = success;
+    }
+}
+

+ 296 - 0
entry/src/main/java/com/fujica/abk/api/auth.java

@@ -0,0 +1,296 @@
+package com.fujica.abk.api;
+
+import com.fujica.abk.model.response.LoginRes;
+import com.fujica.abk.utils.Log;
+import com.fujica.abk.utils.R;
+import com.fujica.abk.utils.Toast;
+import com.fujica.abk.utils.api;
+import com.fujica.abk.utils.ApiOption;
+import com.google.gson.reflect.TypeToken;
+import com.huawei.hms.accountsdk.exception.ApiException;
+import com.huawei.hms.accountsdk.support.account.AccountAuthManager;
+import com.huawei.hms.accountsdk.support.account.request.AccountAuthParams;
+import com.huawei.hms.accountsdk.support.account.request.AccountAuthParamsHelper;
+import com.huawei.hms.accountsdk.support.account.result.AuthAccount;
+import com.huawei.hms.accountsdk.support.account.service.AccountAuthService;
+import com.huawei.hms.accountsdk.support.account.tasks.OnFailureListener;
+import com.huawei.hms.accountsdk.support.account.tasks.OnSuccessListener;
+import com.huawei.hms.accountsdk.support.account.tasks.Task;
+import ohos.app.Context;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 认证工具类
+ */
+public class auth {
+    /**
+     * 登录
+     * @param context 上下文
+     * @return CompletableFuture<Boolean> 登录是否成功
+     */
+    public static CompletableFuture<Boolean> login(Context context) {
+        CompletableFuture<Boolean> future = new CompletableFuture<>();
+        
+        if (cache.isAuth(context)) {
+            future.complete(true);
+            return future;
+        }
+
+        if(true){
+            HWResult hwResult = new HWResult();
+            hwResult.setAppId(config.appId);
+            hwResult.setOpenId("AAAjdc3u_VDHci9G3gSifWUoEpmH");
+
+            ApiOption option = new ApiOption();
+            option.setUrl("/member/hw/login");
+            option.setHideLoading(true);
+
+            // 注意:HMS SDK可能不直接提供authorizationCode,这里需要根据实际情况调整
+            // 如果HMS SDK不提供code,可能需要使用其他方式获取
+            java.util.Map<String, String> data = new java.util.HashMap<>();
+            data.put("appId", config.appId);
+            data.put("openId", hwResult.getOpenId());
+            data.put("unionId", hwResult.getUnionId());
+            option.setData(data);
+            processCodeLogin(context, option, hwResult, future);
+            return future;
+        }
+
+        try {
+            // 先获取华为账号信息
+            getHuaWeiAccount(context).thenAccept(hwResult -> {
+                if (!hwResult.isSuccess()) {
+                    future.complete(false);
+                    return;
+                }
+                
+                // 使用授权码登录
+                ApiOption option = new ApiOption();
+                option.setUrl("/member/hw/code/login");
+                option.setHideLoading(true);
+                
+                // 注意:HMS SDK可能不直接提供authorizationCode,这里需要根据实际情况调整
+                // 如果HMS SDK不提供code,可能需要使用其他方式获取
+                java.util.Map<String, String> data = new java.util.HashMap<>();
+                data.put("appId", config.appId);
+                // data.put("code", authResult.code); // 需要从授权结果中获取
+                data.put("openId", hwResult.getOpenId());
+                data.put("unionId", hwResult.getUnionId());
+                option.setData(data);
+                
+                processCodeLogin(context, option, hwResult, future);
+            }).exceptionally(e -> {
+                Log.error(e);
+                future.complete(false);
+                return null;
+            });
+        } catch (Exception e) {
+            Log.error(e);
+            future.complete(false);
+        }
+        
+        return future;
+    }
+    
+    /**
+     * 处理授权码登录
+     * @param context 上下文
+     * @param option API选项
+     * @param hwResult 华为账号信息
+     * @param future 异步结果
+     */
+    private static void processCodeLogin(Context context, ApiOption option, HWResult hwResult, CompletableFuture<Boolean> future) {
+        api.<HWResult>post1(context, option, new TypeToken<HWResult>(){}).thenAccept((R<HWResult> result) -> {
+            if (result != null && result.isSuccess() && result.getData() != null) {
+                HWResult loginResult = result.getData();
+                
+                if (loginResult != null) {
+                    String openId = loginResult.getOpenId() != null && !loginResult.getOpenId().isEmpty() 
+                            ? loginResult.getOpenId() : hwResult.getOpenId();
+                    String token = loginResult.getCode() != null ? loginResult.getCode() : "";
+                    String mobile = loginResult.getPhone() != null ? loginResult.getPhone() : "";
+                    
+                    cache.setOpenId(context, openId);
+                    cache.setToken(context, token);
+                    cache.setMobile(context, mobile);
+                    future.complete(true);
+                } else {
+                    // 如果登录失败,尝试使用手机号+验证码登录
+                    handlePhoneLogin(context, hwResult, future);
+                }
+            } else {
+                // 登录失败,尝试使用手机号+验证码登录
+                handlePhoneLogin(context, hwResult, future);
+            }
+        }).exceptionally(e -> {
+            Log.error(e);
+            future.complete(false);
+            return null;
+        });
+    }
+    
+    /**
+     * 处理手机号登录
+     */
+    private static void handlePhoneLogin(Context context, HWResult hwResult, CompletableFuture<Boolean> future) {
+        // 这里需要显示手机号输入对话框
+        // 由于PhoneDialog可能不存在,这里提供一个占位实现
+        // 实际使用时需要根据项目中的对话框实现进行调整
+        
+        // 示例:假设有一个PhoneDialog.show方法
+        // PhoneDialog.show(context, (phone, code) -> {
+        //     hwResult.setPhone(phone);
+        //     // 使用手机号和验证码登录
+        //     ApiOption option = new ApiOption();
+        //     option.setUrl("/member/hw/login");
+        //     java.util.Map<String, String> data = new java.util.HashMap<>();
+        //     data.put("phone", phone);
+        //     data.put("code", code);
+        //     data.put("openId", hwResult.getOpenId());
+        //     data.put("unionId", hwResult.getUnionId());
+        //     data.put("appId", config.appId);
+        //     option.setData(data);
+        //     
+        //     return api.post1(context, option).thenApply(result -> {
+        //         if (result != null && result.isSuccess() && result.getData() != null) {
+        //             LoginRes loginRes = (LoginRes) result.getData();
+        //             if (loginRes != null) {
+        //                 cache.setOpenId(context, hwResult.getOpenId());
+        //                 cache.setToken(context, loginRes.getToken());
+        //                 cache.setMobile(context, loginRes.getMobile());
+        //                 return true;
+        //             }
+        //         }
+        //         return false;
+        //     });
+        // });
+        
+        // 暂时返回false,需要根据实际项目中的PhoneDialog实现进行调整
+        future.complete(false);
+    }
+    
+    /**
+     * 获取华为账号信息
+     * @param context 上下文
+     * @return CompletableFuture<HWResult> 华为账号信息
+     */
+    public static CompletableFuture<HWResult> getHuaWeiAccount(Context context) {
+        CompletableFuture<HWResult> future = new CompletableFuture<>();
+        
+        try {
+            // 创建授权请求参数
+            AccountAuthParams accountAuthParams = new AccountAuthParamsHelper(
+                    AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
+                    .createParams();
+            
+            AccountAuthService accountAuthService;
+            try {
+                accountAuthService = AccountAuthManager.getService(accountAuthParams);
+            } catch (ApiException e) {
+                Log.error("Init Huawei accountAuthService FAILED: " + e.getStatusCode());
+                future.complete(new HWResult(false));
+                return future;
+            }
+            
+            if (accountAuthService == null) {
+                future.complete(new HWResult(false));
+                return future;
+            }
+            
+            // 先尝试静默登录
+            Task<AuthAccount> taskSilentSignIn = accountAuthService.silentSignIn();
+            taskSilentSignIn.addOnSuccessListener(new OnSuccessListener<AuthAccount>() {
+                @Override
+                public void onSuccess(AuthAccount authAccount) {
+                    HWResult result = new HWResult(true);
+                    result.setAppId(config.appId);
+                    result.setOpenId(authAccount.getOpenId());
+                    result.setUnionId(authAccount.getUnionId());
+                    // HMS SDK可能不直接提供手机号,需要单独申请权限
+                    result.setPhone("");
+                    future.complete(result);
+                }
+            });
+            
+            taskSilentSignIn.addOnFailureListener(new OnFailureListener() {
+                @Override
+                public void onFailure(Exception e) {
+                    if (e instanceof ApiException) {
+                        ApiException apiException = (ApiException) e;
+                        int statusCode = apiException.getStatusCode();
+                        
+                        // 静默登录失败,尝试前台登录
+                        if (statusCode == 8) { // 需要用户授权
+                            Task<AuthAccount> taskSignIn = accountAuthService.signIn();
+                            taskSignIn.addOnSuccessListener(new OnSuccessListener<AuthAccount>() {
+                                @Override
+                                public void onSuccess(AuthAccount authAccount) {
+                                    HWResult result = new HWResult(true);
+                                    result.setAppId(config.appId);
+                                    result.setOpenId(authAccount.getOpenId());
+                                    result.setUnionId(authAccount.getUnionId());
+                                    result.setPhone("");
+                                    future.complete(result);
+                                }
+                            });
+                            
+                            taskSignIn.addOnFailureListener(new OnFailureListener() {
+                                @Override
+                                public void onFailure(Exception e) {
+                                    handleAuthError(context, e, future);
+                                }
+                            });
+                        } else {
+                            handleAuthError(context, e, future);
+                        }
+                    } else {
+                        handleAuthError(context, e, future);
+                    }
+                }
+            });
+            
+        } catch (Exception e) {
+            handleAuthError(context, e, future);
+        }
+        
+        return future;
+    }
+    
+    /**
+     * 处理认证错误
+     */
+    private static void handleAuthError(Context context, Exception error, CompletableFuture<HWResult> future) {
+        if (error instanceof ApiException) {
+            ApiException apiException = (ApiException) error;
+            int code = apiException.getStatusCode();
+            
+            // 模拟器调试模式
+            if (code == 12300001 && config.isDebug) {
+                HWResult result = new HWResult(true);
+                result.setAppId(config.appId);
+                result.setOpenId("AAAjdc3utGbjvphuWASifWUoEpm1");
+                result.setUnionId("");
+                result.setPhone("");
+                future.complete(result);
+                return;
+            }
+            
+            // 用户取消
+            if (code == 1001502012) {
+                Toast.error(context, "已取消关联");
+                future.complete(new HWResult(false));
+                return;
+            }
+            
+            Toast.error(context, "关联失败: " + code + ", " + apiException.getMessage());
+            Log.error("Failed to auth. Code: " + code + ", message: " + apiException.getMessage());
+        } else {
+            Toast.error(context, "关联失败: " + error.getMessage());
+            Log.error(error);
+        }
+        
+        future.complete(new HWResult(false));
+    }
+}
+

+ 396 - 18
entry/src/main/java/com/fujica/abk/api/cache.java

@@ -1,47 +1,425 @@
 package com.fujica.abk.api;
 
+import com.fujica.abk.utils.Log;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import ohos.app.Context;
 import ohos.data.DatabaseHelper;
 import ohos.data.preferences.Preferences;
 
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 /**
  * 缓存工具类
  */
 public class cache {
-    private static final String PREF_NAME = "app_cache";
-    private static final String KEY_TOKEN = "token";
+    private static final String PREF_NAME = "fujicaV2";
+    
+    // 缓存键名
+    public static final String KEY_TOKEN = "token";
+    public static final String KEY_OPEN_ID = "open_id";
+    public static final String KEY_PARK_CACHE = "park_cache";
+    public static final String KEY_LATITUDE = "latitude";
+    public static final String KEY_LONGITUDE = "longitude";
+    public static final String KEY_LATITUDE_1 = "latitude_1";
+    public static final String KEY_LONGITUDE_1 = "longitude_1";
+    public static final String KEY_MOBILE = "mobile";
+    // 临时车牌
+    public static final String KEY_TMP_PLATE_NO = "tmp_plate_no";
+    // 选中车牌
+    public static final String KEY_PLATE_NO = "plate_no";
+    // 项目历史记录
+    public static final String KEY_PROJECT_HISTORY = "project_history";
+    // 全局选中项目
+    public static final String KEY_SELECTED_PROJECT = "selected_project";
+
+    private static final Gson gson = new Gson();
 
     /**
      * 获取Preferences实例
      */
-    private static Preferences getPreferences(Context context) {
-        DatabaseHelper databaseHelper = new DatabaseHelper(context.getApplicationContext());
-        return databaseHelper.getPreferences(PREF_NAME);
+    private static Preferences getPref(Context context) {
+        if (context == null) {
+            return null;
+        }
+        try {
+            DatabaseHelper databaseHelper = new DatabaseHelper(context.getApplicationContext());
+            return databaseHelper.getPreferences(PREF_NAME);
+        } catch (Exception e) {
+            Log.error(e);
+            return null;
+        }
+    }
+
+    /**
+     * 获取缓存值
+     */
+    public static String get(Context context, String key) {
+        try {
+            Preferences pref = getPref(context);
+            if (pref != null && pref.hasKey(key)) {
+                String val = pref.getString(key, "");
+                return val == null ? "" : val;
+            }
+            return "";
+        } catch (Exception e) {
+            Log.error(e);
+            return "";
+        }
+    }
+
+    /**
+     * 设置缓存值
+     */
+    public static void set(Context context, String key, String value) {
+        try {
+            Preferences pref = getPref(context);
+            if (pref != null) {
+                pref.putString(key, value);
+                pref.flushSync();
+            }
+        } catch (Exception e) {
+            Log.error(e);
+        }
+    }
+
+    /**
+     * 获取停车场缓存列表
+     */
+    public static List<Map<String, Object>> getParkCache(Context context) {
+        String json = get(context, KEY_PARK_CACHE);
+        if (json != null && !json.isEmpty()) {
+            try {
+                Type listType = new TypeToken<List<Map<String, Object>>>() {}.getType();
+                return gson.fromJson(json, listType);
+            } catch (Exception e) {
+                Log.error(e);
+            }
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * 设置停车场缓存列表
+     */
+    public static void setParkCache(Context context, List<Map<String, Object>> list) {
+        if (list == null) {
+            list = new ArrayList<>();
+        }
+        set(context, KEY_PARK_CACHE, gson.toJson(list));
+    }
+
+    /**
+     * 获取浮点数
+     */
+    public static float getFloat(Context context, String key, Float defaultVal) {
+        String val = get(context, key);
+        if (val == null || val.isEmpty()) {
+            return defaultVal != null ? defaultVal : 0f;
+        }
+        try {
+            return Float.parseFloat(val);
+        } catch (NumberFormatException e) {
+            Log.error(e);
+            return defaultVal != null ? defaultVal : 0f;
+        }
+    }
+
+    /**
+     * 获取纬度
+     */
+    public static float getLatitude(Context context) {
+        return getFloat(context, KEY_LATITUDE, 22.58475573142116f);
+    }
+
+    /**
+     * 获取经度
+     */
+    public static float getLongitude(Context context) {
+        return getFloat(context, KEY_LONGITUDE, 113.95887627473346f);
+    }
+
+    /**
+     * 设置纬度
+     */
+    public static void setLatitude(Context context, float value) {
+        set(context, KEY_LATITUDE, String.valueOf(value));
+    }
+
+    /**
+     * 设置经度
+     */
+    public static void setLongitude(Context context, float value) {
+        set(context, KEY_LONGITUDE, String.valueOf(value));
+    }
+
+    /**
+     * 获取纬度1
+     */
+    public static float getLatitude1(Context context) {
+        return getFloat(context, KEY_LATITUDE_1, 22.58475573142116f);
+    }
+
+    /**
+     * 获取经度1
+     */
+    public static float getLongitude1(Context context) {
+        return getFloat(context, KEY_LONGITUDE_1, 113.95887627473346f);
+    }
+
+    /**
+     * 设置纬度1
+     */
+    public static void setLatitude1(Context context, float value) {
+        set(context, KEY_LATITUDE_1, String.valueOf(value));
+    }
+
+    /**
+     * 设置经度1
+     */
+    public static void setLongitude1(Context context, float value) {
+        set(context, KEY_LONGITUDE_1, String.valueOf(value));
     }
 
     /**
      * 获取Token
      */
     public static String getToken(Context context) {
+        return get(context, KEY_TOKEN);
+    }
+
+    /**
+     * 设置Token
+     */
+    public static void setToken(Context context, String value) {
+        set(context, KEY_TOKEN, value);
+    }
+
+    /**
+     * 获取OpenId
+     */
+    public static String getOpenId(Context context) {
+        return get(context, KEY_OPEN_ID);
+    }
+
+    /**
+     * 设置OpenId
+     */
+    public static void setOpenId(Context context, String value) {
+        set(context, KEY_OPEN_ID, value);
+    }
+
+    /**
+     * 获取手机号
+     */
+    public static String getMobile(Context context) {
+        return get(context, KEY_MOBILE);
+    }
+
+    /**
+     * 设置手机号
+     */
+    public static void setMobile(Context context, String value) {
+        set(context, KEY_MOBILE, value);
+    }
+
+    /**
+     * 登出,清除相关缓存
+     */
+    public static void logout(Context context) {
+        try {
+            Preferences pref = getPref(context);
+            if (pref != null) {
+                pref.delete(KEY_TOKEN);
+                pref.delete(KEY_MOBILE);
+                pref.delete(KEY_OPEN_ID);
+                pref.flushSync();
+            }
+        } catch (Exception e) {
+            Log.error(e);
+        }
+    }
+
+    /**
+     * 判断是否已认证
+     */
+    public static boolean isAuth(Context context) {
+        String token = getToken(context);
+        return token != null && !token.isEmpty();
+    }
+
+    /**
+     * 获取临时车牌号
+     */
+    public static String getTmpPlateNo(Context context) {
+        return get(context, KEY_TMP_PLATE_NO);
+    }
+
+    /**
+     * 设置临时车牌号
+     */
+    public static void setTmpPlateNo(Context context, String value) {
+        set(context, KEY_TMP_PLATE_NO, value);
+    }
+
+    /**
+     * 获取车牌号
+     */
+    public static String getPlateNo(Context context) {
+        return get(context, KEY_PLATE_NO);
+    }
+
+    /**
+     * 设置车牌号
+     */
+    public static void setPlateNo(Context context, String value) {
+        set(context, KEY_PLATE_NO, value);
+    }
+
+    /**
+     * 获取项目历史记录
+     */
+    public static List<Map<String, Object>> getProjectHistory(Context context) {
+        String json = get(context, KEY_PROJECT_HISTORY);
+        if (json != null && !json.isEmpty()) {
+            try {
+                Type listType = new TypeToken<List<Map<String, Object>>>() {}.getType();
+                return gson.fromJson(json, listType);
+            } catch (Exception e) {
+                Log.error(e);
+            }
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * 添加项目历史记录(最多保存5个)
+     */
+    public static void addProjectHistory(Context context, Map<String, Object> project) {
+        List<Map<String, Object>> list = getProjectHistory(context);
+        
+        // 移除已存在的相同项目(根据 projectNo 判断)
+        if (project != null && project.containsKey("projectNo")) {
+            Object projectNo = project.get("projectNo");
+            List<Map<String, Object>> filteredList = new ArrayList<>();
+            for (Map<String, Object> item : list) {
+                if (item != null && !projectNo.equals(item.get("projectNo"))) {
+                    filteredList.add(item);
+                }
+            }
+            list = filteredList;
+        }
+        
+        // 将新项目添加到开头
+        if (project != null) {
+            list.add(0, project);
+        }
+        
+        // 最多保留5个
+        if (list.size() > 5) {
+            list = list.subList(0, 5);
+        }
+        
+        set(context, KEY_PROJECT_HISTORY, gson.toJson(list));
+    }
+
+    /**
+     * 清空项目历史记录
+     */
+    public static void clearProjectHistory(Context context) {
         try {
-            Preferences preferences = getPreferences(context);
+            Preferences pref = getPref(context);
+            if (pref != null) {
+                pref.delete(KEY_PROJECT_HISTORY);
+                pref.flushSync();
+            }
+        } catch (Exception e) {
+            Log.error(e);
+        }
+    }
+
+    /**
+     * 获取全局选中的项目
+     */
+    public static Map<String, Object> getSelectedProject(Context context) {
+        String json = get(context, KEY_SELECTED_PROJECT);
+        if (json != null && !json.isEmpty()) {
+            try {
+                Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
+                return gson.fromJson(json, mapType);
+            } catch (Exception e) {
+                Log.error(e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 设置全局选中的项目
+     */
+    public static void setSelectedProject(Context context, Map<String, Object> project) {
+        if (project != null) {
+            set(context, KEY_SELECTED_PROJECT, gson.toJson(project));
+        }
+    }
+
+    /**
+     * 清空全局选中的项目
+     */
+    public static void clearSelectedProject(Context context) {
+        try {
+            Preferences pref = getPref(context);
+            if (pref != null) {
+                pref.delete(KEY_SELECTED_PROJECT);
+                pref.flushSync();
+            }
+        } catch (Exception e) {
+            Log.error(e);
+        }
+    }
+
+    // ========== 以下为兼容旧代码的方法 ==========
+
+    /**
+     * 获取车牌号(兼容旧代码)
+     */
+    public static String getLicensePlate(Context context) {
+        return getPlateNo(context);
+    }
+
+    /**
+     * 保存车牌号(兼容旧代码)
+     */
+    public static void setLicensePlate(Context context, String licensePlate) {
+        setPlateNo(context, licensePlate);
+    }
+
+    /**
+     * 获取停车状态(是否正在停车)
+     */
+    public static boolean getParkingStatus(Context context) {
+        try {
+            Preferences preferences = getPref(context);
             if (preferences != null) {
-                return preferences.getString(KEY_TOKEN, "");
+                return preferences.getBoolean("parking_status", false);
             }
-            return "";
+            return false;
         } catch (Exception e) {
-            return "";
+            return false;
         }
     }
 
     /**
-     * 保存Token
+     * 保存停车状态
      */
-    public static void setToken(Context context, String token) {
+    public static void setParkingStatus(Context context, boolean isParking) {
         try {
-            Preferences preferences = getPreferences(context);
+            Preferences preferences = getPref(context);
             if (preferences != null) {
-                preferences.putString(KEY_TOKEN, token);
+                preferences.putBoolean("parking_status", isParking);
                 preferences.flushSync();
             }
         } catch (Exception e) {
@@ -50,13 +428,14 @@ public class cache {
     }
 
     /**
-     * 登出,清除Token
+     * 清除车牌相关缓存
      */
-    public static void logout(Context context) {
+    public static void clearLicensePlate(Context context) {
         try {
-            Preferences preferences = getPreferences(context);
+            Preferences preferences = getPref(context);
             if (preferences != null) {
-                preferences.delete(KEY_TOKEN);
+                preferences.delete(KEY_PLATE_NO);
+                preferences.delete("parking_status");
                 preferences.flushSync();
             }
         } catch (Exception e) {
@@ -64,4 +443,3 @@ public class cache {
         }
     }
 }
-

+ 10 - 0
entry/src/main/java/com/fujica/abk/api/config.java

@@ -0,0 +1,10 @@
+package com.fujica.abk.api;
+
+/**
+ * 配置类
+ */
+public class config {
+    public static String appId = "6917567451779658527"; // 需要替换为实际的appId
+    public static boolean isDebug = true; // 是否调试模式
+}
+

+ 1 - 1
entry/src/main/java/com/fujica/abk/utils/LoadingComponent.java

@@ -1,4 +1,4 @@
-package com.fujica.abk.utils;
+package com.fujica.abk.component;
 
 import com.fujica.abk.ResourceTable;
 import ohos.agp.animation.Animator;

+ 101 - 127
entry/src/main/java/com/fujica/abk/utils/ParkingItemComponent.java

@@ -1,7 +1,11 @@
-package com.fujica.abk.utils;
+package com.fujica.abk.component;
 
 import com.fujica.abk.ResourceTable;
 import com.fujica.abk.model.response.ParkNearRes;
+import com.fujica.abk.utils.Log;
+import com.fujica.abk.utils.R;
+import com.fujica.abk.utils.ScreenUtil;
+import com.fujica.abk.utils.api;
 import ohos.agp.colors.RgbColor;
 import ohos.agp.components.*;
 import ohos.agp.components.element.ShapeElement;
@@ -82,101 +86,43 @@ public class ParkingItemComponent extends DirectionalLayout {
      * 加载停车场数据(通过 parkId)
      */
     private void loadParkData() {
-        if (parkId == null || parkId.isEmpty()) {
-            Log.error("parkId 为空,无法加载数据");
-            return;
-        }
-
-        // 调用 API 获取停车场详情
-        String url = "/park/detail?parkId=" + parkId;
-        CompletableFuture<R<Object>> future = api.http(getContext(), url, "GET", null, null, null);
-        
-        future.thenAccept(response -> {
-            if (response == null || !response.isSuccess()) {
-                String errorMsg = response != null ? response.getMsg() : "请求失败";
-                Log.error("加载停车场数据失败: " + errorMsg);
-                return;
-            }
-
-            Object dataObj = response.getData();
-            if (dataObj == null) {
-                Log.error("响应数据为空");
-                return;
-            }
-
-            // 解析数据
-            ZSONObject parkObj;
-            if (dataObj instanceof ZSONObject) {
-                parkObj = (ZSONObject) dataObj;
-            } else {
-                parkObj = ZSONObject.stringToZSON(dataObj.toString());
-            }
-
-            if (parkData != null) {
-                // 在 UI 线程更新界面(使用 Component 的 postTask 方法)
-                new EventHandler(EventRunner.getMainEventRunner()).postTask(() -> {
-                    bindData();
-                }, 0);
-            }
-        });
-    }
-
-    /**
-     * 解析停车场数据
-     */
-    private ParkNearRes parseParkData(ZSONObject parkObj) {
-        try {
-            ParkNearRes park = new ParkNearRes();
-            if (parkObj.containsKey("parkId")) {
-                park.setParkId(parkObj.getString("parkId"));
-            }
-            if (parkObj.containsKey("parkName")) {
-                park.setParkName(parkObj.getString("parkName"));
-            }
-            if (parkObj.containsKey("isreserver")) {
-                park.setIsreserver(parkObj.getIntValue("isreserver"));
-            }
-            if (parkObj.containsKey("isfindcar")) {
-                park.setIsfindcar(parkObj.getIntValue("isfindcar"));
-            }
-            if (parkObj.containsKey("powerEnable")) {
-                park.setPowerEnable(parkObj.getIntValue("powerEnable"));
-            }
-            if (parkObj.containsKey("distance")) {
-                park.setDistance(parkObj.getDoubleValue("distance"));
-            }
-            if (parkObj.containsKey("address")) {
-                park.setAddress(parkObj.getString("address"));
-            }
-            if (parkObj.containsKey("totalPlace")) {
-                park.setTotalPlace(parkObj.getIntValue("totalPlace"));
-            }
-            if (parkObj.containsKey("residuePlace")) {
-                park.setResiduePlace(parkObj.getIntValue("residuePlace"));
-            }
-            if (parkObj.containsKey("latitude")) {
-                park.setLatitude(parkObj.getDoubleValue("latitude"));
-            }
-            if (parkObj.containsKey("longitude")) {
-                park.setLongitude(parkObj.getDoubleValue("longitude"));
-            }
-            if (parkObj.containsKey("onlinePayEnable")) {
-                park.setOnlinePayEnable(parkObj.getIntValue("onlinePayEnable"));
-            }
-            if (parkObj.containsKey("invoiceEnable")) {
-                park.setInvoiceEnable(parkObj.getIntValue("invoiceEnable"));
-            }
-            if (parkObj.containsKey("reductionEnable")) {
-                park.setReductionEnable(parkObj.getIntValue("reductionEnable"));
-            }
-            if (parkObj.containsKey("chargeInfo")) {
-                park.setChargeInfo(parkObj.getString("chargeInfo"));
-            }
-            return park;
-        } catch (Exception e) {
-            Log.error("解析停车场数据失败: " + e.getMessage());
-            return null;
-        }
+//        if (parkId == null || parkId.isEmpty()) {
+//            Log.error("parkId 为空,无法加载数据");
+//            return;
+//        }
+//
+//        // 调用 API 获取停车场详情
+//        String url = "/park/detail?parkId=" + parkId;
+//        CompletableFuture<R<Object>> future = api.http(getContext(), url, "GET", null, null, null);
+//
+//        future.thenAccept(response -> {
+//            if (response == null || !response.isSuccess()) {
+//                String errorMsg = response != null ? response.getMsg() : "请求失败";
+//                Log.error("加载停车场数据失败: " + errorMsg);
+//                return;
+//            }
+//
+//            Object dataObj = response.getData();
+//            if (dataObj == null) {
+//                Log.error("响应数据为空");
+//                return;
+//            }
+//
+//            // 解析数据
+//            ZSONObject parkObj;
+//            if (dataObj instanceof ZSONObject) {
+//                parkObj = (ZSONObject) dataObj;
+//            } else {
+//                parkObj = ZSONObject.stringToZSON(dataObj.toString());
+//            }
+//
+//            if (parkData != null) {
+//                // 在 UI 线程更新界面(使用 Component 的 postTask 方法)
+//                new EventHandler(EventRunner.getMainEventRunner()).postTask(() -> {
+//                    bindData();
+//                }, 0);
+//            }
+//        });
     }
 
     /**
@@ -195,13 +141,11 @@ public class ParkingItemComponent extends DirectionalLayout {
             }
 
             // 设置距离和地址
-            Text addressText = (Text) rootLayout.findComponentById(ResourceTable.Id_parking_address);
-            if (addressText != null) {
-                String distanceStr = parkData.getDistance() != null ?
-                        String.format("%.1fkm", parkData.getDistance() / 1000.0) : "0km";
-                String address = parkData.getAddress() != null ? parkData.getAddress() : "";
-                addressText.setText(distanceStr + " | " + address);
-            }
+            String distanceStr = parkData.getDistance() != null ?
+                    String.format("%.1fkm", parkData.getDistance() / 1000.0) : "0km";
+            String address = parkData.getAddress() != null ? parkData.getAddress() : "";
+            ((Text) rootLayout.findComponentById(ResourceTable.Id_parking_address_1)).setText(distanceStr);
+            ((Text) rootLayout.findComponentById(ResourceTable.Id_parking_address_2)).setText(" | " + address);
 
             // 设置总车位
             Text totalPlaceText = (Text) rootLayout.findComponentById(ResourceTable.Id_text_total_place);
@@ -216,26 +160,19 @@ public class ParkingItemComponent extends DirectionalLayout {
             }
 
             // 设置免费时长(从chargeInfo中解析,这里简化处理)
-            Text freeDurationText = (Text) rootLayout.findComponentById(ResourceTable.Id_text_free_duration);
-            if (freeDurationText != null) {
-                // 这里可以根据chargeInfo解析免费时长,暂时显示"15分"
-                freeDurationText.setText("15分");
-            }
+            ((Text) rootLayout.findComponentById(ResourceTable.Id_text_free_duration)).setText(parkData.getFreeTime() + "分");
 
             // 设置标签
-            DirectionalLayout tagsContainer = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_tags_container);
+            DirectionalLayout tagsContainer = rootLayout.findComponentById(ResourceTable.Id_tags_container);
             if (tagsContainer != null) {
                 tagsContainer.removeAllComponents();
 
                 // 根据数据添加标签
-                if (parkData.getIsreserver() != null && parkData.getIsreserver() == 1) {
-                    addTag(tagsContainer, "可预约", "#4CAF50");
+                if (parkData.getReservationEnable() != null && parkData.getReservationEnable() == 1) {
+                    addTag(tagsContainer, "可预约", "#f1f7ff", "#3286FB");
                 }
                 if (parkData.getPowerEnable() != null && parkData.getPowerEnable() == 1) {
-                    addTag(tagsContainer, "可充电", "#4CAF50");
-                }
-                if (parkData.getReductionEnable() != null && parkData.getReductionEnable() == 1) {
-                    addTag(tagsContainer, "惠", "#FF0000");
+                    addTag(tagsContainer, "可充电", "#f3fffd","#29C2AC");
                 }
             }
 
@@ -257,22 +194,22 @@ public class ParkingItemComponent extends DirectionalLayout {
     /**
      * 添加标签
      */
-    private void addTag(DirectionalLayout container, String text, String bgColor) {
+    private void addTag(DirectionalLayout container, String text, String bgColor, String textColor) {
         Text tag = new Text(getContext());
         tag.setText(text);
-        tag.setTextSize(11);
-        tag.setTextColor(Color.WHITE);
-        tag.setPadding(8, 4, 8, 4);
+        tag.setTextSize(ScreenUtil.fp2px(getContext(), 12));
+        tag.setTextColor(new Color(Color.getIntColor(textColor)));
+        tag.setPadding(ScreenUtil.vp2px(getContext(), 8), ScreenUtil.vp2px(getContext(), 4), 
+                ScreenUtil.vp2px(getContext(), 8), ScreenUtil.vp2px(getContext(), 4));
 
         // 创建圆角背景
         ShapeElement background = new ShapeElement();
         background.setShape(ShapeElement.RECTANGLE);
-        RgbColor rgbColor = new RgbColor(Color.getIntColor(bgColor));
-        background.setRgbColor(rgbColor);
-        background.setCornerRadius(12);
+        background.setRgbColor(parseColorToRgbColor(bgColor));
+        background.setCornerRadius(ScreenUtil.vp2px(getContext(), 12));
         tag.setBackground(background);
 
-        tag.setMarginLeft(4);
+        tag.setMarginLeft(ScreenUtil.vp2px(getContext(), 4));
         container.addComponent(tag);
     }
 
@@ -282,9 +219,8 @@ public class ParkingItemComponent extends DirectionalLayout {
     private ShapeElement createNormalBackground() {
         ShapeElement background = new ShapeElement();
         background.setShape(ShapeElement.RECTANGLE);
-        RgbColor normalColor = new RgbColor(Color.getIntColor("#FFFFFFFF"));
+        RgbColor normalColor = parseColorToRgbColor("#FFFFFFFF");
         background.setRgbColor(normalColor);
-        background.setCornerRadius(8);
         return background;
     }
 
@@ -294,9 +230,8 @@ public class ParkingItemComponent extends DirectionalLayout {
     private ShapeElement createSelectedBackground() {
         ShapeElement background = new ShapeElement();
         background.setShape(ShapeElement.RECTANGLE);
-        RgbColor selectedColor = new RgbColor(255, 236,230, 255);
+        RgbColor selectedColor = new RgbColor(255, 236, 230, 255);
         background.setRgbColor(selectedColor);
-        background.setCornerRadius(8);
         return background;
     }
 
@@ -331,5 +266,44 @@ public class ParkingItemComponent extends DirectionalLayout {
     public ParkNearRes getParkData() {
         return parkData;
     }
+
+    /**
+     * 将颜色字符串解析为 RgbColor
+     * 支持格式: #RGB, #RRGGBB, #AARRGGBB
+     */
+    private RgbColor parseColorToRgbColor(String colorStr) {
+        if (colorStr == null || colorStr.isEmpty()) {
+            return new RgbColor(255, 255, 255, 255); // 默认白色
+        }
+
+        // 移除 # 号
+        String color = colorStr.startsWith("#") ? colorStr.substring(1) : colorStr;
+
+        int alpha = 255;
+        int red, green, blue;
+
+        if (color.length() == 3) {
+            // #RGB 格式,每个字符重复一次
+            red = Integer.parseInt(color.substring(0, 1) + color.substring(0, 1), 16);
+            green = Integer.parseInt(color.substring(1, 2) + color.substring(1, 2), 16);
+            blue = Integer.parseInt(color.substring(2, 3) + color.substring(2, 3), 16);
+        } else if (color.length() == 6) {
+            // #RRGGBB 格式
+            red = Integer.parseInt(color.substring(0, 2), 16);
+            green = Integer.parseInt(color.substring(2, 4), 16);
+            blue = Integer.parseInt(color.substring(4, 6), 16);
+        } else if (color.length() == 8) {
+            // #AARRGGBB 格式
+            alpha = Integer.parseInt(color.substring(0, 2), 16);
+            red = Integer.parseInt(color.substring(2, 4), 16);
+            green = Integer.parseInt(color.substring(4, 6), 16);
+            blue = Integer.parseInt(color.substring(6, 8), 16);
+        } else {
+            // 无效格式,返回默认白色
+            return new RgbColor(255, 255, 255, 255);
+        }
+
+        return new RgbColor(red, green, blue, alpha);
+    }
 }
 

+ 475 - 0
entry/src/main/java/com/fujica/abk/component/nav/FindParkingPageComponent.java

@@ -0,0 +1,475 @@
+package com.fujica.abk.component.nav;
+
+import com.fujica.abk.ResourceTable;
+import com.fujica.abk.component.LoadingComponent;
+import com.fujica.abk.component.ParkingItemComponent;
+import com.fujica.abk.model.response.ParkNearRes;
+import com.fujica.abk.model.response.Page;
+import com.fujica.abk.utils.DialogUtil;
+import com.fujica.abk.utils.Log;
+import com.fujica.abk.utils.R;
+import com.fujica.abk.utils.api;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import ohos.agp.components.*;
+import ohos.agp.window.dialog.ListDialog;
+import ohos.app.Context;
+import ohos.eventhandler.EventHandler;
+import ohos.eventhandler.EventRunner;
+import ohos.location.Location;
+
+import java.lang.reflect.Type;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 找车位页面组件
+ */
+public class FindParkingPageComponent extends DirectionalLayout {
+    // 页面组件
+    private Component rootLayout;
+    private TextField inputParkName; // 车场名称输入框
+    private DirectionalLayout btnDistanceFilter; // 距离筛选按钮
+    private DirectionalLayout btnDistanceSort; // 排序方式按钮
+    private ScrollView parkingListScroll; // 停车场列表滚动视图
+    private DirectionalLayout parkingListContainer; // 停车场列表容器
+
+    // 筛选和排序参数
+    private int selectedDistance = 3000; // 选中的距离:500, 1000, 3000(默认3km)
+    private int selectedFilter = 2; // 选中的排序:1=车位最多, 2=距离最近, 3=免费时长最长(默认距离最近)
+    private int filterType = 2; // 筛选类型:2=全部,1=推荐
+
+    // 分页相关
+    private int currentPage = 1; // 当前页码
+    private int pageSize = 20; // 每页数量
+    private boolean isLoading = false; // 是否正在加载
+    private boolean hasMore = true; // 是否还有更多数据
+    private long lastLoadTime = 0; // 上次加载时间,用于防抖
+    private static final long LOAD_THROTTLE_MS = 500; // 防抖时间间隔(毫秒)
+
+    // 数据
+    private List<ParkNearRes> parkingList = new ArrayList<>(); // 停车场列表数据
+    private ParkingItemComponent selectedParkingItem = null; // 当前选中的停车场列表项
+    private EventHandler searchHandler; // 搜索防抖Handler
+
+    // 外部依赖
+    private Context context;
+    private Location currentLocation; // 当前定位坐标
+    private LoadingComponent loadingComponent; // Loading组件
+
+    /**
+     * 构造函数
+     */
+    public FindParkingPageComponent(Context context) {
+        super(context);
+        this.context = context;
+        initComponent(context);
+    }
+
+    /**
+     * 初始化组件
+     */
+    private void initComponent(Context context) {
+        // 设置布局属性
+        setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setOrientation(VERTICAL);
+
+        // 加载布局文件
+        rootLayout = LayoutScatter.getInstance(context)
+                .parse(ResourceTable.Layout_layout_find_parking, null, false);
+        addComponent(rootLayout);
+
+        // 初始化组件引用
+        initViews();
+
+        // 设置事件监听
+        setupListeners();
+
+        // 默认选中全部车场
+        switchTab(2);
+    }
+
+    /**
+     * 初始化视图组件
+     */
+    private void initViews() {
+        inputParkName = (TextField) rootLayout.findComponentById(ResourceTable.Id_input_park_name);
+        btnDistanceFilter = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_btn_distance_filter);
+        btnDistanceSort = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_btn_distance_sort);
+        parkingListScroll = (ScrollView) rootLayout.findComponentById(ResourceTable.Id_parking_list_scroll);
+        parkingListContainer = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_parking_list_container);
+    }
+
+    /**
+     * 设置事件监听
+     */
+    private void setupListeners() {
+        // 设置距离筛选下拉框点击事件
+        if (btnDistanceFilter != null) {
+            btnDistanceFilter.setClickedListener(component -> showDistanceFilterDialog());
+        }
+
+        // 设置排序方式下拉框点击事件
+        if (btnDistanceSort != null) {
+            btnDistanceSort.setClickedListener(component -> showSortFilterDialog());
+        }
+
+        // 设置车场名称输入框值改变监听器(带防抖)
+        if (inputParkName != null) {
+            // 创建用于防抖的Handler
+            searchHandler = new EventHandler(EventRunner.getMainEventRunner());
+            
+            inputParkName.addTextObserver(new Text.TextObserver() {
+                @Override
+                public void onTextUpdated(String s, int i, int i1, int i2) {
+                    // 移除之前的搜索任务
+                    searchHandler.removeAllEvent();
+                    
+                    // 延迟执行查询,实现防抖效果
+                    searchHandler.postTask(() -> {
+                        // 重新加载数据
+                        switchTab(filterType);
+                    }, LOAD_THROTTLE_MS);
+                }
+            });
+        }
+
+        // 设置滚动监听,实现分页加载
+        if (parkingListScroll != null) {
+            parkingListScroll.setReboundEffect(false);
+            // 监听滚动到底部
+            parkingListScroll.addScrolledListener(new Component.ScrolledListener() {
+                @Override
+                public void onContentScrolled(Component component, int x, int y, int oldX, int oldY) {
+                    // 防抖:避免频繁触发
+                    long currentTime = System.currentTimeMillis();
+                    if (currentTime - lastLoadTime < LOAD_THROTTLE_MS) {
+                        return;
+                    }
+
+                    // 如果正在加载或没有更多数据,直接返回
+                    if (isLoading || !hasMore) {
+                        return;
+                    }
+
+                    // 计算是否滚动到底部
+                    int scrollY = parkingListScroll.getScrollValue(1);
+                    int viewHeight = parkingListScroll.getHeight();
+
+                    // 获取内容高度(使用容器的高度)
+                    int contentHeight = 0;
+                    if (parkingListContainer != null) {
+                        contentHeight = parkingListContainer.getHeight();
+                    }
+
+                    // 如果容器高度为0,尝试使用EstimatedHeight
+                    if (contentHeight == 0) {
+                        contentHeight = parkingListScroll.getEstimatedHeight();
+                    }
+
+                    // 如果内容高度或视图高度为0,无法计算,直接返回
+                    if (contentHeight == 0 || viewHeight == 0) {
+                        return;
+                    }
+
+                    // 计算剩余滚动距离
+                    int remainingDistance = contentHeight - scrollY - viewHeight;
+
+                    // 计算阈值(50像素,约等于50vp),当剩余距离小于等于阈值时触发加载
+                    int threshold = 50;
+
+                    // 当滚动到底部(剩余距离小于等于阈值)时,触发加载
+                    if (remainingDistance <= threshold && remainingDistance >= 0) {
+                        lastLoadTime = currentTime;
+                        // 加载下一页
+                        loadParkingData(false);
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * 切换标签页
+     */
+    private void switchTab(int filter) {
+        filterType = filter;
+        currentPage = 1;
+        hasMore = true;
+        lastLoadTime = 0; // 重置防抖时间
+        parkingList.clear();
+        if (parkingListContainer != null) {
+            parkingListContainer.removeAllComponents();
+        }
+        // 清除选中状态
+        selectedParkingItem = null;
+
+        // 加载数据
+        loadParkingData(true);
+    }
+
+    /**
+     * 显示距离筛选下拉对话框
+     */
+    private void showDistanceFilterDialog() {
+        String[] options = {"500m", "1km", "3km"};
+        int[] values = {500, 1000, 3000};
+        
+        ListDialog listDialog = DialogUtil.createListDialog(context, options, (iDialog, index) -> {
+            selectedDistance = values[index];
+            if (btnDistanceFilter != null && btnDistanceFilter.getChildCount() > 0) {
+                Component textComponent = btnDistanceFilter.getComponentAt(0);
+                if (textComponent instanceof Text) {
+                    ((Text) textComponent).setText(options[index]);
+                }
+            }
+            // 重新加载数据
+            switchTab(filterType);
+            iDialog.destroy();
+        });
+        listDialog.show();
+    }
+
+    /**
+     * 显示排序方式下拉对话框
+     */
+    private void showSortFilterDialog() {
+        String[] options = {"车位最多", "距离最近", "免费时长最长"};
+        int[] values = {1, 2, 3};
+        
+        ListDialog listDialog = DialogUtil.createListDialog(context, options, (iDialog, index) -> {
+            selectedFilter = values[index];
+            if (btnDistanceSort != null && btnDistanceSort.getChildCount() > 0) {
+                Component textComponent = btnDistanceSort.getComponentAt(0);
+                if (textComponent instanceof Text) {
+                    ((Text) textComponent).setText(options[index]);
+                }
+            }
+            // 重新加载数据
+            switchTab(filterType);
+            iDialog.destroy();
+        });
+        listDialog.show();
+    }
+
+    /**
+     * 加载停车场数据
+     */
+    private void loadParkingData(boolean isRefresh) {
+        if (isLoading) {
+            return;
+        }
+
+        if (isRefresh) {
+            currentPage = 1;
+            hasMore = true;
+            lastLoadTime = 0; // 重置防抖时间
+            parkingList.clear();
+            if (parkingListContainer != null) {
+                parkingListContainer.removeAllComponents();
+            }
+        }
+
+        if (!hasMore) {
+            return;
+        }
+
+        // 锁定当前页码,避免并发问题
+        final int requestPage = currentPage;
+        isLoading = true;
+
+        // 获取定位坐标
+        double latitude = 0;
+        double longitude = 0;
+        if (currentLocation != null) {
+            latitude = currentLocation.getLatitude();
+            longitude = currentLocation.getLongitude();
+        }
+
+        // 获取车场名称输入框的值
+        String parkName = "";
+        if (inputParkName != null) {
+            String inputText = inputParkName.getText();
+            if (inputText != null && !inputText.trim().isEmpty()) {
+                try {
+                    parkName = URLEncoder.encode(inputText.trim(), "UTF-8");
+                } catch (Exception e) {
+                    parkName = inputText.trim();
+                }
+            }
+        }
+
+        // 构建请求URL(使用锁定的页码)
+        String url = String.format("/park/near/page?type=%d&filter=%d&latitude=%f&longitude=%f&current=%d&size=%d&parkName=%s",
+                filterType, selectedFilter, latitude, longitude, requestPage, pageSize, parkName);
+
+        // 发送请求(网络请求已在后台线程)
+        CompletableFuture<R<Page<ParkNearRes>>> future = api.http(context, url, "GET", null, null, null, new TypeToken<Page<ParkNearRes>>(){});
+        if (loadingComponent != null) {
+            loadingComponent.show();
+        }
+        future.thenAccept(response -> {
+            // 在后台线程解析数据,避免阻塞UI
+            try {
+                if (response == null || !response.isSuccess()) {
+                    String errorMsg = response != null ? response.getMsg() : "请求失败";
+                    Log.error("加载停车场数据失败: " + errorMsg);
+                    return;
+                }
+
+                // 解析响应数据(在后台线程)
+                Object dataObj = response.getData();
+                Page<ParkNearRes> page = null;
+                if (dataObj != null) {
+                    Gson gson = new Gson();
+                    Type pageType = new TypeToken<Page<ParkNearRes>>(){}.getType();
+                    String dataJson = gson.toJson(dataObj);
+                    page = gson.fromJson(dataJson, pageType);
+                }
+                if (page == null) {
+                    Log.error("响应数据为空");
+                    return;
+                }
+
+                // 解析Page对象(在后台线程)
+                if (page == null || page.getRecords() == null) {
+                    Log.error("解析分页数据失败");
+                    return;
+                }
+
+                List<ParkNearRes> records = page.getRecords();
+                if (records.isEmpty()) {
+                    hasMore = false;
+                    return;
+                }
+
+                // 更新分页信息(在后台线程计算)
+                boolean hasMoreData = true;
+                int nextPage = requestPage + 1;
+                if (page.getCurrent() != null && page.getPages() != null) {
+                    int serverCurrent = page.getCurrent();
+                    int totalPages = page.getPages();
+                    if (serverCurrent >= totalPages) {
+                        hasMoreData = false;
+                    } else {
+                        // 使用服务器返回的current值+1作为下一页
+                        nextPage = serverCurrent + 1;
+                    }
+                } else {
+                    if (records.size() < pageSize) {
+                        hasMoreData = false;
+                    }
+                }
+
+                // 保存最终的分页信息
+                final boolean finalHasMore = hasMoreData;
+                final int finalNextPage = nextPage;
+                final List<ParkNearRes> finalRecords = records;
+
+                // 只在UI线程更新界面
+                new EventHandler(EventRunner.getMainEventRunner()).postTask(() -> {
+                    // 检查currentPage是否已经被其他请求更新(防止旧请求覆盖新数据)
+                    if (currentPage > requestPage) {
+                        Log.info("忽略过期请求,当前页码: " + currentPage + ", 请求页码: " + requestPage);
+                        return;
+                    }
+
+                    // 添加到列表
+                    parkingList.addAll(finalRecords);
+
+                    // 批量渲染列表项(减少UI更新次数,延迟批量添加)
+                    if (parkingListContainer != null && !finalRecords.isEmpty()) {
+                        // 先批量创建所有组件
+                        List<Component> items = new ArrayList<>();
+                        for (ParkNearRes park : finalRecords) {
+                            Component item = createParkingItem(park);
+                            if (item != null) {
+                                items.add(item);
+                            }
+                        }
+
+                        // 批量添加到容器(减少UI重绘次数)
+                        for (Component item : items) {
+                            parkingListContainer.addComponent(item);
+                        }
+                    }
+
+                    // 更新分页信息
+                    hasMore = finalHasMore;
+                    if (finalHasMore) {
+                        currentPage = finalNextPage;
+                    }
+                });
+
+            } catch (Exception e) {
+                Log.error("解析停车场数据失败: " + e.getMessage());
+                e.printStackTrace();
+            } finally {
+                isLoading = false;
+                if (loadingComponent != null) {
+                    loadingComponent.hide();
+                }
+            }
+        });
+    }
+
+    /**
+     * 创建停车场列表项组件(不添加到容器)
+     */
+    private Component createParkingItem(ParkNearRes park) {
+        if (parkingListContainer == null) {
+            return null;
+        }
+
+        try {
+            // 使用 ParkingItemComponent 组件
+            ParkingItemComponent item = new ParkingItemComponent(context, park);
+            
+            // 设置选中监听器,实现全局选中状态管理
+            item.setOnItemSelectedListener((component, parkData) -> {
+                // 如果之前有选中的项,取消其选中状态
+                if (selectedParkingItem != null && selectedParkingItem != component) {
+                    selectedParkingItem.setSelected(false);
+                }
+                // 更新当前选中的项
+                selectedParkingItem = component;
+            });
+
+            return item;
+
+        } catch (Exception e) {
+            Log.error("创建停车场列表项失败: " + e.getMessage());
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 设置当前定位坐标
+     */
+    public void setCurrentLocation(Location location) {
+        this.currentLocation = location;
+        // 如果已有定位,重新加载数据
+        if (location != null) {
+            loadParkingData(true);
+        }
+    }
+
+    /**
+     * 设置Loading组件
+     */
+    public void setLoadingComponent(LoadingComponent loadingComponent) {
+        this.loadingComponent = loadingComponent;
+    }
+
+    /**
+     * 刷新数据
+     */
+    public void refresh() {
+        loadParkingData(true);
+    }
+}
+

+ 222 - 0
entry/src/main/java/com/fujica/abk/component/nav/MyPageComponent.java

@@ -0,0 +1,222 @@
+package com.fujica.abk.component.nav;
+
+import com.fujica.abk.ResourceTable;
+import com.fujica.abk.api.cache;
+import com.fujica.abk.utils.LicensePlateInputDialog;
+import com.fujica.abk.utils.R;
+import com.fujica.abk.utils.api;
+import ohos.agp.components.*;
+import ohos.agp.components.ComponentContainer;
+import ohos.agp.components.DirectionalLayout;
+import ohos.agp.components.LayoutScatter;
+import ohos.app.Context;
+import ohos.eventhandler.EventHandler;
+import ohos.eventhandler.EventRunner;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 我的页面组件
+ */
+public class MyPageComponent extends DirectionalLayout {
+    private Component rootLayout;
+    private Context context;
+
+    // 有车牌缓存时的UI组件
+    private DirectionalLayout parkingInfoCard;
+    private Text textLicensePlate;
+    private Text textParkingDuration;
+    private Text textTotalFee;
+    private Button btnPayNow;
+
+    // 无车牌缓存时的UI组件
+    private DirectionalLayout addVehicleCard;
+    private Button btnInputLicensePlate;
+
+    /**
+     * 构造函数
+     */
+    public MyPageComponent(Context context) {
+        super(context);
+        this.context = context;
+        initComponent(context);
+
+        LicensePlateInputDialog licensePlateInputDialog = new LicensePlateInputDialog(context);
+        licensePlateInputDialog.setOnConfirmListener(licensePlate -> {
+            // 确认后保存车牌并查询计费
+            simulateLicensePlateInput(licensePlate);
+        });
+//        licensePlateInputDialog.show(); //测试
+    }
+
+    /**
+     * 初始化组件
+     */
+    private void initComponent(Context context) {
+        // 设置布局属性
+        setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setOrientation(VERTICAL);
+
+        // 加载布局文件
+        rootLayout = LayoutScatter.getInstance(context)
+                .parse(ResourceTable.Layout_layout_my, null, false);
+        addComponent(rootLayout);
+
+        // 初始化UI组件
+        initViews();
+
+        // 设置事件监听
+        setupListeners();
+
+        // 根据缓存状态显示不同UI
+        checkCacheAndUpdateUI();
+    }
+
+    /**
+     * 初始化视图组件
+     */
+    private void initViews() {
+        // 有车牌缓存时的UI组件
+        parkingInfoCard = rootLayout.findComponentById(ResourceTable.Id_parking_info_card);
+        textLicensePlate = rootLayout.findComponentById(ResourceTable.Id_text_license_plate);
+        textParkingDuration = rootLayout.findComponentById(ResourceTable.Id_text_parking_duration);
+        textTotalFee = rootLayout.findComponentById(ResourceTable.Id_text_total_fee);
+        btnPayNow = rootLayout.findComponentById(ResourceTable.Id_btn_pay_now);
+
+        // 无车牌缓存时的UI组件
+        addVehicleCard = rootLayout.findComponentById(ResourceTable.Id_add_vehicle_card);
+        btnInputLicensePlate = rootLayout.findComponentById(ResourceTable.Id_btn_input_license_plate);
+    }
+
+    /**
+     * 设置事件监听
+     */
+    private void setupListeners() {
+        // 输入车牌缴费按钮点击事件
+        if (btnInputLicensePlate != null) {
+            btnInputLicensePlate.setClickedListener(component -> {
+                LicensePlateInputDialog licensePlateInputDialog = new LicensePlateInputDialog(context);
+                licensePlateInputDialog.setOnConfirmListener(licensePlate -> {
+                    // 确认后保存车牌并查询计费
+                    simulateLicensePlateInput(licensePlate);
+                });
+                licensePlateInputDialog.show();
+            });
+        }
+
+        // 立即缴费按钮点击事件
+        if (btnPayNow != null) {
+            btnPayNow.setClickedListener(component -> {
+                // TODO: 实现缴费逻辑
+            });
+        }
+    }
+
+    /**
+     * 检查缓存并更新UI
+     */
+    private void checkCacheAndUpdateUI() {
+        String licensePlate = cache.getLicensePlate(context);
+        boolean isParking = cache.getParkingStatus(context);
+
+        if (licensePlate != null && !licensePlate.isEmpty() && isParking) {
+            // 有缓存,显示停车信息卡片
+            showParkingInfoCard();
+            // 直接查询计费
+            queryParkingFee(licensePlate);
+        } else {
+            // 无缓存,显示添加车辆卡片
+            showAddVehicleCard();
+        }
+    }
+
+    /**
+     * 显示停车信息卡片
+     */
+    private void showParkingInfoCard() {
+        if (parkingInfoCard != null) {
+            parkingInfoCard.setVisibility(VISIBLE);
+        }
+        if (addVehicleCard != null) {
+            addVehicleCard.setVisibility(HIDE);
+        }
+    }
+
+    /**
+     * 显示添加车辆卡片
+     */
+    private void showAddVehicleCard() {
+        if (parkingInfoCard != null) {
+            parkingInfoCard.setVisibility(HIDE);
+        }
+        if (addVehicleCard != null) {
+            addVehicleCard.setVisibility(VISIBLE);
+        }
+    }
+
+    /**
+     * 模拟车牌输入(后续会被实际输入逻辑替换)
+     */
+    private void simulateLicensePlateInput(String licensePlate) {
+        // 保存车牌到缓存
+        cache.setLicensePlate(context, licensePlate);
+        cache.setParkingStatus(context, true);
+
+        // 更新UI
+        showParkingInfoCard();
+
+        // 查询计费
+        queryParkingFee(licensePlate);
+    }
+
+    /**
+     * 查询停车费用
+     */
+    private void queryParkingFee(String licensePlate) {
+        CompletableFuture<R<api.ParkingFeeInfo>> future = api.queryParkingFee(context, licensePlate);
+        future.thenAccept(result -> {
+            // 在主线程更新UI
+            EventRunner mainRunner = EventRunner.getMainEventRunner();
+            if (mainRunner != null) {
+                EventHandler mainHandler = new EventHandler(mainRunner);
+                mainHandler.postTask(() -> {
+                    if (result != null && result.isSuccess() && result.getData() != null) {
+                        api.ParkingFeeInfo feeInfo = result.getData();
+                        updateParkingInfo(feeInfo);
+                    }
+                });
+            }
+        });
+    }
+
+    /**
+     * 更新停车信息显示
+     */
+    private void updateParkingInfo(api.ParkingFeeInfo feeInfo) {
+        if (textLicensePlate != null && feeInfo.getLicensePlate() != null) {
+            textLicensePlate.setText(feeInfo.getLicensePlate());
+        }
+
+        if (textParkingDuration != null) {
+            String duration = String.format("已停%d天%d小时%d分",
+                    feeInfo.getParkingDays(),
+                    feeInfo.getParkingHours(),
+                    feeInfo.getParkingMinutes());
+            textParkingDuration.setText(duration);
+        }
+
+        if (textTotalFee != null) {
+            textTotalFee.setText("¥" + feeInfo.getTotalFee());
+        }
+    }
+
+    /**
+     * 刷新页面数据
+     * 当页面切换过来时调用,重新检查缓存并更新UI
+     */
+    public void refresh() {
+        checkCacheAndUpdateUI();
+    }
+}
+

+ 39 - 0
entry/src/main/java/com/fujica/abk/component/nav/ReserveParkingPageComponent.java

@@ -0,0 +1,39 @@
+package com.fujica.abk.component.nav;
+
+import com.fujica.abk.ResourceTable;
+import ohos.agp.components.Component;
+import ohos.agp.components.ComponentContainer;
+import ohos.agp.components.DirectionalLayout;
+import ohos.agp.components.LayoutScatter;
+import ohos.app.Context;
+
+/**
+ * 预约停车页面组件
+ */
+public class ReserveParkingPageComponent extends DirectionalLayout {
+    private Component rootLayout;
+
+    /**
+     * 构造函数
+     */
+    public ReserveParkingPageComponent(Context context) {
+        super(context);
+        initComponent(context);
+    }
+
+    /**
+     * 初始化组件
+     */
+    private void initComponent(Context context) {
+        // 设置布局属性
+        setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setOrientation(VERTICAL);
+
+        // 加载布局文件
+        rootLayout = LayoutScatter.getInstance(context)
+                .parse(ResourceTable.Layout_layout_reserve_parking, null, false);
+        addComponent(rootLayout);
+    }
+}
+

+ 35 - 0
entry/src/main/java/com/fujica/abk/model/response/LoginRes.java

@@ -0,0 +1,35 @@
+package com.fujica.abk.model.response;
+
+/**
+ * 登录响应数据
+ */
+public class LoginRes {
+    private String token;
+    private String openId;
+    private String mobile;
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
+    public String getMobile() {
+        return mobile;
+    }
+
+    public void setMobile(String mobile) {
+        this.mobile = mobile;
+    }
+}
+

+ 17 - 5
entry/src/main/java/com/fujica/abk/model/response/ParkNearRes.java

@@ -6,10 +6,14 @@ package com.fujica.abk.model.response;
 public class ParkNearRes {
     private String parkId;
     private String parkName;
+    /**
+     * 免费时长
+     */
+    private String freeTime;
     /**
      * 预约车位
      */
-    private Integer isreserver;
+    private Integer reservationEnable;
     /**
      * 支持找车
      */
@@ -42,12 +46,20 @@ public class ParkNearRes {
         this.parkName = parkName;
     }
 
-    public Integer getIsreserver() {
-        return isreserver;
+    public String getFreeTime() {
+        return freeTime;
+    }
+
+    public void setFreeTime(String freeTime) {
+        this.freeTime = freeTime;
+    }
+
+    public Integer getReservationEnable() {
+        return reservationEnable;
     }
 
-    public void setIsreserver(Integer isreserver) {
-        this.isreserver = isreserver;
+    public void setReservationEnable(Integer reservationEnable) {
+        this.reservationEnable = reservationEnable;
     }
 
     public Integer getIsfindcar() {

+ 0 - 5
entry/src/main/java/com/fujica/abk/slice/MainAbilitySlice copy.java

@@ -101,11 +101,6 @@
 //         cache.setToken(getContext(), "sdfdsfdsf11111111111");
 //         String token = cache.getToken(getContext());
 
-// //        api.http(getContext(), "http://www.baidu.com", "GET", null, null, null);
-
-//         api.http(getContext(), "/park/near/page?longitude=0&latitude=0", "GET", null, null, null);
-
-
 //         // 设置全屏显示
 //         setFullScreen();
 

+ 48 - 475
entry/src/main/java/com/fujica/abk/slice/MainAbilitySlice.java

@@ -1,8 +1,13 @@
 package com.fujica.abk.slice;
 
 import com.fujica.abk.ResourceTable;
+import com.fujica.abk.api.auth;
 import com.fujica.abk.api.cache;
+import com.fujica.abk.component.LoadingComponent;
 import com.fujica.abk.utils.*;
+import com.fujica.abk.component.nav.FindParkingPageComponent;
+import com.fujica.abk.component.nav.MyPageComponent;
+import com.fujica.abk.component.nav.ReserveParkingPageComponent;
 import com.huawei.hms.accountsdk.constant.CommonConstant;
 import com.huawei.hms.accountsdk.exception.ApiException;
 import com.huawei.hms.accountsdk.support.account.AccountAuthManager;
@@ -18,8 +23,6 @@ import ohos.aafwk.ability.DataAbilityHelper;
 import ohos.aafwk.ability.IDataAbilityObserver;
 import ohos.aafwk.content.Intent;
 import ohos.agp.components.*;
-import ohos.agp.components.element.ShapeElement;
-import ohos.agp.colors.RgbColor;
 import ohos.agp.utils.Color;
 import ohos.agp.window.dialog.ToastDialog;
 import ohos.agp.window.service.Window;
@@ -30,9 +33,6 @@ import ohos.location.LocatorCallback;
 import ohos.location.RequestParam;
 import ohos.rpc.RemoteException;
 import ohos.sysappcomponents.settings.SystemSettings;
-import ohos.utils.zson.ZSONObject;
-import com.fujica.abk.model.response.ParkNearRes;
-import com.fujica.abk.model.response.Page;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -68,24 +68,9 @@ public class MainAbilitySlice extends AbilitySlice {
     private LocatorCallback locatorCallback;
     private Location currentLocation; // 当前定位坐标
 
-    // 找车位页面相关
-    private Component findParkingPage; // 找车位页面组件
-    private Text tabAll; // 全部车场标签
-    private Text tabRecommended; // 推荐车场标签
-    private Component tabAllUnderline; // 全部车场下划线
-    private Component tabRecommendedUnderline; // 推荐车场下划线
-    private Button btnDistanceSort; // 距离最近按钮
-    private ScrollView parkingListScroll; // 停车场列表滚动视图
-    private DirectionalLayout parkingListContainer; // 停车场列表容器
-    private int currentPage = 1; // 当前页码
-    private int pageSize = 20; // 每页数量
-    private boolean isLoading = false; // 是否正在加载
-    private boolean hasMore = true; // 是否还有更多数据
-    private int filterType = 2; // 筛选类型:2=全部,1=推荐
-    private List<ParkNearRes> parkingList = new ArrayList<>(); // 停车场列表数据
-    private long lastLoadTime = 0; // 上次加载时间,用于防抖
-    private static final long LOAD_THROTTLE_MS = 500; // 防抖时间间隔(毫秒)
-    private ParkingItemComponent selectedParkingItem = null; // 当前选中的停车场列表项
+    // 页面组件
+    private MyPageComponent myPageComponent;
+    private FindParkingPageComponent findParkingPageComponent; // 找车位页面组件
 
     DataAbilityHelper dataAbilityHelper;
     IDataAbilityObserver dataAbilityObserver;
@@ -103,10 +88,6 @@ public class MainAbilitySlice extends AbilitySlice {
             Log.info(appId);
         } catch (RemoteException e) {
         }
-        cache.setToken(getContext(), "sdfdsfdsf11111111111");
-        String token = cache.getToken(getContext());
-
-//        api.http(getContext(), "http://www.baidu.com", "GET", null, null, null);
 
         // 设置全屏显示
         setFullScreen();
@@ -142,6 +123,21 @@ public class MainAbilitySlice extends AbilitySlice {
         dataAbilityHelper.registerObserver(SystemSettings.getUri(key), dataAbilityObserver);
         String timeFormat1 = SystemSettings.getValue(dataAbilityHelper, "car_license_plate_number");
         String timeFormat = SystemSettings.getValue(dataAbilityHelper, key);
+
+        // 测试 - 异步登录处理
+        auth.login(this).thenAccept(success -> {
+            if (success) {
+                Log.info("登录成功");
+                // 登录成功后的处理逻辑
+            } else {
+                Log.error("登录失败");
+                // 登录失败后的处理逻辑
+            }
+        }).exceptionally(e -> {
+            Log.error("登录异常: " + e.getMessage());
+            e.printStackTrace();
+            return null;
+        });
     }
 
     void setTimeFormat(String timeFormat) {
@@ -255,7 +251,8 @@ public class MainAbilitySlice extends AbilitySlice {
      */
     private void initComponents() {
         // 初始化PageSlider
-        pageSlider = (PageSlider) findComponentById(ResourceTable.Id_page_slider);
+        pageSlider = findComponentById(ResourceTable.Id_page_slider);
+        pageSlider.setSlidingPossible(false);
         if (pageSlider != null) {
             // 创建PageSliderProvider
             pageSliderProvider = new PageSliderProvider() {
@@ -272,28 +269,20 @@ public class MainAbilitySlice extends AbilitySlice {
                     try {
                         switch (position) {
                             case 0: // 我的
-                                page = LayoutScatter.getInstance(MainAbilitySlice.this)
-                                        .parse(ResourceTable.Layout_layout_my, null, false);
+                                myPageComponent = new MyPageComponent(MainAbilitySlice.this);
+                                page = myPageComponent;
                                 break;
                             case 1: // 找车位
-                                page = LayoutScatter.getInstance(MainAbilitySlice.this)
-                                        .parse(ResourceTable.Layout_layout_find_parking, null, false);
-                                findParkingPage = page;
-                                // 初始化找车位页面组件(延迟执行,确保页面已添加到容器)
-                                getUITaskDispatcher().asyncDispatch(() -> {
-                                    try {
-                                        Thread.sleep(100); // 等待页面渲染
-                                    } catch (InterruptedException e) {
-                                        e.printStackTrace();
-                                    }
-                                    initFindParkingPage();
-                                    // 默认加载数据
-                                    loadParkingData(true);
-                                });
+                                findParkingPageComponent = new FindParkingPageComponent(MainAbilitySlice.this);
+                                findParkingPageComponent.setLoadingComponent(loadingComponent);
+                                // 如果已有定位信息,设置到组件中
+                                if (currentLocation != null) {
+                                    findParkingPageComponent.setCurrentLocation(currentLocation);
+                                }
+                                page = findParkingPageComponent;
                                 break;
                             case 2: // 预约停车
-                                page = LayoutScatter.getInstance(MainAbilitySlice.this)
-                                        .parse(ResourceTable.Layout_layout_reserve_parking, null, false);
+                                page = new ReserveParkingPageComponent(MainAbilitySlice.this);
                                 break;
                         }
                         if (page != null) {
@@ -323,7 +312,8 @@ public class MainAbilitySlice extends AbilitySlice {
 
             pageSlider.setProvider(pageSliderProvider);
             // 默认显示找车位页面(索引1)
-            pageSlider.setCurrentPage(1);
+//            pageSlider.setCurrentPage(1);
+            pageSlider.setCurrentPage(3);
 
             // 添加页面切换监听
             pageSlider.addPageChangedListener(new PageSlider.PageChangedListener() {
@@ -333,9 +323,13 @@ public class MainAbilitySlice extends AbilitySlice {
                     currentTab = index;
                     updateBottomNavState(index);
                     Log.info("切换到页面: " + index);
-                    // 如果切换到找车位页面,加载数据
-                    if (index == 1 && findParkingPage != null) {
-                        loadParkingData(true);
+                    // 如果切换到我的页面,刷新数据
+                    if (index == 0 && myPageComponent != null) {
+                        myPageComponent.refresh();
+                    }
+                    // 如果切换到找车位页面,刷新数据
+                    if (index == 1 && findParkingPageComponent != null) {
+                        findParkingPageComponent.refresh();
                     }
                 }
 
@@ -392,7 +386,7 @@ public class MainAbilitySlice extends AbilitySlice {
         }
 
         // 默认选中找车位
-        updateBottomNavState(1);
+        updateBottomNavState(1); // 测试
     }
 
     /**
@@ -479,9 +473,9 @@ public class MainAbilitySlice extends AbilitySlice {
                     double longitude = location.getLongitude();
 
                     Log.info("定位成功: " + latitude + ", " + longitude);
-                    // 定位成功后,如果当前在找车位页面,重新加载数据
-                    if (currentTab == 1 && findParkingPage != null) {
-                        loadParkingData(true);
+                    // 定位成功后,如果当前在找车位页面,更新定位信息
+                    if (currentTab == 1 && findParkingPageComponent != null) {
+                        findParkingPageComponent.setCurrentLocation(location);
                     }
                 }
 
@@ -541,425 +535,4 @@ public class MainAbilitySlice extends AbilitySlice {
         dataAbilityHelper.unregisterObserver(SystemSettings.getUri(SystemSettings.Date.TIME_FORMAT), dataAbilityObserver);
     }
 
-    /**
-     * 初始化找车位页面组件
-     */
-    private void initFindParkingPage() {
-        if (findParkingPage == null) {
-            return;
-        }
-
-        // 获取组件
-        btnDistanceSort = (Button) findParkingPage.findComponentById(ResourceTable.Id_btn_distance_sort);
-        parkingListScroll = (ScrollView) findParkingPage.findComponentById(ResourceTable.Id_parking_list_scroll);
-        parkingListContainer = (DirectionalLayout) findParkingPage.findComponentById(ResourceTable.Id_parking_list_container);
-
-        // 设置标签页点击事件
-        if (tabAll != null) {
-            tabAll.setClickedListener(component -> switchTab(2)); // 2=全部
-        }
-        if (tabRecommended != null) {
-            tabRecommended.setClickedListener(component -> switchTab(1)); // 1=推荐
-        }
-
-        // 设置下拉框点击事件(这里用按钮模拟下拉框)
-        if (btnDistanceSort != null) {
-            btnDistanceSort.setClickedListener(component -> {
-                // 可以在这里显示下拉选择框,暂时保持"距离最近"
-                Log.info("点击了距离最近下拉框");
-            });
-        }
-
-        // 设置滚动监听,实现分页加载
-        if (parkingListScroll != null) {
-            parkingListScroll.setReboundEffect(false);
-            // 监听滚动到底部
-            parkingListScroll.addScrolledListener(new Component.ScrolledListener() {
-                @Override
-                public void onContentScrolled(Component component, int x, int y, int oldX, int oldY) {
-                    // 防抖:避免频繁触发
-                    long currentTime = System.currentTimeMillis();
-                    if (currentTime - lastLoadTime < LOAD_THROTTLE_MS) {
-                        return;
-                    }
-
-                    // 如果正在加载或没有更多数据,直接返回
-                    if (isLoading || !hasMore) {
-                        return;
-                    }
-
-                    // 计算是否滚动到底部
-                    int scrollY = parkingListScroll.getScrollValue(1);
-                    int viewHeight = parkingListScroll.getHeight();
-
-                    // 获取内容高度(使用容器的高度)
-                    int contentHeight = 0;
-                    if (parkingListContainer != null) {
-                        contentHeight = parkingListContainer.getHeight();
-                    }
-
-                    // 如果容器高度为0,尝试使用EstimatedHeight
-                    if (contentHeight == 0) {
-                        contentHeight = parkingListScroll.getEstimatedHeight();
-                    }
-
-                    // 如果内容高度或视图高度为0,无法计算,直接返回
-                    if (contentHeight == 0 || viewHeight == 0) {
-                        return;
-                    }
-
-                    // 计算剩余滚动距离
-                    int remainingDistance = contentHeight - scrollY - viewHeight;
-
-                    // 计算阈值(50像素,约等于50vp),当剩余距离小于等于阈值时触发加载
-                    int threshold = 50;
-
-                    // 当滚动到底部(剩余距离小于等于阈值)时,触发加载
-                    if (remainingDistance <= threshold && remainingDistance >= 0) {
-                        lastLoadTime = currentTime;
-                        // 加载下一页
-                        loadParkingData(false);
-                    }
-                }
-            });
-        }
-
-        // 默认选中全部车场
-        switchTab(2);
-    }
-
-    /**
-     * 切换标签页
-     */
-    private void switchTab(int filter) {
-        filterType = filter;
-        currentPage = 1;
-        hasMore = true;
-        lastLoadTime = 0; // 重置防抖时间
-        parkingList.clear();
-        if (parkingListContainer != null) {
-            parkingListContainer.removeAllComponents();
-        }
-        // 清除选中状态
-        selectedParkingItem = null;
-
-        // 更新标签样式
-        Color selectedColor = new Color(Color.getIntColor("#FA6332"));
-        Color normalColor = new Color(Color.getIntColor("#FF666666"));
-
-        if (tabAll != null) {
-            tabAll.setTextColor(filter == 2 ? selectedColor : normalColor);
-        }
-        if (tabRecommended != null) {
-            tabRecommended.setTextColor(filter == 1 ? selectedColor : normalColor);
-        }
-
-        // 更新下划线显示
-        if (tabAllUnderline != null) {
-            tabAllUnderline.setVisibility(filter == 2 ? Component.VISIBLE : Component.HIDE);
-        }
-        if (tabRecommendedUnderline != null) {
-            tabRecommendedUnderline.setVisibility(filter == 1 ? Component.VISIBLE : Component.HIDE);
-        }
-
-        // 加载数据
-        loadParkingData(true);
-    }
-
-    /**
-     * 加载停车场数据
-     */
-    private void loadParkingData(boolean isRefresh) {
-        if (isLoading) {
-            return;
-        }
-
-        if (isRefresh) {
-            currentPage = 1;
-            hasMore = true;
-            lastLoadTime = 0; // 重置防抖时间
-            parkingList.clear();
-            if (parkingListContainer != null) {
-                parkingListContainer.removeAllComponents();
-            }
-        }
-
-        if (!hasMore) {
-            return;
-        }
-
-        // 锁定当前页码,避免并发问题
-        final int requestPage = currentPage;
-        isLoading = true;
-
-        // 获取定位坐标
-        double latitude = 0;
-        double longitude = 0;
-        if (currentLocation != null) {
-            latitude = currentLocation.getLatitude();
-            longitude = currentLocation.getLongitude();
-        }
-
-        // 构建请求URL(使用锁定的页码)
-        String url = String.format("/park/near/page?filter=%d&latitude=%f&longitude=%f&current=%d&size=%d",
-                filterType, latitude, longitude, requestPage, pageSize);
-
-        // 发送请求(网络请求已在后台线程)
-        CompletableFuture<R<Object>> future = api.http(getContext(), url, "GET", null, null, null);
-        loadingComponent.show();
-        future.thenAccept(response -> {
-            // 在后台线程解析数据,避免阻塞UI
-            try {
-                if (response == null || !response.isSuccess()) {
-                    String errorMsg = response != null ? response.getMsg() : "请求失败";
-                    Log.error("加载停车场数据失败: " + errorMsg);
-                    return;
-                }
-
-                // 解析响应数据(在后台线程)
-                Object dataObj = response.getData();
-                if (dataObj == null) {
-                    Log.error("响应数据为空");
-                    return;
-                }
-
-                // 将data转换为ZSONObject
-                ZSONObject pageObj;
-                if (dataObj instanceof ZSONObject) {
-                    pageObj = (ZSONObject) dataObj;
-                } else {
-                    pageObj = ZSONObject.stringToZSON(dataObj.toString());
-                }
-
-                // 解析Page对象(在后台线程)
-                Page<ParkNearRes> page = parsePageData(pageObj);
-                if (page == null || page.getRecords() == null) {
-                    Log.error("解析分页数据失败");
-                    return;
-                }
-
-                List<ParkNearRes> records = page.getRecords();
-                if (records.isEmpty()) {
-                    hasMore = false;
-                    return;
-                }
-
-                // 更新分页信息(在后台线程计算)
-                boolean hasMoreData = true;
-                int nextPage = requestPage + 1;
-                if (page.getCurrent() != null && page.getPages() != null) {
-                    int serverCurrent = page.getCurrent();
-                    int totalPages = page.getPages();
-                    if (serverCurrent >= totalPages) {
-                        hasMoreData = false;
-                    } else {
-                        // 使用服务器返回的current值+1作为下一页
-                        nextPage = serverCurrent + 1;
-                    }
-                } else {
-                    if (records.size() < pageSize) {
-                        hasMoreData = false;
-                    }
-                }
-
-                // 保存最终的分页信息
-                final boolean finalHasMore = hasMoreData;
-                final int finalNextPage = nextPage;
-                final List<ParkNearRes> finalRecords = records;
-
-                // 只在UI线程更新界面
-                getUITaskDispatcher().asyncDispatch(() -> {
-
-                    // 检查currentPage是否已经被其他请求更新(防止旧请求覆盖新数据)
-                    // 如果currentPage > requestPage,说明有更新的请求已经完成,忽略这个旧请求的结果
-                    if (currentPage > requestPage) {
-                        Log.info("忽略过期请求,当前页码: " + currentPage + ", 请求页码: " + requestPage);
-                        return;
-                    }
-
-                    // 添加到列表
-                    parkingList.addAll(finalRecords);
-
-                    // 批量渲染列表项(减少UI更新次数,延迟批量添加)
-                    if (parkingListContainer != null && !finalRecords.isEmpty()) {
-                        // 先批量创建所有组件
-                        List<Component> items = new ArrayList<>();
-                        for (ParkNearRes park : finalRecords) {
-                            Component item = createParkingItem(park);
-                            if (item != null) {
-                                items.add(item);
-                            }
-                        }
-
-                        // 批量添加到容器(减少UI重绘次数)
-                        for (Component item : items) {
-                            parkingListContainer.addComponent(item);
-                        }
-                    }
-
-                    // 更新分页信息
-                    hasMore = finalHasMore;
-                    if (finalHasMore) {
-                        currentPage = finalNextPage;
-                    }
-                });
-
-            } catch (Exception e) {
-                Log.error("解析停车场数据失败: " + e.getMessage());
-                e.printStackTrace();
-            } finally {
-                isLoading = false;
-                loadingComponent.hide();
-            }
-        });
-    }
-
-    /**
-     * 解析分页数据
-     */
-    private Page<ParkNearRes> parsePageData(ZSONObject pageObj) {
-        try {
-            Page<ParkNearRes> page = new Page<>();
-
-            if (pageObj.containsKey("total")) {
-                page.setTotal(pageObj.getIntValue("total"));
-            }
-            if (pageObj.containsKey("pages")) {
-                page.setPages(pageObj.getIntValue("pages"));
-            }
-            if (pageObj.containsKey("current")) {
-                page.setCurrent(pageObj.getIntValue("current"));
-            }
-            if (pageObj.containsKey("size")) {
-                page.setSize(pageObj.getIntValue("size"));
-            }
-            if (pageObj.containsKey("records")) {
-                Object recordsObj = pageObj.get("records");
-                if (recordsObj instanceof List) {
-                    List<?> recordsList = (List<?>) recordsObj;
-                    List<ParkNearRes> parkList = new ArrayList<>();
-                    for (Object item : recordsList) {
-                        ParkNearRes park = parseParkData(item);
-                        if (park != null) {
-                            parkList.add(park);
-                        }
-                    }
-                    page.setRecords(parkList);
-                }
-            }
-
-            return page;
-        } catch (Exception e) {
-            Log.error("解析Page数据失败: " + e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * 解析停车场数据
-     */
-    private ParkNearRes parseParkData(Object itemObj) {
-        try {
-            ZSONObject parkObj;
-            if (itemObj instanceof ZSONObject) {
-                parkObj = (ZSONObject) itemObj;
-            } else {
-                parkObj = ZSONObject.stringToZSON(itemObj.toString());
-            }
-
-            ParkNearRes park = new ParkNearRes();
-            if (parkObj.containsKey("parkId")) {
-                park.setParkId(parkObj.getString("parkId"));
-            }
-            if (parkObj.containsKey("parkName")) {
-                park.setParkName(parkObj.getString("parkName"));
-            }
-            if (parkObj.containsKey("isreserver")) {
-                park.setIsreserver(parkObj.getIntValue("isreserver"));
-            }
-            if (parkObj.containsKey("isfindcar")) {
-                park.setIsfindcar(parkObj.getIntValue("isfindcar"));
-            }
-            if (parkObj.containsKey("powerEnable")) {
-                park.setPowerEnable(parkObj.getIntValue("powerEnable"));
-            }
-            if (parkObj.containsKey("distance")) {
-                park.setDistance(parkObj.getDoubleValue("distance"));
-            }
-            if (parkObj.containsKey("address")) {
-                park.setAddress(parkObj.getString("address"));
-            }
-            if (parkObj.containsKey("totalPlace")) {
-                park.setTotalPlace(parkObj.getIntValue("totalPlace"));
-            }
-            if (parkObj.containsKey("residuePlace")) {
-                park.setResiduePlace(parkObj.getIntValue("residuePlace"));
-            }
-            if (parkObj.containsKey("latitude")) {
-                park.setLatitude(parkObj.getDoubleValue("latitude"));
-            }
-            if (parkObj.containsKey("longitude")) {
-                park.setLongitude(parkObj.getDoubleValue("longitude"));
-            }
-            if (parkObj.containsKey("onlinePayEnable")) {
-                park.setOnlinePayEnable(parkObj.getIntValue("onlinePayEnable"));
-            }
-            if (parkObj.containsKey("invoiceEnable")) {
-                park.setInvoiceEnable(parkObj.getIntValue("invoiceEnable"));
-            }
-            if (parkObj.containsKey("reductionEnable")) {
-                park.setReductionEnable(parkObj.getIntValue("reductionEnable"));
-            }
-            if (parkObj.containsKey("chargeInfo")) {
-                park.setChargeInfo(parkObj.getString("chargeInfo"));
-            }
-
-            return park;
-        } catch (Exception e) {
-            Log.error("解析ParkNearRes数据失败: " + e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * 创建停车场列表项组件(不添加到容器)
-     * 使用 ParkingItemComponent 组件
-     */
-    private Component createParkingItem(ParkNearRes park) {
-        if (parkingListContainer == null) {
-            return null;
-        }
-
-        try {
-            // 使用 ParkingItemComponent 组件
-            ParkingItemComponent item = new ParkingItemComponent(this, park);
-            
-            // 设置选中监听器,实现全局选中状态管理
-            item.setOnItemSelectedListener((component, parkData) -> {
-                // 如果之前有选中的项,取消其选中状态
-                if (selectedParkingItem != null && selectedParkingItem != component) {
-                    selectedParkingItem.setSelected(false);
-                }
-                // 更新当前选中的项
-                selectedParkingItem = component;
-            });
-
-            return item;
-
-        } catch (Exception e) {
-            Log.error("创建停车场列表项失败: " + e.getMessage());
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * 添加停车场列表项(兼容方法,内部调用createParkingItem)
-     */
-    private void addParkingItem(ParkNearRes park) {
-        Component item = createParkingItem(park);
-        if (item != null && parkingListContainer != null) {
-            parkingListContainer.addComponent(item);
-        }
-    }
 }

+ 53 - 0
entry/src/main/java/com/fujica/abk/utils/DialogUtil.java

@@ -0,0 +1,53 @@
+package com.fujica.abk.utils;
+
+import ohos.agp.window.dialog.IDialog;
+import ohos.agp.window.dialog.ListDialog;
+import ohos.app.Context;
+
+/**
+ * 对话框工具类
+ * 用于统一管理 ListDialog 的创建和样式配置
+ * 统一设置样式,使对话框内容左右居中显示
+ */
+public class DialogUtil {
+    
+    /**
+     * 单选监听器接口
+     */
+    @FunctionalInterface
+    public interface SingleSelectListener {
+        /**
+         * 当选择某个选项时调用
+         * @param dialog 对话框对象
+         * @param index 选中的索引
+         */
+        void onSelect(IDialog dialog, int index);
+    }
+    
+    /**
+     * 创建并配置 ListDialog(公共方法)
+     * 统一设置样式,使对话框内容左右居中
+     * 
+     * @param context 上下文
+     * @param options 选项数组
+     * @param listener 选择监听器
+     * @return 配置好的 ListDialog
+     */
+    public static ListDialog createListDialog(Context context, String[] options, 
+                                              SingleSelectListener listener) {
+        ListDialog listDialog = new ListDialog(context);
+        listDialog.setItems(options);
+        listDialog.setOnSingleSelectListener((iDialog, index) -> {
+            if (listener != null) {
+                listener.onSelect(iDialog, index);
+            }
+        });
+        
+        // 在 HarmonyOS 中,ListDialog 默认会居中显示
+        // 如果需要自定义样式,可以在这里添加相关配置
+        // 注意:ListDialog 在 HarmonyOS 中默认就是居中的,无需额外设置
+        
+        return listDialog;
+    }
+}
+

+ 60 - 0
entry/src/main/java/com/fujica/abk/utils/LicensePlateDialog.java

@@ -0,0 +1,60 @@
+package com.fujica.abk.utils;
+
+import ohos.agp.window.dialog.CommonDialog;
+import ohos.app.Context;
+
+/**
+ * 车牌输入对话框组件
+ * 用于输入车牌号
+ */
+public class LicensePlateDialog {
+    private CommonDialog dialog;
+    private Context context;
+    
+    /**
+     * 构造函数
+     */
+    public LicensePlateDialog(Context context) {
+        this.context = context;
+        this.dialog = new CommonDialog(context);
+        initDialog();
+    }
+    
+    /**
+     * 初始化对话框
+     */
+    private void initDialog() {
+        // 设置对话框属性
+        dialog.setAutoClosable(true);
+        // 可以在这里添加更多默认配置
+        // 暂时为空,后续实现输入框等UI
+    }
+    
+    /**
+     * 显示对话框
+     */
+    public void show() {
+        if (dialog != null) {
+            dialog.show();
+        }
+    }
+    
+    /**
+     * 隐藏对话框
+     */
+    public void hide() {
+        if (dialog != null) {
+            dialog.hide();
+        }
+    }
+    
+    /**
+     * 销毁对话框
+     */
+    public void destroy() {
+        if (dialog != null) {
+            dialog.destroy();
+        }
+    }
+}
+

+ 906 - 0
entry/src/main/java/com/fujica/abk/utils/LicensePlateInputDialog.java

@@ -0,0 +1,906 @@
+package com.fujica.abk.utils;
+
+import com.fujica.abk.ResourceTable;
+import ohos.agp.colors.RgbColor;
+import ohos.agp.components.*;
+import ohos.agp.components.LayoutScatter;
+import ohos.agp.components.element.ShapeElement;
+import ohos.agp.utils.Color;
+import ohos.agp.window.dialog.CommonDialog;
+import ohos.app.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static ohos.agp.components.Component.HIDE;
+import static ohos.agp.components.Component.VISIBLE;
+
+/**
+ * 车牌输入对话框
+ * 继承自CommonDialog,实现车牌输入功能
+ */
+public class LicensePlateInputDialog extends CommonDialog {
+    private Context context;
+    private Component rootLayout;
+    
+    // 车牌输入框
+    private Text plateProvince;      // 省份
+    private Text plateLetter;        // 字母
+    private Text plateChar1, plateChar2, plateChar3, plateChar4, plateChar5;  // 5个字符
+    private DirectionalLayout plateNewEnergy;  // 新能源选项
+    private Text newEnergyText;
+    private Text newEnergyPlusText;  // 新能源选项的+号
+    
+    // 特殊车牌输入
+    private TextField specialPlateInput;
+    private DirectionalLayout licensePlateInputArea;
+    private Text btnSwitchSpecial;
+    
+    // 键盘相关
+    private DirectionalLayout keyboardContainer;
+    private DirectionalLayout chineseKeyboardLayout;
+    private DirectionalLayout englishKeyboardLayout;
+    
+    // 键盘按钮列表(用于启用/禁用)
+    private List<Button> chineseKeyboardButtons = new ArrayList<>();
+    private List<Button> englishKeyboardButtons = new ArrayList<>();
+    private List<KeyboardItem> chineseKeyboardItems = new ArrayList<>();
+    private List<KeyboardItem> englishKeyboardItems = new ArrayList<>();
+    
+    // 确认按钮
+    private Button btnConfirm;
+    
+    // 当前输入位置索引 (0-7: 省份、字母、5个字符、新能源)
+    private int currentInputIndex = 0;
+    
+    // 车牌类型:0-常规,1-特殊
+    private int plateType = 0;
+    
+    // 是否新能源
+    private boolean isNewEnergy = false;
+    
+    // 车牌数据
+    private String[] plateData = new String[8];  // 8个位置:省份、字母、5个字符、新能源
+    
+    // 回调接口
+    public interface OnConfirmListener {
+        void onConfirm(String licensePlate);
+    }
+    
+    private OnConfirmListener confirmListener;
+    
+    /**
+     * 键盘项数据类
+     */
+    private static class KeyboardItem {
+        int id;
+        String font;
+        
+        KeyboardItem(int id, String font) {
+            this.id = id;
+            this.font = font;
+        }
+    }
+    
+    /**
+     * 构造函数
+     */
+    public LicensePlateInputDialog(Context context) {
+        super(context);
+        this.context = context;
+        initKeyboardData();
+        initDialog();
+    }
+    
+    /**
+     * 初始化对话框
+     */
+    private void initDialog() {
+        // 设置对话框属性
+        setAutoClosable(true);
+        setCornerRadius(ScreenUtil.vp2px(context, 20));
+        
+        // 加载布局
+        rootLayout = LayoutScatter.getInstance(context)
+                .parse(ResourceTable.Layout_layout_license_plate_dialog, null, false);
+        setContentCustomComponent(rootLayout);
+        
+        // 初始化视图
+        initViews();
+        
+        // 设置监听器
+        setupListeners();
+        
+        // 初始化车牌数据
+        initPlateData();
+        
+        // 显示常规车牌输入
+        showNormalPlateInput();
+        
+        // 初始化时聚焦第一个输入框
+        currentInputIndex = 0;
+        updateInputFocus();
+        showChineseKeyboard();
+    }
+    
+    /**
+     * 初始化键盘数据
+     */
+    private void initKeyboardData() {
+        // 中文键盘(省份)- 按照截图布局:4行,每行10个
+        // 第1行:京、津、冀、鲁、晋、蒙、辽、吉、黑、沪
+        String[] row1 = {"京", "津", "冀", "鲁", "晋", "蒙", "辽", "吉", "黑", "沪"};
+        int[] row1Ids = {1, 4, 5, 16, 6, 7, 8, 9, 10, 2};
+        for (int i = 0; i < row1.length; i++) {
+            chineseKeyboardItems.add(new KeyboardItem(row1Ids[i], row1[i]));
+        }
+        // 第2行:苏、浙、皖、闽、赣、豫、鄂、湘、粤、桂
+        String[] row2 = {"苏", "浙", "皖", "闽", "赣", "豫", "鄂", "湘", "粤", "桂"};
+        int[] row2Ids = {11, 12, 13, 14, 15, 17, 18, 19, 3, 20};
+        for (int i = 0; i < row2.length; i++) {
+            chineseKeyboardItems.add(new KeyboardItem(row2Ids[i], row2[i]));
+        }
+        // 第3行:琼、渝、川、贵、云、藏、陕、甘、青、宁
+        String[] row3 = {"琼", "渝", "川", "贵", "云", "藏", "陕", "甘", "青", "宁"};
+        int[] row3Ids = {21, 22, 23, 24, 25, 26, 27, 28, 29, 30};
+        for (int i = 0; i < row3.length; i++) {
+            chineseKeyboardItems.add(new KeyboardItem(row3Ids[i], row3[i]));
+        }
+        // 第4行:新、虚、M、删除
+        String[] row4 = {"新", "虚", "M", ""};
+        int[] row4Ids = {31, 32, 34, 33};
+        for (int i = 0; i < row4.length; i++) {
+            chineseKeyboardItems.add(new KeyboardItem(row4Ids[i], row4[i]));
+        }
+        
+        // 英文键盘(字母和数字)- 按照截图布局
+        // 第1行:1、2、3、4、5、6、7、8、9、0
+        String[] engRow1 = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"};
+        int[] engRow1Ids = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+        for (int i = 0; i < engRow1.length; i++) {
+            englishKeyboardItems.add(new KeyboardItem(engRow1Ids[i], engRow1[i]));
+        }
+        // 第2行:Q、W、E、R、T、Y、U、O、P、港
+        String[] engRow2 = {"Q", "W", "E", "R", "T", "Y", "U", "O", "P", "港"};
+        int[] engRow2Ids = {25, 31, 15, 26, 28, 41, 29, 40, 24, 35};
+        for (int i = 0; i < engRow2.length; i++) {
+            englishKeyboardItems.add(new KeyboardItem(engRow2Ids[i], engRow2[i]));
+        }
+        // 第3行:A、S、D、F、G、H、J、K、L、澳
+        String[] engRow3 = {"A", "S", "D", "F", "G", "H", "J", "K", "L", "澳"};
+        int[] engRow3Ids = {11, 27, 14, 16, 17, 18, 19, 20, 21, 36};
+        for (int i = 0; i < engRow3.length; i++) {
+            englishKeyboardItems.add(new KeyboardItem(engRow3Ids[i], engRow3[i]));
+        }
+        // 第4行:Z、X、C、V、B、N、M、学、领、删除
+        String[] engRow4 = {"Z", "X", "C", "V", "B", "N", "M", "学", "领", ""};
+        int[] engRow4Ids = {34, 32, 13, 30, 12, 23, 22, 37, 39, 38};
+        for (int i = 0; i < engRow4.length; i++) {
+            englishKeyboardItems.add(new KeyboardItem(engRow4Ids[i], engRow4[i]));
+        }
+    }
+    
+    /**
+     * 初始化视图
+     */
+    private void initViews() {
+        // 标题栏
+        Image btnClose = (Image) rootLayout.findComponentById(ResourceTable.Id_btn_close);
+        if (btnClose != null) {
+            btnClose.setClickedListener(component -> hide());
+        }
+        
+        // 车牌输入框
+        plateProvince = (Text) rootLayout.findComponentById(ResourceTable.Id_plate_province);
+        plateLetter = (Text) rootLayout.findComponentById(ResourceTable.Id_plate_letter);
+        plateChar1 = (Text) rootLayout.findComponentById(ResourceTable.Id_plate_char1);
+        plateChar2 = (Text) rootLayout.findComponentById(ResourceTable.Id_plate_char2);
+        plateChar3 = (Text) rootLayout.findComponentById(ResourceTable.Id_plate_char3);
+        plateChar4 = (Text) rootLayout.findComponentById(ResourceTable.Id_plate_char4);
+        plateChar5 = (Text) rootLayout.findComponentById(ResourceTable.Id_plate_char5);
+        plateNewEnergy = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_plate_new_energy);
+        newEnergyText = (Text) rootLayout.findComponentById(ResourceTable.Id_new_energy_text);
+        // 获取+号文本(plateNewEnergy的第一个子组件)
+        if (plateNewEnergy != null && plateNewEnergy.getChildCount() > 0) {
+            Component firstChild = plateNewEnergy.getComponentAt(0);
+            if (firstChild instanceof Text) {
+                newEnergyPlusText = (Text) firstChild;
+            }
+        }
+        
+        // 特殊车牌
+        specialPlateInput = rootLayout.findComponentById(ResourceTable.Id_special_plate_input);
+        licensePlateInputArea = rootLayout.findComponentById(ResourceTable.Id_license_plate_input_area);
+        btnSwitchSpecial = rootLayout.findComponentById(ResourceTable.Id_btn_switch_special);
+        
+        // 键盘
+        keyboardContainer = rootLayout.findComponentById(ResourceTable.Id_keyboard_container);
+        chineseKeyboardLayout = rootLayout.findComponentById(ResourceTable.Id_chinese_keyboard);
+        englishKeyboardLayout = rootLayout.findComponentById(ResourceTable.Id_english_keyboard);
+        
+        // 确认按钮
+        btnConfirm = (Button) rootLayout.findComponentById(ResourceTable.Id_btn_confirm);
+        
+        // 初始化键盘(创建所有按钮)
+        initKeyboards();
+    }
+    
+    /**
+     * 设置监听器
+     */
+    private void setupListeners() {
+        // 切换特殊车牌
+        if (btnSwitchSpecial != null) {
+            btnSwitchSpecial.setClickedListener(component -> {
+                plateType = (plateType + 1) % 2;
+                if (plateType == 0) {
+                    showNormalPlateInput();
+                    btnSwitchSpecial.setText("切换特殊车牌");
+                    // 显示键盘
+                    currentInputIndex = 0;
+                    updateInputFocus();
+                    showChineseKeyboard();
+                } else {
+                    showSpecialPlateInput();
+                    btnSwitchSpecial.setText("切换常规车牌");
+                    // 隐藏键盘
+                    hideKeyboard();
+                }
+            });
+        }
+        
+        // 确认按钮
+        if (btnConfirm != null) {
+            btnConfirm.setClickedListener(component -> {
+                String licensePlate = getLicensePlate();
+                if (licensePlate != null && !licensePlate.isEmpty()) {
+                    if (confirmListener != null) {
+                        confirmListener.onConfirm(licensePlate);
+                    }
+                    hide();
+                }
+            });
+        }
+        
+        // 车牌输入框点击事件
+        setupPlateInputListeners();
+    }
+    
+    /**
+     * 设置车牌输入框点击监听
+     */
+    private void setupPlateInputListeners() {
+        if (plateProvince != null) {
+            plateProvince.setClickedListener(component -> {
+                currentInputIndex = 0;
+                updateInputFocus();
+                showChineseKeyboard();
+            });
+        }
+
+        if (plateLetter != null) {
+            plateLetter.setClickedListener(component -> {
+                currentInputIndex = 1;
+                updateInputFocus();
+                showEnglishKeyboard();
+            });
+        }
+        
+        if (plateChar1 != null) {
+            plateChar1.setClickedListener(component -> {
+                currentInputIndex = 2;
+                updateInputFocus();
+                showEnglishKeyboard();
+            });
+        }
+        
+        if (plateChar2 != null) {
+            plateChar2.setClickedListener(component -> {
+                currentInputIndex = 3;
+                updateInputFocus();
+                showEnglishKeyboard();
+            });
+        }
+        
+        if (plateChar3 != null) {
+            plateChar3.setClickedListener(component -> {
+                currentInputIndex = 4;
+                updateInputFocus();
+                showEnglishKeyboard();
+            });
+        }
+        
+        if (plateChar4 != null) {
+            plateChar4.setClickedListener(component -> {
+                currentInputIndex = 5;
+                updateInputFocus();
+                showEnglishKeyboard();
+            });
+        }
+        
+        if (plateChar5 != null) {
+            plateChar5.setClickedListener(component -> {
+                currentInputIndex = 6;
+                updateInputFocus();
+                showEnglishKeyboard();
+            });
+        }
+        
+        if (plateNewEnergy != null) {
+            plateNewEnergy.setClickedListener(component -> {
+                currentInputIndex = 7;
+                updateInputFocus();
+                showEnglishKeyboard();
+            });
+        }
+    }
+    
+    /**
+     * 初始化车牌数据
+     */
+    private void initPlateData() {
+        plateData[0] = "粤";  // 默认省份
+        plateData[1] = "B";   // 默认字母
+        for (int i = 2; i < 7; i++) {
+            plateData[i] = "";
+        }
+        plateData[7] = "新能源";
+        updatePlateDisplay();
+    }
+    
+    /**
+     * 更新车牌显示
+     */
+    private void updatePlateDisplay() {
+        if (plateProvince != null) plateProvince.setText(plateData[0] != null ? plateData[0] : "");
+        if (plateLetter != null) plateLetter.setText(plateData[1] != null ? plateData[1] : "");
+        if (plateChar1 != null) plateChar1.setText(plateData[2] != null ? plateData[2] : "");
+        if (plateChar2 != null) plateChar2.setText(plateData[3] != null ? plateData[3] : "");
+        if (plateChar3 != null) plateChar3.setText(plateData[4] != null ? plateData[4] : "");
+        if (plateChar4 != null) plateChar4.setText(plateData[5] != null ? plateData[5] : "");
+        if (plateChar5 != null) plateChar5.setText(plateData[6] != null ? plateData[6] : "");
+        
+        // 更新新能源显示
+        if (newEnergyText != null) {
+            if (plateData[7] != null && !plateData[7].isEmpty() && !plateData[7].equals("新能源")) {
+                // 如果有输入字符,显示输入的字符,隐藏+号,使用正常颜色和大小
+                newEnergyText.setText(plateData[7]);
+                newEnergyText.setTextSize(ScreenUtil.fp2px(context, 16));  // 正常大小
+                // 如果当前聚焦在第8个位置,文字颜色为白色;否则为黑色
+                if (currentInputIndex == 7) {
+                    newEnergyText.setTextColor(Color.WHITE);
+                } else {
+                    newEnergyText.setTextColor(new Color(0xFF000000));  // 黑色
+                }
+                // 隐藏+号
+                if (newEnergyPlusText != null) {
+                    newEnergyPlusText.setVisibility(HIDE);
+                }
+            } else {
+                // 没有输入时,显示默认样式
+                if (isNewEnergy) {
+                    // 如果是新能源状态,显示空
+                    newEnergyText.setText("");
+                } else {
+                    // 默认显示"新能源"
+                    newEnergyText.setText("新能源");
+                }
+                newEnergyText.setTextColor(new Color(0xFF999999));  // 灰色
+                newEnergyText.setTextSize(ScreenUtil.fp2px(context, 10));  // 小字体
+                // 显示+号
+                if (newEnergyPlusText != null) {
+                    newEnergyPlusText.setVisibility(VISIBLE);
+                }
+            }
+        }
+    }
+    
+    /**
+     * 显示常规车牌输入
+     */
+    private void showNormalPlateInput() {
+        if (licensePlateInputArea != null) {
+            licensePlateInputArea.setVisibility(VISIBLE);
+        }
+        if (specialPlateInput != null) {
+            specialPlateInput.setVisibility(HIDE);
+        }
+    }
+    
+    /**
+     * 显示特殊车牌输入
+     */
+    private void showSpecialPlateInput() {
+        if (licensePlateInputArea != null) {
+            licensePlateInputArea.setVisibility(HIDE);
+        }
+        if (specialPlateInput != null) {
+            specialPlateInput.setVisibility(VISIBLE);
+        }
+        hideKeyboard();
+    }
+    
+    /**
+     * 初始化键盘(创建所有按钮)
+     */
+    private void initKeyboards() {
+        // 初始化中文键盘
+        initChineseKeyboard();
+        // 初始化英文键盘
+        initEnglishKeyboard();
+    }
+    
+    /**
+     * 初始化中文键盘
+     */
+    private void initChineseKeyboard() {
+        if (chineseKeyboardLayout == null) return;
+        chineseKeyboardLayout.removeAllComponents();
+        chineseKeyboardButtons.clear();
+        
+        int itemsPerRow = 10;
+        DirectionalLayout currentRow = null;
+        int itemCount = 0;
+        
+        for (KeyboardItem item : chineseKeyboardItems) {
+            if (itemCount % itemsPerRow == 0) {
+                currentRow = new DirectionalLayout(context);
+                currentRow.setOrientation(Component.HORIZONTAL);
+                ComponentContainer.LayoutConfig rowConfig = new ComponentContainer.LayoutConfig(
+                        ComponentContainer.LayoutConfig.MATCH_PARENT,
+                        ComponentContainer.LayoutConfig.MATCH_CONTENT);
+                currentRow.setLayoutConfig(rowConfig);
+                chineseKeyboardLayout.addComponent(currentRow);
+            }
+            
+            Button btn = createKeyboardButton(item, true);
+            chineseKeyboardButtons.add(btn);
+            
+            if (currentRow != null) {
+                currentRow.addComponent(btn);
+            }
+            
+            itemCount++;
+        }
+    }
+    
+    /**
+     * 初始化英文键盘
+     */
+    private void initEnglishKeyboard() {
+        if (englishKeyboardLayout == null) return;
+        englishKeyboardLayout.removeAllComponents();
+        englishKeyboardButtons.clear();
+        
+        int itemsPerRow = 10;
+        DirectionalLayout currentRow = null;
+        int itemCount = 0;
+        
+        for (KeyboardItem item : englishKeyboardItems) {
+            if (itemCount % itemsPerRow == 0) {
+                currentRow = new DirectionalLayout(context);
+                currentRow.setOrientation(Component.HORIZONTAL);
+                ComponentContainer.LayoutConfig rowConfig = new ComponentContainer.LayoutConfig(
+                        ComponentContainer.LayoutConfig.MATCH_PARENT,
+                        ComponentContainer.LayoutConfig.MATCH_CONTENT);
+                currentRow.setLayoutConfig(rowConfig);
+                englishKeyboardLayout.addComponent(currentRow);
+            }
+            
+            Button btn = createKeyboardButton(item, false);
+            englishKeyboardButtons.add(btn);
+            
+            if (currentRow != null) {
+                currentRow.addComponent(btn);
+            }
+            
+            itemCount++;
+        }
+    }
+    
+    /**
+     * 创建键盘按钮
+     */
+    private Button createKeyboardButton(KeyboardItem item, boolean isChinese) {
+        Button btn = new Button(context);
+        if (item.font.isEmpty()) {
+            // 删除按钮
+            btn.setText("删除");
+        } else {
+            btn.setText(item.font);
+        }
+        btn.setTextSize(ScreenUtil.fp2px(context, 20));  // 增大字体
+        
+        // 设置按钮样式
+        ShapeElement background = new ShapeElement();
+        background.setShape(ShapeElement.RECTANGLE);
+        background.setRgbColor(new RgbColor(255, 255, 255));
+        background.setCornerRadius(ScreenUtil.vp2px(context, 6));
+        btn.setBackground(background);
+        btn.setTextColor(new Color(0xFF333333));
+        
+        // 设置按钮尺寸和布局参数(增大按钮)
+        DirectionalLayout.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig(
+                0,
+                ComponentContainer.LayoutConfig.MATCH_CONTENT);
+        layoutConfig.width = 0;
+        layoutConfig.weight = 1;
+        layoutConfig.height = ScreenUtil.vp2px(context, 50);  // 增大高度到50vp
+        layoutConfig.setMarginLeft(ScreenUtil.vp2px(context, 4));
+        layoutConfig.setMarginRight(ScreenUtil.vp2px(context, 4));
+        layoutConfig.setMarginTop(ScreenUtil.vp2px(context, 4));
+        layoutConfig.setMarginBottom(ScreenUtil.vp2px(context, 4));
+        btn.setLayoutConfig(layoutConfig);
+        
+        // 设置点击事件
+        btn.setClickedListener(component -> onKeyboardItemClick(item));
+        
+        return btn;
+    }
+    
+    /**
+     * 显示中文键盘
+     */
+    private void showChineseKeyboard() {
+        if (keyboardContainer == null || chineseKeyboardLayout == null || englishKeyboardLayout == null) return;
+        
+        keyboardContainer.setVisibility(VISIBLE);
+        chineseKeyboardLayout.setVisibility(VISIBLE);
+        englishKeyboardLayout.setVisibility(HIDE);
+        
+        // 更新按钮状态
+        updateKeyboardButtonsState();
+    }
+    
+    /**
+     * 显示英文键盘
+     */
+    private void showEnglishKeyboard() {
+        if (keyboardContainer == null || chineseKeyboardLayout == null || englishKeyboardLayout == null) return;
+        
+        keyboardContainer.setVisibility(VISIBLE);
+        chineseKeyboardLayout.setVisibility(HIDE);
+        englishKeyboardLayout.setVisibility(VISIBLE);
+        
+        // 更新按钮状态
+        updateKeyboardButtonsState();
+    }
+    
+    /**
+     * 更新键盘按钮状态(根据当前输入索引启用/禁用按钮)
+     */
+    private void updateKeyboardButtonsState() {
+        // 更新中文键盘按钮状态
+        for (int i = 0; i < chineseKeyboardButtons.size() && i < chineseKeyboardItems.size(); i++) {
+            Button btn = chineseKeyboardButtons.get(i);
+            KeyboardItem item = chineseKeyboardItems.get(i);
+            boolean enabled = isButtonEnabled(item, true);
+            btn.setEnabled(enabled);
+            
+            // 更新按钮样式(禁用时置灰)
+            ShapeElement background = new ShapeElement();
+            background.setShape(ShapeElement.RECTANGLE);
+            background.setCornerRadius(ScreenUtil.vp2px(context, 6));
+            if (enabled) {
+                background.setRgbColor(new RgbColor(255, 255, 255));
+                btn.setTextColor(new Color(0xFF333333));
+            } else {
+                background.setRgbColor(new RgbColor(192, 192, 192));
+                btn.setTextColor(new Color(0xFF666666));
+            }
+            btn.setBackground(background);
+        }
+        
+        // 更新英文键盘按钮状态
+        for (int i = 0; i < englishKeyboardButtons.size() && i < englishKeyboardItems.size(); i++) {
+            Button btn = englishKeyboardButtons.get(i);
+            KeyboardItem item = englishKeyboardItems.get(i);
+            boolean enabled = isButtonEnabled(item, false);
+            btn.setEnabled(enabled);
+            
+            // 更新按钮样式(禁用时置灰)
+            ShapeElement background = new ShapeElement();
+            background.setShape(ShapeElement.RECTANGLE);
+            background.setCornerRadius(ScreenUtil.vp2px(context, 6));
+            if (enabled) {
+                background.setRgbColor(new RgbColor(255, 255, 255));
+                btn.setTextColor(new Color(0xFF333333));
+            } else {
+                background.setRgbColor(new RgbColor(192, 192, 192));
+                btn.setTextColor(new Color(0xFF666666));
+            }
+            btn.setBackground(background);
+        }
+    }
+    
+    /**
+     * 判断按钮是否可用
+     */
+    private boolean isButtonEnabled(KeyboardItem item, boolean isChinese) {
+        // 删除按钮始终可用
+        if (item.id == 33 || item.id == 38) {
+            return true;
+        }
+        
+        // 根据当前输入索引判断
+        if (currentInputIndex == 0) {
+            // 省份输入:只显示中文键盘
+            return isChinese;
+        } else if (currentInputIndex == 1) {
+            // 字母输入:只显示英文键盘
+            if (!isChinese) {
+                // 如果首位是M,第二位只能是数字
+                if (plateData[0] != null && plateData[0].equals("M")) {
+                    return item.id >= 1 && item.id <= 10;
+                }
+                // 如果首位是虚,第二位只能是数字
+                if (plateData[0] != null && plateData[0].equals("虚")) {
+                    return item.id >= 1 && item.id <= 10;
+                }
+                // 禁用数字 0-9(ID: 1-10)
+                if (item.id >= 1 && item.id <= 10) {
+                    return false;
+                }
+                // 字母O只能在第二位使用
+                if (item.id == 40) {  // O
+                    return true;
+                }
+                // 港澳学领只能在第六位使用
+                if (item.id == 35 || item.id == 36 || item.id == 37 || item.id == 39) {
+                    return false;
+                }
+                return true;
+            }
+            return false;
+        } else if (currentInputIndex >= 2 && currentInputIndex <= 6) {
+            // 字符输入:只显示英文键盘
+            if (!isChinese) {
+                // 港澳学领只能在第六位使用
+                if (item.id == 35 || item.id == 36 || item.id == 37 || item.id == 39) {
+                    return currentInputIndex == 6;
+                }
+                // 字母O不能在第二位之后使用
+                if (item.id == 40) {
+                    return false;
+                }
+                return true;
+            }
+            return false;
+        } else if (currentInputIndex == 7) {
+            // 新能源选项:显示英文键盘,禁用规则与第6个位置相同
+            if (!isChinese) {
+                // 港澳学领只能在第六位使用(第8个位置不能使用)
+                if (item.id == 35 || item.id == 36 || item.id == 37 || item.id == 39) {
+                    return false;
+                }
+                // 字母O不能在第二位之后使用
+                if (item.id == 40) {
+                    return false;
+                }
+                return true;
+            }
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 键盘项点击事件
+     */
+    private void onKeyboardItemClick(KeyboardItem item) {
+        if (!isButtonEnabled(item, currentInputIndex == 0)) {
+            return;  // 按钮被禁用,不处理
+        }
+        
+        if (item.id == 33 || item.id == 38) {
+            // 删除按钮
+            handleDelete();
+        } else {
+            // 输入字符
+            handleInput(item.font);
+        }
+        updatePlateDisplay();
+        updateInputFocus();
+        // 更新键盘按钮状态
+        updateKeyboardButtonsState();
+    }
+    
+    /**
+     * 处理输入
+     */
+    private void handleInput(String value) {
+        if (currentInputIndex < 0 || currentInputIndex >= 8) return;
+        
+        if (currentInputIndex == 7) {
+            // 第8个位置:允许输入字符
+            plateData[currentInputIndex] = value;
+            // 输入后失去聚焦并隐藏键盘
+            currentInputIndex = -1;  // 设置为无效值,表示失去聚焦
+            hideKeyboard();
+        } else {
+            plateData[currentInputIndex] = value;
+            // 自动移动到下一个输入框
+            if (currentInputIndex < 6) {
+                currentInputIndex++;
+                // 根据位置决定显示哪个键盘
+                if (currentInputIndex == 0) {
+                    showChineseKeyboard();
+                } else if (currentInputIndex == 7) {
+                    // 第8个位置,显示英文键盘
+                    showEnglishKeyboard();
+                } else {
+                    showEnglishKeyboard();
+                }
+            } else if (currentInputIndex == 6) {
+                // 第7个字符输入后,隐藏键盘,不聚焦到第8个位置
+                currentInputIndex = -1;  // 设置为无效值,表示失去聚焦
+                hideKeyboard();
+            }
+        }
+    }
+    
+    /**
+     * 处理删除
+     */
+    private void handleDelete() {
+        if (currentInputIndex == 0) {
+            // 删除省份
+            plateData[0] = "";
+        } else if (currentInputIndex > 0 && currentInputIndex < 7) {
+            // 删除当前字符,并移动到前一个输入框
+            plateData[currentInputIndex] = "";
+            currentInputIndex--;
+            // 根据位置决定显示哪个键盘
+            if (currentInputIndex == 0) {
+                showChineseKeyboard();
+            } else if (currentInputIndex > 0) {
+                showEnglishKeyboard();
+            }
+        } else if (currentInputIndex == 7) {
+            // 第8个位置:删除字符,如果为空则移动到前一个位置
+            if (plateData[7] != null && !plateData[7].isEmpty()) {
+                plateData[7] = "";
+            } else {
+                // 如果已经为空,移动到前一个位置
+                currentInputIndex = 6;
+                showEnglishKeyboard();
+            }
+        }
+    }
+    
+    /**
+     * 切换新能源
+     */
+    private void toggleNewEnergy() {
+        isNewEnergy = !isNewEnergy;
+        if (isNewEnergy) {
+            plateData[7] = "";
+        } else {
+            plateData[7] = "新能源";
+        }
+        hideKeyboard();
+    }
+    
+    /**
+     * 更新输入框焦点样式
+     */
+    private void updateInputFocus() {
+        // 清除所有焦点样式
+        clearInputFocus();
+        
+        // 设置当前输入框焦点样式
+        if (currentInputIndex == 7) {
+            // 第8个位置:plateNewEnergy (DirectionalLayout)
+            if (plateNewEnergy != null) {
+                ShapeElement background = new ShapeElement();
+                background.setShape(ShapeElement.RECTANGLE);
+                background.setRgbColor(new RgbColor(0xFA, 0x63, 0x32));
+                background.setCornerRadius(ScreenUtil.vp2px(context, 5));
+                plateNewEnergy.setBackground(background);
+                // 聚焦后,无论有没有值,字体都是白色
+                if (newEnergyText != null) {
+                    newEnergyText.setTextColor(Color.WHITE);
+                }
+            }
+        } else {
+            // 其他位置:Text 组件
+            Text currentInput = getInputByIndex(currentInputIndex);
+            if (currentInput != null) {
+                ShapeElement background = new ShapeElement();
+                background.setShape(ShapeElement.RECTANGLE);
+                background.setRgbColor(new RgbColor(0xFA, 0x63, 0x32));
+                background.setCornerRadius(ScreenUtil.vp2px(context, 5));
+                currentInput.setBackground(background);
+                currentInput.setTextColor(Color.WHITE);
+            }
+        }
+    }
+    
+    /**
+     * 清除所有输入框焦点样式
+     */
+    private void clearInputFocus() {
+        Text[] inputs = {plateProvince, plateLetter, plateChar1, plateChar2, 
+                        plateChar3, plateChar4, plateChar5};
+        for (Text input : inputs) {
+            if (input != null) {
+                ShapeElement background = new ShapeElement();
+                background.setShape(ShapeElement.RECTANGLE);
+                background.setRgbColor(new RgbColor(0xE2, 0xE2, 0xE2));
+                background.setCornerRadius(ScreenUtil.vp2px(context, 5));
+                input.setBackground(background);
+                input.setTextColor(new Color(0xFF333333));
+            }
+        }
+        // 清除第8个位置的焦点样式
+        if (plateNewEnergy != null) {
+            ShapeElement background = new ShapeElement();
+            background.setShape(ShapeElement.RECTANGLE);
+            background.setRgbColor(new RgbColor(0xE2, 0xE2, 0xE2));
+            background.setCornerRadius(ScreenUtil.vp2px(context, 5));
+            plateNewEnergy.setBackground(background);
+        }
+    }
+    
+    /**
+     * 根据索引获取输入框
+     */
+    private Text getInputByIndex(int index) {
+        switch (index) {
+            case 0: return plateProvince;
+            case 1: return plateLetter;
+            case 2: return plateChar1;
+            case 3: return plateChar2;
+            case 4: return plateChar3;
+            case 5: return plateChar4;
+            case 6: return plateChar5;
+            default: return null;
+        }
+    }
+    
+    /**
+     * 隐藏键盘
+     */
+    private void hideKeyboard() {
+        if (keyboardContainer != null) {
+            keyboardContainer.setVisibility(HIDE);
+        }
+        if (chineseKeyboardLayout != null) {
+            chineseKeyboardLayout.setVisibility(HIDE);
+        }
+        if (englishKeyboardLayout != null) {
+            englishKeyboardLayout.setVisibility(HIDE);
+        }
+    }
+    
+    /**
+     * 获取车牌号
+     */
+    private String getLicensePlate() {
+        if (plateType == 1) {
+            // 特殊车牌
+            if (specialPlateInput != null) {
+                return specialPlateInput.getText();
+            }
+            return "";
+        } else {
+            // 常规车牌
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < 7; i++) {
+                if (plateData[i] != null && !plateData[i].isEmpty()) {
+                    sb.append(plateData[i]);
+                }
+            }
+            return sb.toString();
+        }
+    }
+    
+    /**
+     * 设置确认监听器
+     */
+    public void setOnConfirmListener(OnConfirmListener listener) {
+        this.confirmListener = listener;
+    }
+}
+

+ 11 - 0
entry/src/main/java/com/fujica/abk/utils/Log.java

@@ -10,6 +10,17 @@ public class Log {
     public static void error(String message) {
         HiLog.error(TAG, message);
     }
+
+    public static void error(Exception e) {
+        HiLog.error(TAG, e.getMessage() != null ? e.getMessage() : e.toString());
+        e.printStackTrace();
+    }
+
+    public static void error(Throwable e) {
+        HiLog.error(TAG, e.getMessage() != null ? e.getMessage() : e.toString());
+        e.printStackTrace();
+    }
+
     public static void info(String message) {
         HiLog.info(TAG, message);
     }

+ 59 - 0
entry/src/main/java/com/fujica/abk/utils/ScreenUtil.java

@@ -23,5 +23,64 @@ public class ScreenUtil {
     public static int getScreenHeight(Context context) {
         return DisplayManager.getInstance().getDefaultDisplay(context).get().getAttributes().height;
     }
+
+    private static float densityPixels = -1;
+
+    /**
+     * 获取屏幕密度比例
+     * HarmonyOS 中标准密度为 160 dpi
+     * 对于 360 dpi 的屏幕,密度比例为 360/160 = 2.25
+     *
+     * @param context Context
+     * @return density ratio (densityPixels / 160)
+     */
+    public static float getDensity(Context context) {
+        if (densityPixels != -1) {
+            return densityPixels;
+        }
+        try {
+            densityPixels = DisplayManager.getInstance()
+                    .getDefaultDisplay(context)
+                    .get()
+                    .getAttributes()
+                    .densityPixels;
+            // HarmonyOS 标准密度为 160 dpi
+            // 1 vp = densityPixels / 160 px
+        } catch (Exception e) {
+            // 如果获取失败,使用默认密度比例 2.25 (对应 360 dpi)
+            densityPixels = 2.25f;
+        }
+        return densityPixels;
+    }
+
+    /**
+     * 将 fp 转换为 px(字体像素单位)
+     * fp 会随系统字体大小设置而变化,这里简化处理使用与 vp 相同的转换方式
+     *
+     * @param context Context
+     * @param fpValue fp value
+     * @return px value
+     */
+    public static int fp2px(Context context, float fpValue) {
+        float density = getDensity(context);
+        // fp 需要考虑字体缩放,这里简化处理,使用与 vp 相同的转换方式
+        // 实际应用中,fp 还需要考虑系统字体大小设置
+        return (int) (fpValue * density + 0.5f);
+    }
+
+    /**
+     * 将 vp 转换为 px(虚拟像素单位)
+     * HarmonyOS 中标准密度为 160 dpi,1 vp = densityPixels / 160 px
+     * 对于 360 dpi 屏幕:1 vp = 360 / 160 = 2.25 px
+     *
+     * @param context Context
+     * @param vpValue vp value
+     * @return px value
+     */
+    public static int vp2px(Context context, float vpValue) {
+        float density = getDensity(context);
+        // 1 vp = densityPixels / 160 px
+        return (int) (vpValue * density + 0.5f);
+    }
 }
 

+ 136 - 146
entry/src/main/java/com/fujica/abk/utils/api.java

@@ -2,14 +2,17 @@ package com.fujica.abk.utils;
 
 import com.fujica.abk.api.cache;
 import com.fujica.abk.common.EventBus;
+import com.fujica.abk.model.response.Page;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import ohos.app.Context;
-import ohos.utils.zson.ZSONObject;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.lang.reflect.Type;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLEncoder;
@@ -21,16 +24,19 @@ import java.util.concurrent.CompletableFuture;
  * HarmonyOS Java API7 版本
  */
 public class api {
+    // Gson 实例,用于 JSON 序列化和反序列化
+    private static final Gson gson = new Gson();
+
     // 后端gateway连接
     // private static String host = "http://192.168.12.139:10004/mobile";   //中台服务
     // private static String host = "http://192.168.12.139:10001/transfer/mobile";  //本机网关
 //    private static String host = "http://192.168.12.139:10004/mobile";  // 本机中转
 
-    private static String host = "https://gatewayservicev2dev.fujica.com.cn/transfer/mobile"; //UAT环境
+//    private static String host = "https://gatewayservicev2dev.fujica.com.cn/transfer/mobile"; //UAT环境
     // private static String host = "https://gatewayservicev2test.fujica.com.cn/transfer/mobile"; //PRE环境
 
     // 前端nginx连接
-//     private static String host = "https://fsabk.fujica.com.cn/api"; //正式环境
+    private static String host = "https://fsabk.fujica.com.cn/api"; //正式环境
     // private static String host = "https://pre-fsh5.fujica.com.cn"; //测试环境
 
     /**
@@ -81,37 +87,45 @@ public class api {
     private static String objectToJson(Object data) {
         if (data instanceof String) {
             return (String) data;
-        } else if (data instanceof Map) {
-            ZSONObject jsonObj = new ZSONObject((Map<String, Object>) data);
-            return ZSONObject.toZSONString(jsonObj);
         } else {
-            // 对于其他对象,尝试使用反射或直接toString
-            // 这里简化处理,实际项目中可能需要更复杂的序列化
-            return data != null ? data.toString() : "{}";
+            // 使用 Gson 将对象序列化为 JSON 字符串
+            return gson.toJson(data);
         }
     }
 
     /**
      * 从JSON字符串解析为R对象
+     * 使用 Gson 直接解析泛型对象,自动映射字段
+     *
+     * @param jsonStr   JSON 字符串
+     * @param dataClass data 字段的类型,如果为 null 则按 Object 类型解析
+     * @return 解析后的 R 对象,data 字段为指定类型 T
      */
     @SuppressWarnings("unchecked")
-    private static <T> R<T> parseResponse(String jsonStr) {
+    private static <T> R<T> parseResponse(String jsonStr, TypeToken<T> dataClass) {
         try {
-            ZSONObject jsonObj = ZSONObject.stringToZSON(jsonStr);
-            R<T> result = new R<>();
-            if (jsonObj.containsKey("success")) {
-                result.setSuccess(jsonObj.getBooleanValue("success"));
-            }
-            if (jsonObj.containsKey("msg")) {
-                result.setMsg(jsonObj.getString("msg"));
-            }
-            if (jsonObj.containsKey("code")) {
-                result.setCode(jsonObj.getIntValue("code"));
+
+            // 先解析为 R<Object> 获取基本结构
+            Type objectType = new TypeToken<R<Object>>() {
+            }.getType();
+            R<Object> tempResult = gson.fromJson(jsonStr, objectType);
+
+            if (tempResult == null) {
+                return null;
             }
-            if (jsonObj.containsKey("data")) {
-                // data字段可能是任意类型,这里直接设置为Object
-                // 如果需要特定类型,调用方需要自己转换
-                result.setData((T) jsonObj.get("data"));
+
+            // 创建结果对象
+            R<T> result = new R<>();
+            result.setSuccess(tempResult.isSuccess());
+            result.setMsg(tempResult.getMsg());
+            result.setCode(tempResult.getCode());
+
+            // 处理 data 字段:如果是 LinkedTreeMap,转换为目标类型
+            if (tempResult.getData() != null) {
+                // 将 LinkedTreeMap 或其他类型转换为目标类型
+                String dataJson = gson.toJson(tempResult.getData());
+                T convertedData = gson.fromJson(dataJson, dataClass);
+                result.setData(convertedData);
             }
 
             return result;
@@ -122,10 +136,10 @@ public class api {
     }
 
     /**
-     * HTTP请求核心方法
+     * HTTP请求核心方法(带类型参数)
      */
     public static <T> CompletableFuture<R<T>> http(Context context, String url, String method,
-                                                   Object data, Boolean failToast, Boolean hideLoading) {
+                                                   Object data, Boolean failToast, Boolean hideLoading, TypeToken<T> dataClass) {
         Log.error("请求:" + url);
         if (failToast == null) {
             failToast = true;
@@ -198,7 +212,7 @@ public class api {
 
                         String resultStr = response.toString();
                         Log.error("响应:" + resultStr);
-                        result = parseResponse(resultStr);
+                        result = parseResponse(resultStr, dataClass);
 
                         if (result != null && !result.isSuccess() && _failToast) {
                             String errorMsg = result.getMsg() != null ? result.getMsg() : "操作失败" + result.getCode();
@@ -243,159 +257,135 @@ public class api {
     }
 
     /**
-     * DELETE请求
+     * DELETE请求(带类型参数)
      */
-    public static <T> CompletableFuture<R<T>> del(Context context, String url, Object data) {
-        return http(context, url, "DELETE", data, null, null);
+    public static <T> CompletableFuture<R<T>> del(Context context, String url, Object data, TypeToken<T> dataClass) {
+        return http(context, url, "DELETE", data, null, null, dataClass);
     }
 
     /**
-     * POST请求
+     * POST请求(带类型参数)
      */
-    public static <T> CompletableFuture<R<T>> post(Context context, String url, Object data) {
-        return http(context, url, "POST", data, null, null);
+    public static <T> CompletableFuture<R<T>> post(Context context, String url, Object data, TypeToken<T> dataClass) {
+        return http(context, url, "POST", data, null, null, dataClass);
     }
 
     /**
-     * POST请求(带选项)
+     * POST请求(带选项和类型参数
      */
-    public static <T> CompletableFuture<R<T>> post1(Context context, ApiOption option) {
-        return http(context, option.getUrl(), "POST", option.getData(), option.getToast(), option.getHideLoading());
+    public static <T> CompletableFuture<R<T>> post1(Context context, ApiOption option, TypeToken<T> dataClass) {
+        return http(context, option.getUrl(), "POST", option.getData(), option.getToast(), option.getHideLoading(), dataClass);
     }
 
     /**
-     * GET请求(带选项)
+     * GET请求(带选项和类型参数
      */
-    public static <T> CompletableFuture<R<T>> get1(Context context, ApiOption option) {
-        return http(context, option.getUrl(), "GET", option.getData(), option.getToast(), option.getHideLoading());
+    public static <T> CompletableFuture<R<T>> get1(Context context, ApiOption option, TypeToken<T> dataClass) {
+        return http(context, option.getUrl(), "GET", option.getData(), option.getToast(), option.getHideLoading(), dataClass);
     }
 
-
     /**
-     * PUT请求(带选项)
+     * PUT请求(带选项和类型参数
      */
-    public static <T> CompletableFuture<R<T>> put1(Context context, ApiOption option) {
-        return http(context, option.getUrl(), "PUT", option.getData(), option.getToast(), option.getHideLoading());
+    public static <T> CompletableFuture<R<T>> put1(Context context, ApiOption option, TypeToken<T> dataClass) {
+        return http(context, option.getUrl(), "PUT", option.getData(), option.getToast(), option.getHideLoading(), dataClass);
     }
 
     /**
-     * 文件上传
+     * 模拟查询停车费用API
+     *
+     * @param context      上下文
+     * @param licensePlate 车牌号
+     * @return 停车费用信息
      */
-    public static <T> CompletableFuture<R<T>> upload(Context context, String url, String imageUri) {
-        url = url.startsWith("http") ? url : host + url;
-        Log.info("请求" + url);
-        String token = cache.getToken(context);
-
-        // 显示Loading(上传默认显示loading)
-//        LoadingDialog.show(context);
-
-        String finalUrl = url;
+    public static CompletableFuture<R<ParkingFeeInfo>> queryParkingFee(Context context, String licensePlate) {
         return CompletableFuture.supplyAsync(() -> {
-            HttpURLConnection connection = null;
             try {
-                URL requestUrl = new URL(finalUrl);
-                connection = (HttpURLConnection) requestUrl.openConnection();
-
-                // 设置请求方法
-                connection.setRequestMethod("POST");
-
-                // 设置请求头
-                String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
-                connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
-                connection.setRequestProperty("Connection", "keep-alive");
-                connection.setRequestProperty("token", token);
-                connection.setDoOutput(true);
-
-                // 构建multipart/form-data请求体
-                OutputStream os = connection.getOutputStream();
-                java.io.File file = new java.io.File(imageUri);
-                if (file.exists()) {
-                    // 写入文件部分
-                    os.write(("--" + boundary + "\r\n").getBytes("UTF-8"));
-                    os.write(("Content-Disposition: form-data; name=\"file\"; filename=\"file.jpg\"\r\n").getBytes("UTF-8"));
-                    os.write(("Content-Type: image/jpg\r\n\r\n").getBytes("UTF-8"));
-
-                    // 读取并写入文件内容
-                    java.io.FileInputStream fis = new java.io.FileInputStream(file);
-                    byte[] buffer = new byte[8192];
-                    int bytesRead;
-                    while ((bytesRead = fis.read(buffer)) != -1) {
-                        os.write(buffer, 0, bytesRead);
-                    }
-                    fis.close();
-
-                    // 结束multipart
-                    os.write(("\r\n--" + boundary + "--\r\n").getBytes("UTF-8"));
-                }
-                os.flush();
-                os.close();
+                // 模拟网络延迟
+                Thread.sleep(500);
+
+                // 模拟返回数据
+                ParkingFeeInfo feeInfo = new ParkingFeeInfo();
+                feeInfo.setLicensePlate(licensePlate);
+                feeInfo.setParkingLotName("认证后查看车场名称");
+                feeInfo.setParkingDays(48);
+                feeInfo.setParkingHours(20);
+                feeInfo.setParkingMinutes(48);
+                feeInfo.setTotalFee(490);
+
+                R<ParkingFeeInfo> result = new R<>();
+                result.setSuccess(true);
+                result.setMsg("查询成功");
+                result.setCode(200);
+                result.setData(feeInfo);
+
+                return result;
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                return new R<>("查询失败: " + e.getMessage());
+            } catch (Exception e) {
+                return new R<>("查询失败: " + e.getMessage());
+            }
+        });
+    }
 
-                // 执行请求
-                int responseCode = connection.getResponseCode();
+    /**
+     * 停车费用信息类
+     */
+    public static class ParkingFeeInfo {
+        private String licensePlate;
+        private String parkingLotName;
+        private int parkingDays;
+        private int parkingHours;
+        private int parkingMinutes;
+        private int totalFee;
+
+        public String getLicensePlate() {
+            return licensePlate;
+        }
 
-                try {
-                    R<T> result;
-                    if (responseCode != 200) {
-                        String msg = "操作失败:" + responseCode;
-                        Toast.error(context, msg);
-                        result = new R<>(msg);
-                    } else {
-                        // 读取响应
-                        InputStream inputStream = connection.getInputStream();
-                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
-                        StringBuilder response = new StringBuilder();
-                        String line;
-                        while ((line = reader.readLine()) != null) {
-                            response.append(line);
-                        }
-                        reader.close();
-                        inputStream.close();
+        public void setLicensePlate(String licensePlate) {
+            this.licensePlate = licensePlate;
+        }
 
-                        String resultStr = response.toString();
-                        result = parseResponse(resultStr);
+        public String getParkingLotName() {
+            return parkingLotName;
+        }
 
-                        if (result != null && !result.isSuccess()) {
-                            String errorMsg = result.getMsg() != null ? result.getMsg() : "操作失败" + result.getCode();
-                            Toast.error(context, errorMsg);
-                        }
-                        if (result == null) {
-                            result = new R<>("解析响应失败");
-                        }
-                    }
+        public void setParkingLotName(String parkingLotName) {
+            this.parkingLotName = parkingLotName;
+        }
 
-                    // 隐藏Loading
+        public int getParkingDays() {
+            return parkingDays;
+        }
 
-                    return result;
-                } catch (Exception e) {
-                    String msg = "操作失败" + e.getMessage();
-                    Toast.error(context, msg);
-                    Log.error("响应解析错误: " + e.getMessage());
+        public void setParkingDays(int parkingDays) {
+            this.parkingDays = parkingDays;
+        }
 
-                    // 隐藏Loading
+        public int getParkingHours() {
+            return parkingHours;
+        }
 
-                    return new R<>(msg);
-                }
-            } catch (IOException e) {
-                String msg = e.getMessage() + ":" + e.getClass().getSimpleName();
-                Toast.error(context, msg);
-                Log.error("上传错误: " + e.getMessage());
+        public void setParkingHours(int parkingHours) {
+            this.parkingHours = parkingHours;
+        }
 
-                // 隐藏Loading
+        public int getParkingMinutes() {
+            return parkingMinutes;
+        }
 
-                return new R<>(msg);
-            } catch (Exception e) {
-                String msg = "操作失败" + e.getMessage();
-                Toast.error(context, msg);
-                Log.error("上传异常: " + e.getMessage());
+        public void setParkingMinutes(int parkingMinutes) {
+            this.parkingMinutes = parkingMinutes;
+        }
 
-                // 隐藏Loading
+        public int getTotalFee() {
+            return totalFee;
+        }
 
-                return new R<>(msg);
-            } finally {
-                if (connection != null) {
-                    connection.disconnect();
-                }
-            }
-        });
+        public void setTotalFee(int totalFee) {
+            this.totalFee = totalFee;
+        }
     }
 }

+ 10 - 0
entry/src/main/resources/base/graphic/background_filter_item.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:ohos="http://schemas.huawei.com/res/ohos"
+    ohos:shape="rectangle">
+    <corners
+        ohos:radius="5"/>
+    <solid
+        ohos:color="#FFFFFF"/>
+</shape>
+

+ 10 - 0
entry/src/main/resources/base/graphic/button.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:ohos="http://schemas.huawei.com/res/ohos"
+    ohos:shape="rectangle">
+    <corners
+        ohos:radius="24vp"/>
+    <solid
+        ohos:color="#FA6332"/>
+</shape>
+

+ 10 - 0
entry/src/main/resources/base/graphic/button_cancel.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:ohos="http://schemas.huawei.com/res/ohos"
+    ohos:shape="rectangle">
+    <corners
+        ohos:radius="24vp"/>
+    <solid
+        ohos:color="#CCC"/>
+</shape>
+

+ 7 - 0
entry/src/main/resources/base/graphic/container_body.xml

@@ -2,6 +2,13 @@
 <shape
     xmlns:ohos="http://schemas.huawei.com/res/ohos"
     ohos:shape="rectangle">
+    <corners
+        ohos:left_top_x="0"
+        ohos:right_top_x="0"
+        ohos:radius="10vp"/>
+
+    <solid
+        ohos:color="#FFFFFFFF"/>
     <stroke
         ohos:width="1vp"
         ohos:color="#FFEFEFEF"/>

+ 3 - 4
entry/src/main/resources/base/graphic/container_bottom.xml

@@ -3,10 +3,9 @@
     xmlns:ohos="http://schemas.huawei.com/res/ohos"
     ohos:shape="rectangle">
     <corners
-        ohos:left_top_x="0"
-        ohos:right_top_x="0"
-        ohos:radius="12vp"/>
-
+        ohos:radius="10vp"/>
+    <solid
+        ohos:color="#FFFFFFFF"/>
     <stroke
         ohos:width="1vp"
         ohos:color="#FFEFEFEF"

+ 1 - 1
entry/src/main/resources/base/graphic/container_top.xml

@@ -5,7 +5,7 @@
     <corners
         ohos:left_bottom_x="0"
         ohos:right_bottom_x="0"
-        ohos:radius="12vp"/>
+        ohos:radius="10vp"/>
     <solid
         ohos:color="#FA6332"/>
 </shape>

+ 156 - 154
entry/src/main/resources/base/layout/ability_main.xml

@@ -14,11 +14,10 @@
 
     <!-- 主内容区域 - 垂直布局 -->
     <DirectionalLayout
-        ohos:margin="10vp"
         ohos:id="$+id:main_content"
         ohos:height="match_parent"
         ohos:width="400vp"
-        ohos:background_element="#FFFFFFFF"
+        ohos:margin="10vp"
         ohos:orientation="vertical">
 
         <DirectionalLayout
@@ -32,18 +31,19 @@
             ohos:start_padding="16vp">
 
             <DirectionalLayout
-                ohos:layout_alignment="center"
                 ohos:height="match_content"
                 ohos:width="match_content"
                 ohos:alignment="center"
+                ohos:layout_alignment="center"
                 ohos:orientation="horizontal">
 
-                <Image ohos:image_src="$media:logo_white"
-                       ohos:width="25vp"
-                       ohos:height="25vp"
-                       ohos:right_margin="10vp"
-                       ohos:scale_mode="stretch"
-                       ></Image>
+                <Image
+                    ohos:height="25vp"
+                    ohos:width="25vp"
+                    ohos:image_src="$media:logo_white"
+                    ohos:right_margin="10vp"
+                    ohos:scale_mode="stretch"
+                    ></Image>
 
                 <!-- 标题文字 -->
                 <Text
@@ -52,14 +52,15 @@
                     ohos:width="match_content"
                     ohos:layout_alignment="vertical_center"
                     ohos:text="爱泊客.停车缴费"
-                    ohos:text_weight="600"
                     ohos:text_color="#FFFFFFFF"
-                    ohos:text_size="14fp"/>
+                    ohos:text_size="14fp"
+                    ohos:text_weight="600"/>
             </DirectionalLayout>
         </DirectionalLayout>
 
         <!-- 页面滑动容器 -->
         <DirectionalLayout
+            ohos:bottom_padding="10vp"
             ohos:height="0vp"
             ohos:width="match_parent"
             ohos:background_element="$graphic:container_body"
@@ -76,156 +77,157 @@
         <!-- 底部导航栏 -->
         <DirectionalLayout
             ohos:height="64vp"
-            ohos:width="match_parent">
+            ohos:width="match_parent"
+            ohos:background_element="$graphic:container_bottom"
+            ohos:bottom_padding="8vp"
+            ohos:orientation="horizontal"
+            ohos:top_margin="8vp"
+            ohos:top_padding="8vp">
+
+            <!-- 找车位 -->
+            <DirectionalLayout
+                ohos:id="$+id:nav_find_parking"
+                ohos:height="match_parent"
+                ohos:width="0vp"
+                ohos:alignment="center"
+                ohos:orientation="vertical"
+                ohos:weight="1">
+
+                <Image
+                    ohos:id="$+id:icon_park"
+                    ohos:height="24vp"
+                    ohos:width="24vp"
+                    ohos:bottom_margin="4vp"
+                    ohos:image_src="$media:park"
+                    ohos:scale_mode="stretch"
+                    ohos:visibility="hide"/>
+
+                <Image
+                    ohos:id="$+id:icon_park_1"
+                    ohos:height="24vp"
+                    ohos:width="24vp"
+                    ohos:bottom_margin="4vp"
+                    ohos:image_src="$media:park_1"
+                    ohos:scale_mode="stretch"/>
+
+                <Text
+                    ohos:id="$+id:text_park"
+                    ohos:height="match_content"
+                    ohos:width="match_content"
+                    ohos:text="找车位"
+                    ohos:text_color="#FA6332"
+                    ohos:text_size="12fp"/>
+            </DirectionalLayout>
+
+            <!-- 我的 -->
+            <DirectionalLayout
+                ohos:id="$+id:nav_my"
+                ohos:height="match_parent"
+                ohos:width="0vp"
+                ohos:alignment="center"
+                ohos:orientation="vertical"
+                ohos:weight="1">
+
+                <Image
+                    ohos:id="$+id:icon_my"
+                    ohos:height="24vp"
+                    ohos:width="24vp"
+                    ohos:bottom_margin="4vp"
+                    ohos:image_src="$media:my"
+                    ohos:scale_mode="stretch"/>
+
+                <Image
+                    ohos:id="$+id:icon_my_1"
+                    ohos:height="24vp"
+                    ohos:width="24vp"
+                    ohos:bottom_margin="4vp"
+                    ohos:image_src="$media:my_1"
+                    ohos:scale_mode="stretch"
+                    ohos:visibility="hide"/>
+
+                <Text
+                    ohos:id="$+id:text_my"
+                    ohos:height="match_content"
+                    ohos:width="match_content"
+                    ohos:text="缴费"
+                    ohos:text_color="#FF666666"
+                    ohos:text_size="12fp"/>
+            </DirectionalLayout>
 
+            <!-- 预约停车 -->
             <DirectionalLayout
-                ohos:top_margin="-1vp"
-                ohos:height="64vp"
-                ohos:width="match_parent"
-                ohos:background_element="$graphic:container_bottom"
-                ohos:bottom_padding="8vp"
-                ohos:orientation="horizontal"
-                ohos:top_padding="8vp">
-
-                <!-- 找车位 -->
-                <DirectionalLayout
-                    ohos:id="$+id:nav_find_parking"
-                    ohos:height="match_parent"
-                    ohos:width="0vp"
-                    ohos:alignment="center"
-                    ohos:orientation="vertical"
-                    ohos:weight="1">
-
-                    <Image
-                        ohos:id="$+id:icon_park"
-                        ohos:height="24vp"
-                        ohos:width="24vp"
-                        ohos:scale_mode="stretch"
-                        ohos:bottom_margin="4vp"
-                        ohos:visibility="hide"
-                        ohos:image_src="$media:park"/>
-
-                    <Image
-                        ohos:id="$+id:icon_park_1"
-                        ohos:height="24vp"
-                        ohos:width="24vp"
-                        ohos:scale_mode="stretch"
-                        ohos:bottom_margin="4vp"
-                        ohos:image_src="$media:park_1"/>
-
-                    <Text
-                        ohos:id="$+id:text_park"
-                        ohos:height="match_content"
-                        ohos:width="match_content"
-                        ohos:text="找车位"
-                        ohos:text_color="#FA6332"
-                        ohos:text_size="12fp"/>
-                </DirectionalLayout>
-
-                <!-- 预约停车 -->
-                <DirectionalLayout
-                    ohos:id="$+id:nav_reserve_parking"
-                    ohos:height="match_parent"
-                    ohos:width="0vp"
-                    ohos:alignment="center"
-                    ohos:orientation="vertical"
-                    ohos:weight="1">
-
-                    <Image
-                        ohos:id="$+id:icon_fee"
-                        ohos:scale_mode="stretch"
-                        ohos:height="24vp"
-                        ohos:width="24vp"
-                        ohos:bottom_margin="4vp"
-                        ohos:image_src="$media:fee"/>
-                    <Image
-                        ohos:id="$+id:icon_fee_1"
-                        ohos:scale_mode="stretch"
-                        ohos:height="24vp"
-                        ohos:width="24vp"
-                        ohos:bottom_margin="4vp"
-                        ohos:visibility="hide"
-                        ohos:image_src="$media:fee_1"/>
-
-                    <Text
-                        ohos:id="$+id:text_fee"
-                        ohos:height="match_content"
-                        ohos:width="match_content"
-                        ohos:text="缴费记录"
-                        ohos:text_color="#FF666666"
-                        ohos:text_size="12fp"/>
-                </DirectionalLayout>
-
-
-                <!-- 我的 -->
-                <DirectionalLayout
-                    ohos:id="$+id:nav_my"
-                    ohos:height="match_parent"
-                    ohos:width="0vp"
-                    ohos:alignment="center"
-                    ohos:orientation="vertical"
-                    ohos:weight="1">
-
-                    <Image
-                        ohos:id="$+id:icon_my"
-                        ohos:height="24vp"
-                        ohos:width="24vp"
-                        ohos:scale_mode="stretch"
-                        ohos:bottom_margin="4vp"
-                        ohos:image_src="$media:my"/>
-
-                    <Image
-                        ohos:id="$+id:icon_my_1"
-                        ohos:height="24vp"
-                        ohos:width="24vp"
-                        ohos:scale_mode="stretch"
-                        ohos:bottom_margin="4vp"
-                        ohos:visibility="hide"
-                        ohos:image_src="$media:my_1"/>
-
-                    <Text
-                        ohos:id="$+id:text_my"
-                        ohos:height="match_content"
-                        ohos:width="match_content"
-                        ohos:text="我的"
-                        ohos:text_color="#FF666666"
-                        ohos:text_size="12fp"/>
-                </DirectionalLayout>
-
-                <!-- 当前位置 -->
-                <DirectionalLayout
-                    ohos:id="$+id:nav_current_location"
-                    ohos:height="match_parent"
-                    ohos:width="0vp"
-                    ohos:alignment="center"
-                    ohos:orientation="vertical"
-                    ohos:weight="1">
-
-                    <Image
-                        ohos:id="$+id:icon_current_location"
-                        ohos:scale_mode="stretch"
-                        ohos:height="24vp"
-                        ohos:width="24vp"
-                        ohos:bottom_margin="4vp"
-                        ohos:image_src="$media:location"/>
-
-                    <Text
-                        ohos:id="$+id:text_current_location"
-                        ohos:height="match_content"
-                        ohos:width="match_content"
-                        ohos:text="当前位置"
-                        ohos:text_color="#FF666666"
-                        ohos:text_size="12fp"/>
-                </DirectionalLayout>
+                ohos:id="$+id:nav_reserve_parking"
+                ohos:height="match_parent"
+                ohos:width="0vp"
+                ohos:alignment="center"
+                ohos:orientation="vertical"
+                ohos:weight="1">
+
+                <Image
+                    ohos:id="$+id:icon_fee"
+                    ohos:height="24vp"
+                    ohos:width="24vp"
+                    ohos:bottom_margin="4vp"
+                    ohos:image_src="$media:fee"
+                    ohos:scale_mode="stretch"/>
+
+                <Image
+                    ohos:id="$+id:icon_fee_1"
+                    ohos:height="24vp"
+                    ohos:width="24vp"
+                    ohos:bottom_margin="4vp"
+                    ohos:image_src="$media:fee_1"
+                    ohos:scale_mode="stretch"
+                    ohos:visibility="hide"/>
+
+                <Text
+                    ohos:id="$+id:text_fee"
+                    ohos:height="match_content"
+                    ohos:width="match_content"
+                    ohos:text="缴费记录"
+                    ohos:text_color="#FF666666"
+                    ohos:text_size="12fp"/>
+            </DirectionalLayout>
+
+            <!-- 当前位置 -->
+            <DirectionalLayout
+                ohos:id="$+id:nav_current_location"
+                ohos:height="match_parent"
+                ohos:width="0vp"
+                ohos:alignment="center"
+                ohos:orientation="vertical"
+                ohos:weight="1">
+
+                <Image
+                    ohos:id="$+id:icon_current_location"
+                    ohos:height="24vp"
+                    ohos:width="24vp"
+                    ohos:bottom_margin="4vp"
+                    ohos:image_src="$media:location"
+                    ohos:scale_mode="stretch"/>
+
+                <Text
+                    ohos:id="$+id:text_current_location"
+                    ohos:height="match_content"
+                    ohos:width="match_content"
+                    ohos:text="当前位置"
+                    ohos:text_color="#FF666666"
+                    ohos:text_size="12fp"/>
             </DirectionalLayout>
         </DirectionalLayout>
 
-        <Button ohos:width="match_parent" ohos:visibility="hide" ohos:height="60vp" ohos:id="$+id:btn_hwid_sign_in" ohos:text="华为账号登录" ohos:layout_alignment="right|horizontal_center"  ></Button>
+        <Button
+            ohos:id="$+id:btn_hwid_sign_in"
+            ohos:height="60vp"
+            ohos:width="match_parent"
+            ohos:layout_alignment="right|horizontal_center"
+            ohos:text="华为账号登录"
+            ohos:visibility="hide"></Button>
     </DirectionalLayout>
 
     <!-- Loading组件放在最后,确保在最上层显示 -->
-    <com.fujica.abk.utils.LoadingComponent 
+    <com.fujica.abk.component.LoadingComponent
         ohos:id="$+id:loading_component"
-        ohos:width="match_parent" 
-        ohos:height="match_parent" />
+        ohos:height="match_parent"
+        ohos:width="match_parent"/>
 </StackLayout>

+ 49 - 36
entry/src/main/resources/base/layout/item_parking.xml

@@ -3,10 +3,10 @@
     xmlns:ohos="http://schemas.huawei.com/res/ohos"
     ohos:height="match_content"
     ohos:width="match_parent"
-    ohos:orientation="vertical"
     ohos:left_padding="16vp"
-    ohos:right_padding="16vp"
-    ohos:top_padding="16vp"
+    ohos:orientation="vertical"
+    ohos:right_padding="8vp"
+    ohos:top_padding="8vp"
     >
 
 
@@ -26,22 +26,20 @@
             <DirectionalLayout
                 ohos:height="match_content"
                 ohos:width="match_parent"
-                ohos:alignment="center"
-                ohos:bottom_margin="8vp"
+                ohos:alignment="left"
                 ohos:orientation="horizontal">
 
                 <Text
                     ohos:id="$+id:parking_name"
                     ohos:height="match_content"
-                    ohos:width="0vp"
-                    ohos:end_margin="8vp"
+                    ohos:width="match_content"
                     ohos:text="停车场名称"
-                    ohos:text_color="#FF000000"
-                    ohos:text_size="16fp"
-                    ohos:weight="1"/>
+                    ohos:text_color="#333333"
+                    ohos:text_size="16fp"/>
 
                 <!-- 标签容器 -->
                 <DirectionalLayout
+                    ohos:left_margin="20vp"
                     ohos:id="$+id:tags_container"
                     ohos:height="match_content"
                     ohos:width="match_content"
@@ -50,29 +48,43 @@
             </DirectionalLayout>
 
             <!-- 距离和地址 -->
-            <Text
-                ohos:id="$+id:parking_address"
+            <DirectionalLayout
                 ohos:height="match_content"
-                ohos:width="match_parent"
-                ohos:bottom_margin="8vp"
-                ohos:text="0.8km | 地址信息"
-                ohos:text_color="#FF666666"
-                ohos:text_size="12fp"/>
+                ohos:width="match_content"
+                ohos:orientation="horizontal">
+
+                <Text
+                    ohos:id="$+id:parking_address_1"
+                    ohos:height="match_content"
+                    ohos:width="match_parent"
+                    ohos:bottom_margin="8vp"
+                    ohos:text="0.8km"
+                    ohos:text_color="#FA6332"
+                    ohos:text_size="12fp"/>
+
+                <Text
+                    ohos:id="$+id:parking_address_2"
+                    ohos:height="match_content"
+                    ohos:width="match_parent"
+                    ohos:bottom_margin="8vp"
+                    ohos:text="地址信息"
+                    ohos:text_color="#999999"
+                    ohos:text_size="12fp"/>
+            </DirectionalLayout>
 
             <!-- 统计信息:总车位、剩余车位、免费时长 -->
             <DirectionalLayout
                 ohos:height="match_content"
                 ohos:width="match_parent"
-                ohos:alignment="center"
+                ohos:alignment="left"
                 ohos:orientation="horizontal">
 
                 <!-- 总车位 -->
                 <DirectionalLayout
                     ohos:height="match_content"
-                    ohos:width="0vp"
+                    ohos:width="match_content"
                     ohos:alignment="center"
-                    ohos:orientation="vertical"
-                    ohos:weight="1">
+                    ohos:orientation="vertical">
 
                     <Text
                         ohos:id="$+id:text_total_place"
@@ -80,7 +92,7 @@
                         ohos:width="match_content"
                         ohos:text="2000"
                         ohos:text_alignment="center"
-                        ohos:text_color="#FF000000"
+                        ohos:text_color="#333333"
                         ohos:text_size="14fp"/>
 
                     <Text
@@ -88,17 +100,17 @@
                         ohos:width="match_content"
                         ohos:text="总车位"
                         ohos:text_alignment="center"
-                        ohos:text_color="#FF666666"
+                        ohos:text_color="#999999"
                         ohos:text_size="12fp"/>
                 </DirectionalLayout>
 
                 <!-- 剩余车位 -->
                 <DirectionalLayout
                     ohos:height="match_content"
-                    ohos:width="0vp"
+                    ohos:width="match_content"
                     ohos:alignment="center"
-                    ohos:orientation="vertical"
-                    ohos:weight="1">
+                    ohos:left_margin="20vp"
+                    ohos:orientation="vertical">
 
                     <Text
                         ohos:id="$+id:text_residue_place"
@@ -106,7 +118,7 @@
                         ohos:width="match_content"
                         ohos:text="50"
                         ohos:text_alignment="center"
-                        ohos:text_color="#FA6332"
+                        ohos:text_color="#FF7800"
                         ohos:text_size="14fp"/>
 
                     <Text
@@ -114,17 +126,17 @@
                         ohos:width="match_content"
                         ohos:text="剩余车位"
                         ohos:text_alignment="center"
-                        ohos:text_color="#FF666666"
+                        ohos:text_color="#999999"
                         ohos:text_size="12fp"/>
                 </DirectionalLayout>
 
                 <!-- 免费时长 -->
                 <DirectionalLayout
                     ohos:height="match_content"
-                    ohos:width="0vp"
+                    ohos:width="match_content"
                     ohos:alignment="center"
-                    ohos:orientation="vertical"
-                    ohos:weight="1">
+                    ohos:left_margin="20vp"
+                    ohos:orientation="vertical">
 
                     <Text
                         ohos:id="$+id:text_free_duration"
@@ -132,7 +144,7 @@
                         ohos:width="match_content"
                         ohos:text="15分"
                         ohos:text_alignment="center"
-                        ohos:text_color="#FF000000"
+                        ohos:text_color="#333333"
                         ohos:text_size="14fp"/>
 
                     <Text
@@ -140,10 +152,11 @@
                         ohos:width="match_content"
                         ohos:text="免费时长"
                         ohos:text_alignment="center"
-                        ohos:text_color="#FF666666"
+                        ohos:text_color="#999999"
                         ohos:text_size="12fp"/>
                 </DirectionalLayout>
             </DirectionalLayout>
+
         </DirectionalLayout>
 
         <!-- 右侧导航按钮 -->
@@ -166,7 +179,7 @@
                 ohos:width="match_content"
                 ohos:text="导航"
                 ohos:text_alignment="center"
-                ohos:text_color="#FF000000"
+                ohos:text_color="#FA6332"
                 ohos:text_size="12fp"
                 ohos:top_margin="4vp"/>
         </DirectionalLayout>
@@ -177,8 +190,8 @@
     <DirectionalLayout
         xmlns:ohos="http://schemas.huawei.com/res/ohos"
         ohos:height="1vp"
-        ohos:top_margin="16vp"
         ohos:width="match_parent"
-        ohos:background_element="#FFE0E0E0"/>
+        ohos:background_element="#EEEEEE"
+        ohos:top_margin="16vp"/>
 </DirectionalLayout>
 

+ 74 - 14
entry/src/main/resources/base/layout/layout_find_parking.xml

@@ -3,8 +3,7 @@
     xmlns:ohos="http://schemas.huawei.com/res/ohos"
     ohos:height="match_parent"
     ohos:width="match_parent"
-    ohos:orientation="vertical"
-    ohos:background_element="#CCC">
+    ohos:orientation="vertical">
 
     <!-- 顶部查询条件区域 -->
     <DirectionalLayout
@@ -12,23 +11,85 @@
         ohos:height="match_content"
         ohos:width="match_parent"
         ohos:orientation="horizontal"
-        ohos:padding="16vp"
-        ohos:background_element="#FFFFFFFF"
-        ohos:bottom_margin="8vp">
+        ohos:top_padding="8vp"
+        ohos:left_padding="10vp"
+        ohos:bottom_padding="8vp"
+        ohos:right_padding="10vp"
+        ohos:background_element="#EFEFEF">
 
-        <!-- 距离最近下拉框 -->
-        <Button
-            ohos:id="$+id:btn_distance_sort"
+        <!-- 车场名称输入框 -->
+        <TextField
+            ohos:id="$+id:input_park_name"
             ohos:height="36vp"
-            ohos:width="match_content"
-            ohos:text="距离最近"
+            ohos:width="0"
+            ohos:weight="1"
+            ohos:hint="车场名称"
             ohos:text_size="14fp"
             ohos:text_color="#FF000000"
-            ohos:background_element="#F5F5F5"
+            ohos:hint_color="#FF999999"
+            ohos:background_element="$graphic:background_filter_item"
+            ohos:left_padding="12vp"
+            ohos:right_padding="12vp"
+            ohos:top_padding="6vp"
+            ohos:bottom_padding="6vp"
+            ohos:right_margin="8vp"/>
+
+        <!-- 距离筛选下拉框 -->
+        <DirectionalLayout
+            ohos:id="$+id:btn_distance_filter"
+            ohos:height="36vp"
+            ohos:width="match_content"
+            ohos:orientation="horizontal"
+            ohos:alignment="center"
+            ohos:background_element="$graphic:background_filter_item"
+            ohos:left_padding="12vp"
+            ohos:right_padding="12vp"
+            ohos:top_padding="6vp"
+            ohos:bottom_padding="6vp"
+            ohos:right_margin="8vp">
+            <Text
+                ohos:height="match_content"
+                ohos:width="match_content"
+                ohos:text="3km"
+                ohos:text_size="14fp"
+                ohos:text_color="#FF000000"/>
+            <Text
+                ohos:height="match_content"
+                ohos:width="match_content"
+                ohos:text="▼"
+                ohos:text_size="10fp"
+                ohos:text_color="#FF666666"
+                ohos:left_margin="4vp"/>
+        </DirectionalLayout>
+
+        <!-- 排序方式下拉框 -->
+        <DirectionalLayout
+            ohos:id="$+id:btn_distance_sort"
+            ohos:height="36vp"
+            ohos:width="match_content"
+            ohos:orientation="horizontal"
+            ohos:alignment="center"
+            ohos:background_element="$graphic:background_filter_item"
             ohos:left_padding="12vp"
             ohos:right_padding="12vp"
             ohos:top_padding="6vp"
-            ohos:bottom_padding="6vp"/>
+            ohos:bottom_padding="6vp">
+            <Text
+                ohos:height="match_content"
+                ohos:width="match_content"
+                ohos:text="距离最近"
+                ohos:text_size="14fp"
+                ohos:text_color="#FF000000"/>
+            <Text
+                ohos:height="match_content"
+                ohos:width="match_content"
+                ohos:text="▼"
+                ohos:text_size="10fp"
+                ohos:text_color="#FF666666"
+                ohos:left_margin="4vp"/>
+        </DirectionalLayout>
+
+        
     </DirectionalLayout>
 
     <!-- 停车场列表 -->
@@ -36,8 +97,7 @@
         ohos:id="$+id:parking_list_scroll"
         ohos:height="0vp"
         ohos:width="match_parent"
-        ohos:weight="1"
-        ohos:background_element="#FFFFFFFF">
+        ohos:weight="1">
 
         <DirectionalLayout
             ohos:id="$+id:parking_list_container"

+ 264 - 0
entry/src/main/resources/base/layout/layout_license_plate_dialog.xml

@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="utf-8"?>
+<DirectionalLayout
+    xmlns:ohos="http://schemas.huawei.com/res/ohos"
+    ohos:height="match_parent"
+    ohos:width="match_parent"
+    ohos:background_element="#FFFFFFFF"
+    ohos:orientation="vertical">
+
+
+    <DirectionalLayout
+        ohos:height="match_content"
+        ohos:width="match_parent"
+        ohos:alignment="center"
+        ohos:orientation="horizontal">
+
+
+        <DirectionalLayout
+            ohos:height="match_content"
+            ohos:width="500vp"
+            ohos:orientation="vertical">
+
+            <!-- 车牌输入区域 -->
+            <DirectionalLayout
+                ohos:height="80vp"
+                ohos:width="match_parent"
+                ohos:alignment="center"
+                ohos:orientation="horizontal">
+
+
+                <!-- 特殊车牌输入框(隐藏) -->
+                <TextField
+                    ohos:id="$+id:special_plate_input"
+                    ohos:height="50vp"
+                    ohos:width="350vp"
+                    ohos:background_element="#FFE2E2E2"
+                    ohos:hint="请输入完整车牌"
+                    ohos:text_size="16fp"
+                    ohos:left_padding="10vp"
+                    ohos:right_padding="10vp"
+                    ohos:visibility="hide"/>
+
+                <DirectionalLayout
+                    ohos:id="$+id:license_plate_input_area"
+                    ohos:height="match_content"
+                    ohos:width="0"
+                    ohos:alignment="center"
+                    ohos:orientation="horizontal"
+                    ohos:weight="1">
+
+                    <!-- 省份输入框 -->
+                    <Text
+                        ohos:id="$+id:plate_province"
+                        ohos:height="50vp"
+                        ohos:width="36vp"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:focusable="focus_enable"
+                        ohos:text="粤"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF333333"
+                        ohos:text_size="16fp"/>
+
+                    <!-- 字母输入框 -->
+                    <Text
+                        ohos:id="$+id:plate_letter"
+                        ohos:height="50vp"
+                        ohos:width="36vp"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:end_margin="8vp"
+                        ohos:focusable="focus_enable"
+                        ohos:start_margin="8vp"
+                        ohos:text="B"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF333333"
+                        ohos:text_size="16fp"/>
+
+                    <!-- 分隔点 -->
+                    <Text
+                        ohos:height="match_content"
+                        ohos:width="6vp"
+                        ohos:end_margin="8vp"
+                        ohos:text="·"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF999999"
+                        ohos:text_size="12fp"/>
+
+                    <!-- 5个字符输入框 -->
+                    <Text
+                        ohos:id="$+id:plate_char1"
+                        ohos:height="50vp"
+                        ohos:width="36vp"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:end_margin="4vp"
+                        ohos:focusable="focus_enable"
+                        ohos:text=""
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF333333"
+                        ohos:text_size="16fp"/>
+
+                    <Text
+                        ohos:id="$+id:plate_char2"
+                        ohos:height="50vp"
+                        ohos:width="36vp"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:end_margin="4vp"
+                        ohos:focusable="focus_enable"
+                        ohos:text=""
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF333333"
+                        ohos:text_size="16fp"/>
+
+                    <Text
+                        ohos:id="$+id:plate_char3"
+                        ohos:height="50vp"
+                        ohos:width="36vp"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:end_margin="4vp"
+                        ohos:focusable="focus_enable"
+                        ohos:text=""
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF333333"
+                        ohos:text_size="16fp"/>
+
+                    <Text
+                        ohos:id="$+id:plate_char4"
+                        ohos:height="50vp"
+                        ohos:width="36vp"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:end_margin="4vp"
+                        ohos:focusable="focus_enable"
+                        ohos:text=""
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF333333"
+                        ohos:text_size="16fp"/>
+
+                    <Text
+                        ohos:id="$+id:plate_char5"
+                        ohos:height="50vp"
+                        ohos:width="36vp"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:end_margin="8vp"
+                        ohos:focusable="focus_enable"
+                        ohos:text=""
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF333333"
+                        ohos:text_size="16fp"/>
+
+                    <!-- 新能源选项 -->
+                    <DirectionalLayout
+                        ohos:id="$+id:plate_new_energy"
+                        ohos:height="50vp"
+                        ohos:width="50vp"
+                        ohos:alignment="center"
+                        ohos:background_element="#FFE2E2E2"
+                        ohos:clickable="true"
+                        ohos:corner_radius="5vp"
+                        ohos:focusable="focus_enable"
+                        ohos:orientation="vertical"
+                        ohos:padding="4vp">
+
+                        <Text
+                            ohos:height="match_content"
+                            ohos:width="match_content"
+                            ohos:text="+"
+                            ohos:text_alignment="center"
+                            ohos:text_color="#FF999999"
+                            ohos:text_size="20fp"/>
+
+                        <Text
+                            ohos:id="$+id:new_energy_text"
+                            ohos:height="match_content"
+                            ohos:width="match_content"
+                            ohos:text="新能源"
+                            ohos:text_alignment="center"
+                            ohos:text_color="#FF999999"
+                            ohos:text_size="10fp"/>
+                    </DirectionalLayout>
+
+
+                </DirectionalLayout>
+
+            </DirectionalLayout>
+
+            <!-- 切换特殊车牌按钮 -->
+            <Text
+                ohos:id="$+id:btn_switch_special"
+                ohos:height="match_content"
+                ohos:width="match_content"
+                ohos:bottom_margin="15vp"
+                ohos:clickable="true"
+                ohos:focusable="focus_enable"
+                ohos:layout_alignment="center"
+                ohos:text="切换特殊车牌"
+                ohos:text_alignment="center"
+                ohos:text_color="#FF888888"
+                ohos:text_size="14fp"/>
+
+            <!-- 确认按钮 -->
+            <Button
+                ohos:id="$+id:btn_confirm"
+                ohos:height="48vp"
+                ohos:width="match_parent"
+                ohos:background_element="$graphic:button"
+                ohos:text="确认"
+                ohos:bottom_margin="10vp"
+                ohos:text_color="#FFFFFFFF"
+                ohos:text_size="16fp"/>
+
+        </DirectionalLayout>
+
+        <Image
+            ohos:id="$+id:btn_close"
+            ohos:top_margin="20vp"
+            ohos:layout_alignment="right|top"
+            ohos:scale_mode="stretch"
+            ohos:height="24vp"
+            ohos:width="24vp"
+            ohos:clickable="true"
+            ohos:focusable="focus_enable"
+            ohos:image_src="$media:quit"/>
+    </DirectionalLayout>
+
+
+    <!-- 键盘区域 -->
+    <DirectionalLayout
+        ohos:id="$+id:keyboard_container"
+        ohos:height="match_content"
+        ohos:width="match_parent"
+        ohos:background_element="#FFE7E7E7"
+        ohos:orientation="vertical"
+        ohos:padding="8vp"
+        ohos:top_padding="20vp"
+        ohos:visibility="hide">
+
+        <!-- 中文键盘容器 -->
+        <DirectionalLayout
+            ohos:id="$+id:chinese_keyboard"
+            ohos:height="match_parent"
+            ohos:width="match_parent"
+            ohos:orientation="vertical"/>
+
+        <!-- 英文键盘容器 -->
+        <DirectionalLayout
+            ohos:id="$+id:english_keyboard"
+            ohos:height="match_parent"
+            ohos:width="match_parent"
+            ohos:orientation="vertical"/>
+    </DirectionalLayout>
+
+</DirectionalLayout>
+

+ 138 - 27
entry/src/main/resources/base/layout/layout_my.xml

@@ -3,38 +3,149 @@
     xmlns:ohos="http://schemas.huawei.com/res/ohos"
     ohos:height="match_parent"
     ohos:width="match_parent"
-    ohos:orientation="vertical"
-    ohos:background_element="#FFFFFFFF">
+    ohos:background_element="#FFF"
+    ohos:orientation="vertical">
 
     <ScrollView
-        ohos:height="0vp"
-        ohos:width="match_parent"
-        ohos:weight="1"
-        ohos:background_element="#FFFFFFFF">
-
-        <DirectionalLayout
-            ohos:height="match_content"
-            ohos:width="match_parent"
-            ohos:orientation="vertical"
-            ohos:padding="16vp"
-            ohos:alignment="center">
-
-            <Text
+        ohos:height="match_parent"
+        ohos:width="match_parent">
+            <!-- 有车牌缓存时显示的停车信息卡片 -->
+            <DirectionalLayout
+                ohos:id="$+id:parking_info_card"
                 ohos:height="match_content"
-                ohos:width="match_content"
-                ohos:text="我的"
-                ohos:text_size="24fp"
-                ohos:text_color="#FF000000"
-                ohos:margin_top="100vp"/>
+                ohos:width="match_parent"
+                ohos:orientation="vertical"
+                ohos:background_element="#FFFFFFFF"
+                ohos:corner_radius="12vp"
+                ohos:margin="16vp"
+                ohos:padding="16vp"
+                ohos:visibility="hide">
 
-            <Text
+                <!-- 车牌号头部 -->
+                <DirectionalLayout
+                    ohos:height="match_content"
+                    ohos:width="match_parent"
+                    ohos:orientation="horizontal"
+                    ohos:alignment="center"
+                    ohos:background_element="#FFF5F5F5"
+                    ohos:corner_radius="8vp"
+                    ohos:padding="12vp"
+                    ohos:bottom_margin="16vp">
+
+                    <Text
+                        ohos:id="$+id:text_license_plate"
+                        ohos:height="match_content"
+                        ohos:width="0vp"
+                        ohos:weight="1"
+                        ohos:text="京N8P8F8"
+                        ohos:text_size="18fp"
+                        ohos:text_color="#FF000000"
+                        ohos:text_alignment="center"/>
+
+                    <Image
+                        ohos:id="$+id:img_dropdown"
+                        ohos:height="20vp"
+                        ohos:width="20vp"
+                        ohos:image_src="media:icon"
+                        ohos:start_margin="8vp"/>
+                </DirectionalLayout>
+
+                <!-- 停车信息 -->
+                <DirectionalLayout
+                    ohos:height="match_content"
+                    ohos:width="match_parent"
+                    ohos:orientation="vertical"
+                    ohos:bottom_margin="16vp">
+
+                    <DirectionalLayout
+                        ohos:height="match_content"
+                        ohos:width="match_parent"
+                        ohos:orientation="horizontal"
+                        ohos:bottom_margin="8vp">
+
+                        <Text
+                            ohos:height="match_content"
+                            ohos:width="0vp"
+                            ohos:weight="1"
+                            ohos:text="认证后查看车场名称>"
+                            ohos:text_size="14fp"
+                            ohos:text_color="#FF0066FF"
+                            ohos:text_alignment="start"/>
+
+                        <Text
+                            ohos:id="$+id:text_parking_duration"
+                            ohos:height="match_content"
+                            ohos:width="match_content"
+                            ohos:text="已停48天20小时48分"
+                            ohos:text_size="14fp"
+                            ohos:text_color="#FA6332"
+                            ohos:text_alignment="end"/>
+                    </DirectionalLayout>
+
+                    <Text
+                        ohos:id="$+id:text_total_fee"
+                        ohos:height="match_content"
+                        ohos:width="match_parent"
+                        ohos:text="¥490"
+                        ohos:text_size="32fp"
+                        ohos:text_color="#FA6332"
+                        ohos:text_alignment="center"
+                        ohos:top_margin="8vp"/>
+                </DirectionalLayout>
+
+                <!-- 立即缴费按钮 -->
+                <Button
+                    ohos:id="$+id:btn_pay_now"
+                    ohos:height="48vp"
+                    ohos:width="match_parent"
+                    ohos:text="立即缴费"
+                    ohos:text_size="16fp"
+                    ohos:text_color="#FFFFFFFF"
+                    ohos:background_element="#FA6332"
+                    ohos:corner_radius="24vp"/>
+            </DirectionalLayout>
+
+            <!-- 无车牌缓存时显示的添加车辆卡片 -->
+            <DirectionalLayout
+                ohos:layout_alignment="center"
+                ohos:id="$+id:add_vehicle_card"
                 ohos:height="match_content"
-                ohos:width="match_content"
-                ohos:text="个人中心功能开发中..."
-                ohos:text_size="16fp"
-                ohos:text_color="#FF666666"
-                ohos:margin_top="20vp"/>
-        </DirectionalLayout>
+                ohos:width="match_parent"
+                ohos:orientation="vertical"
+                ohos:alignment="center"
+                ohos:visibility="visible">
+
+                <!-- 汽车图标 -->
+                <Image
+                    ohos:id="$+id:img_car"
+                    ohos:height="40vp"
+                    ohos:width="50vp"
+                    ohos:scale_mode="stretch"
+                    ohos:image_src="$media:nocar"/>
+
+                <!-- 提示文字 -->
+                <Text
+                    ohos:top_margin="24vp"
+                    ohos:id="$+id:text_add_vehicle_tip"
+                    ohos:height="match_content"
+                    ohos:width="match_parent"
+                    ohos:text="添加车辆快捷缴费,免排队、免找零"
+                    ohos:text_size="16fp"
+                    ohos:text_color="#FF333333"
+                    ohos:text_alignment="center"/>
+
+                <!-- 输入车牌缴费按钮 -->
+                <Button
+                    ohos:margin="24vp"
+                    ohos:id="$+id:btn_input_license_plate"
+                    ohos:height="48vp"
+                    ohos:width="match_parent"
+                    ohos:text="输入车牌缴费"
+                    ohos:text_size="16fp"
+                    ohos:text_color="#FFFFFFFF"
+                    ohos:background_element="$graphic:button"/>
+            </DirectionalLayout>
+
     </ScrollView>
 </DirectionalLayout>
 

BIN
entry/src/main/resources/base/media/close.png


BIN
entry/src/main/resources/base/media/nocar.png


BIN
entry/src/main/resources/base/media/quit.png