linee 5 dienas atpakaļ
vecāks
revīzija
dad0f0b2da

+ 60 - 143
entry/src/main/java/com/fujica/abk/slice/MainAbilitySlice.java

@@ -2,9 +2,7 @@ package com.fujica.abk.slice;
 
 import com.fujica.abk.ResourceTable;
 import com.fujica.abk.api.cache;
-import com.fujica.abk.utils.Log;
-import com.fujica.abk.utils.Toast;
-import com.fujica.abk.utils.api;
+import com.fujica.abk.utils.*;
 import com.huawei.hms.accountsdk.constant.CommonConstant;
 import com.huawei.hms.accountsdk.exception.ApiException;
 import com.huawei.hms.accountsdk.support.account.AccountAuthManager;
@@ -35,7 +33,7 @@ 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 com.fujica.abk.utils.R;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
@@ -80,20 +78,25 @@ public class MainAbilitySlice extends AbilitySlice {
     private ScrollView parkingListScroll; // 停车场列表滚动视图
     private DirectionalLayout parkingListContainer; // 停车场列表容器
     private int currentPage = 1; // 当前页码
-    private int pageSize = 10; // 每页数量
+    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; // 当前选中的停车场列表项
 
     DataAbilityHelper dataAbilityHelper;
     IDataAbilityObserver dataAbilityObserver;
 
+    // Loading组件
+    private LoadingComponent loadingComponent;
+
     @Override
     public void onStart(Intent intent) {
         super.onStart(intent);
+
         try {
             //com.fujica.abk_BD8VI9k5bO0HeGAPnhTGeYX++mgKw87G8y+3RZ6nrb9evCePddojupXJN03auUKxTKn1qbFrYQAjFyGumpjsHzw=
             String appId = getApplicationContext().getBundleManager().getBundleInfo(getBundleName(), 0).getAppId();
@@ -111,6 +114,9 @@ public class MainAbilitySlice extends AbilitySlice {
         // 设置布局
         super.setUIContent(ResourceTable.Layout_ability_main);
 
+        // 初始化Loading组件并添加到根布局
+        loadingComponent = findComponentById(ResourceTable.Id_loading_component);
+
         // 初始化组件
         initComponents();
 
@@ -161,13 +167,13 @@ public class MainAbilitySlice extends AbilitySlice {
         } catch (ApiException e) {
             // 处理初始化登录授权服务失败,status code标识了失败的原因,请参考API中的错误码参考了解详细错误原因
             e.getStatusCode();
-            Toast.error(getContext(),"Init Huawei accountAuthService FAILED.");
+            Toast.error(getContext(), "Init Huawei accountAuthService FAILED.");
             return;
         }
-        Toast.info(getContext(),"Init Huawei accountAuthService SUCCESS");
+        Toast.info(getContext(), "Init Huawei accountAuthService SUCCESS");
 
         if (accountAuthService == null) {
-            Toast.error(getContext(),"获取不到账号信息");
+            Toast.error(getContext(), "获取不到账号信息");
             return;
         }
         // 调用静默登录接口。
@@ -175,43 +181,43 @@ public class MainAbilitySlice extends AbilitySlice {
         // 否则静默登录失败,需要在失败监听中,显式地调用前台登录授权接口,完成登录授权。
         Task<AuthAccount> taskSilentSignIn = accountAuthService.silentSignIn();
 //        Task<AuthAccount> taskSilentSignIn = accountAuthService.silentSignIn();
-        Toast.info(getContext(),"SilentSign START.");
+        Toast.info(getContext(), "SilentSign START.");
         // 添加静默登录成功处理监听
         taskSilentSignIn.addOnSuccessListener(authAccount -> updateUI(authAccount));
         // 添加静默登录失败监听
         taskSilentSignIn.addOnFailureListener(e -> {
             if (e instanceof ApiException) {
                 ApiException apiException = (ApiException) e;
-                Toast.error(getContext(),"SilentSignIn FAILED, status code: " + apiException.getStatusCode() + ". Need to foreground sign in" + "\r\n" + apiException.getStatusMessage()
+                Toast.error(getContext(), "SilentSignIn FAILED, status code: " + apiException.getStatusCode() + ". Need to foreground sign in" + "\r\n" + apiException.getStatusMessage()
                         + "\r\n" + apiException.getMessage() + "\r\n" + apiException.getCause());
 
                 // 静默登录失败,显式地调用前台登录授权接口,完成登录授权。
                 Task<AuthAccount> taskSignIn = accountAuthService.signIn();
-                Toast.info(getContext(),"SignIn foreground START.");
+                Toast.info(getContext(), "SignIn foreground START.");
                 if (taskSignIn == null) {
-                    Toast.info(getContext(),"SignIn foreground task is null.");
+                    Toast.info(getContext(), "SignIn foreground task is null.");
                     return;
                 }
                 taskSignIn.addOnSuccessListener(new OnSuccessListener<AuthAccount>() {
                     @Override
                     public void onSuccess(AuthAccount result) {
-                        Toast.info(getContext(),"SignIn foreground SUCCESS.");
+                        Toast.info(getContext(), "SignIn foreground SUCCESS.");
                         updateUI(result);
                     }
                 });
                 taskSignIn.addOnFailureListener(new OnFailureListener() {
                     @Override
                     public void onFailure(Exception e) {
-                        Toast.info(getContext(),"SignIn foreground FAILED.");
+                        Toast.info(getContext(), "SignIn foreground FAILED.");
                         if (e instanceof ApiException) {
                             ApiException apiException = (ApiException) e;
                             // 登录失败,status code标识了失败的原因,请参考API中的错误码参考了解详细错误原因
                             apiException.getStatusCode();
-                            Toast.info(getContext(),"SignIn foreground FAILED. status code: "
+                            Toast.info(getContext(), "SignIn foreground FAILED. status code: "
                                     + apiException.getStatusCode()
                                     + ".");
                             if (CommonConstant.RETCODE.SIGN_IN_CANCELLED == apiException.getStatusCode()) {
-                                Toast.info(getContext(),"Error message: User click CANCEL or Return, user cancel login in.");
+                                Toast.info(getContext(), "Error message: User click CANCEL or Return, user cancel login in.");
                             }
                         }
                     }
@@ -221,7 +227,7 @@ public class MainAbilitySlice extends AbilitySlice {
     }
 
     private void updateUI(AuthAccount authAccount) {
-        Toast.info(getContext(),authAccount.getOpenId() + " : " + authAccount.getUnionId());
+        Toast.info(getContext(), authAccount.getOpenId() + " : " + authAccount.getUnionId());
     }
 
 
@@ -576,38 +582,38 @@ public class MainAbilitySlice extends AbilitySlice {
                     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;
@@ -634,18 +640,20 @@ public class MainAbilitySlice extends AbilitySlice {
         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);
@@ -653,7 +661,7 @@ public class MainAbilitySlice extends AbilitySlice {
         if (tabRecommendedUnderline != null) {
             tabRecommendedUnderline.setVisibility(filter == 1 ? Component.VISIBLE : Component.HIDE);
         }
-        
+
         // 加载数据
         loadParkingData(true);
     }
@@ -698,16 +706,13 @@ public class MainAbilitySlice extends AbilitySlice {
 
         // 发送请求(网络请求已在后台线程)
         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);
-                    getUITaskDispatcher().asyncDispatch(() -> {
-                        isLoading = false;
-                        // 请求失败,保持currentPage不变,允许重试
-                    });
                     return;
                 }
 
@@ -715,9 +720,6 @@ public class MainAbilitySlice extends AbilitySlice {
                 Object dataObj = response.getData();
                 if (dataObj == null) {
                     Log.error("响应数据为空");
-                    getUITaskDispatcher().asyncDispatch(() -> {
-                        isLoading = false;
-                    });
                     return;
                 }
 
@@ -733,18 +735,12 @@ public class MainAbilitySlice extends AbilitySlice {
                 Page<ParkNearRes> page = parsePageData(pageObj);
                 if (page == null || page.getRecords() == null) {
                     Log.error("解析分页数据失败");
-                    getUITaskDispatcher().asyncDispatch(() -> {
-                        isLoading = false;
-                    });
                     return;
                 }
 
                 List<ParkNearRes> records = page.getRecords();
                 if (records.isEmpty()) {
-                    getUITaskDispatcher().asyncDispatch(() -> {
-                        isLoading = false;
-                        hasMore = false;
-                    });
+                    hasMore = false;
                     return;
                 }
 
@@ -773,18 +769,17 @@ public class MainAbilitySlice extends AbilitySlice {
 
                 // 只在UI线程更新界面
                 getUITaskDispatcher().asyncDispatch(() -> {
-                    isLoading = false;
-                    
+
                     // 检查currentPage是否已经被其他请求更新(防止旧请求覆盖新数据)
                     // 如果currentPage > requestPage,说明有更新的请求已经完成,忽略这个旧请求的结果
                     if (currentPage > requestPage) {
                         Log.info("忽略过期请求,当前页码: " + currentPage + ", 请求页码: " + requestPage);
                         return;
                     }
-                    
+
                     // 添加到列表
                     parkingList.addAll(finalRecords);
-                    
+
                     // 批量渲染列表项(减少UI更新次数,延迟批量添加)
                     if (parkingListContainer != null && !finalRecords.isEmpty()) {
                         // 先批量创建所有组件
@@ -795,7 +790,7 @@ public class MainAbilitySlice extends AbilitySlice {
                                 items.add(item);
                             }
                         }
-                        
+
                         // 批量添加到容器(减少UI重绘次数)
                         for (Component item : items) {
                             parkingListContainer.addComponent(item);
@@ -812,9 +807,9 @@ public class MainAbilitySlice extends AbilitySlice {
             } catch (Exception e) {
                 Log.error("解析停车场数据失败: " + e.getMessage());
                 e.printStackTrace();
-                getUITaskDispatcher().asyncDispatch(() -> {
-                    isLoading = false;
-                });
+            } finally {
+                isLoading = false;
+                loadingComponent.hide();
             }
         });
     }
@@ -825,7 +820,7 @@ public class MainAbilitySlice extends AbilitySlice {
     private Page<ParkNearRes> parsePageData(ZSONObject pageObj) {
         try {
             Page<ParkNearRes> page = new Page<>();
-            
+
             if (pageObj.containsKey("total")) {
                 page.setTotal(pageObj.getIntValue("total"));
             }
@@ -852,7 +847,7 @@ public class MainAbilitySlice extends AbilitySlice {
                     page.setRecords(parkList);
                 }
             }
-            
+
             return page;
         } catch (Exception e) {
             Log.error("解析Page数据失败: " + e.getMessage());
@@ -928,6 +923,7 @@ public class MainAbilitySlice extends AbilitySlice {
 
     /**
      * 创建停车场列表项组件(不添加到容器)
+     * 使用 ParkingItemComponent 组件
      */
     private Component createParkingItem(ParkNearRes park) {
         if (parkingListContainer == null) {
@@ -935,75 +931,18 @@ public class MainAbilitySlice extends AbilitySlice {
         }
 
         try {
-            // 加载列表项布局
-            Component item = LayoutScatter.getInstance(this)
-                    .parse(ResourceTable.Layout_item_parking, null, false);
-
-            // 设置停车场名称
-            Text nameText = (Text) item.findComponentById(ResourceTable.Id_parking_name);
-            if (nameText != null && park.getParkName() != null) {
-                nameText.setText(park.getParkName());
-            }
-
-            // 设置距离和地址
-            Text addressText = (Text) item.findComponentById(ResourceTable.Id_parking_address);
-            if (addressText != null) {
-                String distanceStr = park.getDistance() != null ? 
-                    String.format("%.1fkm", park.getDistance() / 1000.0) : "0km";
-                String address = park.getAddress() != null ? park.getAddress() : "";
-                addressText.setText(distanceStr + " | " + address);
-            }
-
-            // 设置总车位
-            Text totalPlaceText = (Text) item.findComponentById(ResourceTable.Id_text_total_place);
-            if (totalPlaceText != null && park.getTotalPlace() != null) {
-                totalPlaceText.setText(String.valueOf(park.getTotalPlace()));
-            }
-
-            // 设置剩余车位
-            Text residuePlaceText = (Text) item.findComponentById(ResourceTable.Id_text_residue_place);
-            if (residuePlaceText != null && park.getResiduePlace() != null) {
-                residuePlaceText.setText(String.valueOf(park.getResiduePlace()));
-            }
-
-            // 设置免费时长(从chargeInfo中解析,这里简化处理)
-            Text freeDurationText = (Text) item.findComponentById(ResourceTable.Id_text_free_duration);
-            if (freeDurationText != null) {
-                // 这里可以根据chargeInfo解析免费时长,暂时显示"15分"
-                freeDurationText.setText("15分");
-            }
-
-            // 设置标签
-            DirectionalLayout tagsContainer = (DirectionalLayout) item.findComponentById(ResourceTable.Id_tags_container);
-            if (tagsContainer != null) {
-                tagsContainer.removeAllComponents();
-                
-                // 根据数据添加标签
-                // 商场、学校等标签需要根据业务逻辑判断,这里简化处理
-                // 可预约 - 浅蓝色(#4CAF50 或 #2196F3)
-                if (park.getIsreserver() != null && park.getIsreserver() == 1) {
-                    addTag(tagsContainer, "可预约", "#4CAF50");
-                }
-                // 可充电 - 浅蓝色
-                if (park.getPowerEnable() != null && park.getPowerEnable() == 1) {
-                    addTag(tagsContainer, "可充电", "#4CAF50");
-                }
-                // 优惠 - 红色
-                if (park.getReductionEnable() != null && park.getReductionEnable() == 1) {
-                    addTag(tagsContainer, "惠", "#FF0000");
+            // 使用 ParkingItemComponent 组件
+            ParkingItemComponent item = new ParkingItemComponent(this, park);
+            
+            // 设置选中监听器,实现全局选中状态管理
+            item.setOnItemSelectedListener((component, parkData) -> {
+                // 如果之前有选中的项,取消其选中状态
+                if (selectedParkingItem != null && selectedParkingItem != component) {
+                    selectedParkingItem.setSelected(false);
                 }
-                // 商场、学校等标签 - 橙色(#FA6332,需要根据业务逻辑判断,这里暂时不添加)
-            }
-
-            // 设置导航按钮点击事件
-            Image navButton = item.findComponentById(ResourceTable.Id_btn_navigate);
-            if (navButton != null) {
-                navButton.setClickedListener(component -> {
-                    // 导航功能
-                    Log.info("导航到: " + park.getParkName());
-                    // TODO: 实现导航功能
-                });
-            }
+                // 更新当前选中的项
+                selectedParkingItem = component;
+            });
 
             return item;
 
@@ -1023,26 +962,4 @@ public class MainAbilitySlice extends AbilitySlice {
             parkingListContainer.addComponent(item);
         }
     }
-
-    /**
-     * 添加标签
-     */
-    private void addTag(DirectionalLayout container, String text, String bgColor) {
-        Text tag = new Text(getContext());
-        tag.setText(text);
-        tag.setTextSize(11);
-        tag.setTextColor(Color.WHITE);
-        tag.setPadding(8, 4, 8, 4);
-        
-        // 创建圆角背景(椭圆形)
-        ShapeElement background = new ShapeElement();
-        background.setShape(ShapeElement.RECTANGLE);
-        RgbColor rgbColor = new RgbColor(Color.getIntColor(bgColor));
-        background.setRgbColor(rgbColor);
-        background.setCornerRadius(12);
-        tag.setBackground(background);
-        
-        tag.setMarginLeft(4);
-        container.addComponent(tag);
-    }
 }

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

@@ -0,0 +1,179 @@
+package com.fujica.abk.utils;
+
+import com.fujica.abk.ResourceTable;
+import ohos.agp.animation.Animator;
+import ohos.agp.animation.AnimatorProperty;
+import ohos.agp.components.AttrSet;
+import ohos.agp.components.Component;
+import ohos.agp.components.ComponentContainer;
+import ohos.agp.components.DirectionalLayout;
+import ohos.agp.components.Image;
+import ohos.agp.components.LayoutScatter;
+import ohos.agp.components.ProgressBar;
+import ohos.agp.utils.Color;
+import ohos.agp.utils.LayoutAlignment;
+import ohos.app.Context;
+import ohos.eventhandler.EventHandler;
+import ohos.eventhandler.EventRunner;
+
+/**
+ * Loading组件类,继承DirectionalLayout
+ * 全屏遮罩,中间显示loading,不可点击,不可取消
+ * 使用方式:在 AbilitySlice 中定义为属性,初始化后添加到根布局
+ */
+public class LoadingComponent extends DirectionalLayout {
+    private Component contentLayout;
+    private Image loadingImage;
+    private AnimatorProperty rotationAnimator;
+
+    /**
+     * 构造函数(用于代码创建)
+     */
+    public LoadingComponent(Context context) {
+        super(context);
+        initComponent(context);
+    }
+
+    /**
+     * 构造函数(用于XML布局文件)
+     */
+    public LoadingComponent(Context context, AttrSet attrSet) {
+        super(context, attrSet);
+        initComponent(context);
+    }
+
+    /**
+     * 构造函数(用于XML布局文件,带样式)
+     */
+    public LoadingComponent(Context context, AttrSet attrSet, String styleName) {
+        super(context, attrSet, styleName);
+        initComponent(context);
+    }
+
+    private void initComponent(Context context) {
+        // 设置全屏布局属性
+        setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setAlignment(LayoutAlignment.CENTER);
+        setOrientation(VERTICAL);
+        
+        // 使用布局文件加载内容
+        contentLayout = LayoutScatter.getInstance(context)
+                .parse(ResourceTable.Layout_layout_loading_dialog, null, false);
+
+        // 将内容布局添加到根布局中
+        addComponent(contentLayout);
+        
+        // 获取图片组件
+        Component imageComponent = contentLayout.findComponentById(ResourceTable.Id_loading_image);
+        if (imageComponent instanceof Image) {
+            loadingImage = (Image) imageComponent;
+            // 创建旋转动画
+            initRotationAnimation();
+        }
+        
+        // 默认隐藏
+        setVisibility(HIDE);
+    }
+    
+    /**
+     * 初始化旋转动画
+     */
+    private void initRotationAnimation() {
+        if (loadingImage == null) {
+            return;
+        }
+        
+        // 先设置初始旋转角度为0
+        loadingImage.setRotation(0f);
+        
+        // 创建旋转动画属性
+        rotationAnimator = loadingImage.createAnimatorProperty();
+        // 设置旋转动画(从当前位置旋转360度)
+        rotationAnimator.rotate(360f);
+        // 设置动画持续时间(2秒)
+        rotationAnimator.setDuration(2000);
+        // 不设置无限循环,而是通过监听器手动控制
+        rotationAnimator.setLoopedCount(1);
+        // 设置动画曲线为线性(匀速旋转)
+        rotationAnimator.setCurveType(Animator.CurveType.LINEAR);
+        
+        // 添加动画状态监听器,在每次动画结束后重新启动
+        rotationAnimator.setStateChangedListener(new Animator.StateChangedListener() {
+            @Override
+            public void onStart(Animator animator) {
+            }
+            
+            @Override
+            public void onStop(Animator animator) {
+            }
+            
+            @Override
+            public void onCancel(Animator animator) {
+            }
+            
+            @Override
+            public void onEnd(Animator animator) {
+                // 每次动画结束时重置旋转角度为0,然后重新启动
+                if (loadingImage != null && rotationAnimator != null && getVisibility() == VISIBLE) {
+                    loadingImage.setRotation(0f);
+                    // 延迟一小段时间后重新启动动画,实现连续旋转
+                    EventHandler mainHandler = new EventHandler(EventRunner.getMainEventRunner());
+                    mainHandler.postTask(() -> {
+                        if (rotationAnimator != null && loadingImage != null && getVisibility() == VISIBLE) {
+                            rotationAnimator.start();
+                        }
+                    }, 10);
+                }
+            }
+            
+            @Override
+            public void onPause(Animator animator) {
+            }
+            
+            @Override
+            public void onResume(Animator animator) {
+            }
+        });
+    }
+    
+    /**
+     * 显示Loading
+     */
+    public void show() {
+        setVisibility(VISIBLE);
+        // 延迟启动旋转动画,确保组件已完全渲染
+        EventHandler mainHandler = new EventHandler(EventRunner.getMainEventRunner());
+        mainHandler.postTask(() -> {
+            if (rotationAnimator != null && loadingImage != null) {
+                // 重置旋转角度
+                loadingImage.setRotation(0f);
+                // 如果动画正在运行,先停止
+                if (rotationAnimator.isRunning()) {
+                    rotationAnimator.stop();
+                }
+                // 启动动画
+                rotationAnimator.start();
+            }
+        }, 100);
+    }
+    
+    /**
+     * 隐藏Loading
+     */
+    public void hide() {
+        setVisibility(HIDE);
+        // 停止旋转动画
+        if (rotationAnimator != null && rotationAnimator.isRunning()) {
+            rotationAnimator.stop();
+        }
+    }
+    
+    /**
+     * 是否正在显示
+     */
+    public boolean isShowing() {
+        return getVisibility() == VISIBLE;
+    }
+}
+

+ 0 - 206
entry/src/main/java/com/fujica/abk/utils/LoadingDialog.java

@@ -1,206 +0,0 @@
-package com.fujica.abk.utils;
-
-import com.amap.adapter.view.ViewGroup;
-import com.fujica.abk.ResourceTable;
-import ohos.agp.components.Component;
-import ohos.agp.components.ComponentContainer;
-import ohos.agp.components.LayoutScatter;
-import ohos.agp.components.ProgressBar;
-import ohos.agp.components.Text;
-import ohos.agp.colors.RgbColor;
-import ohos.agp.components.element.ShapeElement;
-import ohos.agp.utils.Color;
-import ohos.agp.window.dialog.CommonDialog;
-import ohos.app.Context;
-import ohos.eventhandler.EventHandler;
-import ohos.eventhandler.EventRunner;
-
-/**
- * Loading对话框类,继承CommonDialog
- * 全屏遮罩,中间显示loading,不可点击,不可取消
- */
-class LoadingCommonDialog extends CommonDialog {
-    private Component rootLayout;
-
-    public LoadingCommonDialog(Context context) {
-        super(context);
-        setTransparentBackground();
-        initDialog(context);
-    }
-
-    private void initDialog(Context context) {
-        // 使用布局文件加载
-        rootLayout = LayoutScatter.getInstance(context)
-                .parse(ResourceTable.Layout_layout_loading_dialog, null, false);
-
-        // 获取布局中的组件并设置属性
-        ProgressBar progressBar = (ProgressBar) rootLayout.findComponentById(ResourceTable.Id_progress_bar);
-        if (progressBar != null) {
-            progressBar.setProgressColor(Color.BLUE);
-        }
-
-        Text text = (Text) rootLayout.findComponentById(ResourceTable.Id_text_loading);
-        if (text != null) {
-            // 文本已在布局文件中设置,这里可以保持默认或根据需要修改
-        }
-
-        // 设置对话框属性
-        setTransparent(true); // 设置对话框背景透明
-        setContentCustomComponent(rootLayout);
-        setAutoClosable(false); // 不可自动关闭
-    }
-
-    @Override
-    public void show() {
-        super.show();
-        // 在显示后设置窗口和根布局的透明背景
-    }
-
-    /**
-     * 设置窗口和根布局的透明背景
-     */
-    private void setTransparentBackground() {
-        // 设置窗口背景为透明
-        RgbColor transparentColor = new RgbColor(Color.TRANSPARENT.getValue());
-        getWindow().setBackgroundColor(transparentColor);
-        getWindow().setLayoutInDisplaySideMode(1);
-        getWindow().setWindowLayout(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
-    }
-}
-
-/**
- * Loading对话框工具类
- * 全屏遮罩,中间显示loading,不可点击,不可取消
- */
-public class LoadingDialog {
-    private static LoadingCommonDialog currentDialog = null;
-    private static int showCount = 0; // 显示计数,用于处理多个请求同时显示loading的情况
-
-    /**
-     * 在主线程显示Loading
-     */
-    private static void showOnMainThread(Context context) {
-        if (context == null) {
-            return;
-        }
-
-        // 获取主线程的 EventRunner
-        EventRunner mainRunner = EventRunner.getMainEventRunner();
-        if (mainRunner == null) {
-            // 如果获取不到主线程,直接在当前线程显示(可能已经是主线程)
-            showDialog(context);
-            return;
-        }
-
-        // 创建主线程的 EventHandler
-        EventHandler mainHandler = new EventHandler(mainRunner);
-        mainHandler.postTask(() -> {
-            showDialog(context);
-        });
-    }
-
-    /**
-     * 在主线程隐藏Loading
-     */
-    private static void hideOnMainThread() {
-        // 获取主线程的 EventRunner
-        EventRunner mainRunner = EventRunner.getMainEventRunner();
-        if (mainRunner == null) {
-            // 如果获取不到主线程,直接在当前线程隐藏(可能已经是主线程)
-            hideDialog();
-            return;
-        }
-
-        // 创建主线程的 EventHandler
-        EventHandler mainHandler = new EventHandler(mainRunner);
-        mainHandler.postTask(() -> {
-            hideDialog();
-        });
-    }
-
-    /**
-     * 显示Loading对话框
-     */
-    private static void showDialog(Context context) {
-        if (currentDialog != null && currentDialog.isShowing()) {
-            // 如果已经显示,增加计数
-            showCount++;
-            return;
-        }
-
-        try {
-            // 创建自定义的Loading对话框
-            LoadingCommonDialog dialog = new LoadingCommonDialog(context);
-
-            // 显示对话框
-            dialog.show();
-            currentDialog = dialog;
-            showCount = 1;
-
-        } catch (Exception e) {
-            Log.error("显示Loading失败: " + e.getMessage());
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * 隐藏Loading对话框
-     */
-    private static void hideDialog() {
-        if (currentDialog == null) {
-            return;
-        }
-
-        try {
-            // 减少计数
-            showCount--;
-
-            // 只有当计数为0时才真正关闭对话框
-            if (showCount <= 0) {
-                if (currentDialog.isShowing()) {
-                    currentDialog.destroy();
-                }
-                currentDialog = null;
-                showCount = 0;
-            }
-        } catch (Exception e) {
-            Log.error("隐藏Loading失败: " + e.getMessage());
-            e.printStackTrace();
-            // 出错时强制重置
-            currentDialog = null;
-            showCount = 0;
-        }
-    }
-
-    /**
-     * 显示Loading
-     */
-    public static void show(Context context) {
-        showOnMainThread(context);
-    }
-
-    /**
-     * 隐藏Loading
-     */
-    public static void hide() {
-        hideOnMainThread();
-    }
-
-    /**
-     * 强制关闭所有Loading(用于异常情况)
-     */
-    public static void forceHide() {
-        if (currentDialog != null) {
-            try {
-                if (currentDialog.isShowing()) {
-                    currentDialog.destroy();
-                }
-            } catch (Exception e) {
-                Log.error("强制关闭Loading失败: " + e.getMessage());
-            }
-            currentDialog = null;
-            showCount = 0;
-        }
-    }
-}
-

+ 335 - 0
entry/src/main/java/com/fujica/abk/utils/ParkingItemComponent.java

@@ -0,0 +1,335 @@
+package com.fujica.abk.utils;
+
+import com.fujica.abk.ResourceTable;
+import com.fujica.abk.model.response.ParkNearRes;
+import ohos.agp.colors.RgbColor;
+import ohos.agp.components.*;
+import ohos.agp.components.element.ShapeElement;
+import ohos.agp.utils.Color;
+import ohos.app.Context;
+import ohos.eventhandler.EventHandler;
+import ohos.eventhandler.EventRunner;
+import ohos.utils.zson.ZSONObject;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 停车场列表项组件
+ * 内部调用 API 并绑定数据
+ */
+public class ParkingItemComponent extends DirectionalLayout {
+    private ParkNearRes parkData;
+    private String parkId;
+    private Component rootLayout;
+    private OnItemSelectedListener onItemSelectedListener;
+    private boolean isSelected = false;
+
+    /**
+     * 选中状态监听器
+     */
+    public interface OnItemSelectedListener {
+        void onItemSelected(ParkingItemComponent component, ParkNearRes park);
+    }
+
+    /**
+     * 构造函数(通过 parkId 创建)
+     */
+    public ParkingItemComponent(Context context, String parkId) {
+        super(context);
+        this.parkId = parkId;
+        initComponent(context);
+        loadParkData();
+    }
+
+    /**
+     * 构造函数(通过 ParkNearRes 对象创建)
+     */
+    public ParkingItemComponent(Context context, ParkNearRes park) {
+        super(context);
+        this.parkData = park;
+        this.parkId = park != null ? park.getParkId() : null;
+        initComponent(context);
+        bindData();
+    }
+
+    /**
+     * 初始化组件
+     */
+    private void initComponent(Context context) {
+        // 设置布局属性
+        setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
+        setHeight(ComponentContainer.LayoutConfig.MATCH_CONTENT);
+        setOrientation(HORIZONTAL);
+        setBackground(createNormalBackground());
+
+        // 加载布局文件
+        rootLayout = LayoutScatter.getInstance(context)
+                .parse(ResourceTable.Layout_item_parking, null, false);
+        addComponent(rootLayout);
+
+        // 设置整个列表项的点击事件
+        setClickedListener(component -> {
+            if (parkData != null) {
+                setSelected(true);
+                if (onItemSelectedListener != null) {
+                    onItemSelectedListener.onItemSelected(this, parkData);
+                }
+            }
+        });
+    }
+
+    /**
+     * 加载停车场数据(通过 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;
+        }
+    }
+
+    /**
+     * 绑定数据到 UI
+     */
+    private void bindData() {
+        if (parkData == null || rootLayout == null) {
+            return;
+        }
+
+        try {
+            // 设置停车场名称
+            Text nameText = (Text) rootLayout.findComponentById(ResourceTable.Id_parking_name);
+            if (nameText != null && parkData.getParkName() != null) {
+                nameText.setText(parkData.getParkName());
+            }
+
+            // 设置距离和地址
+            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);
+            }
+
+            // 设置总车位
+            Text totalPlaceText = (Text) rootLayout.findComponentById(ResourceTable.Id_text_total_place);
+            if (totalPlaceText != null && parkData.getTotalPlace() != null) {
+                totalPlaceText.setText(String.valueOf(parkData.getTotalPlace()));
+            }
+
+            // 设置剩余车位
+            Text residuePlaceText = (Text) rootLayout.findComponentById(ResourceTable.Id_text_residue_place);
+            if (residuePlaceText != null && parkData.getResiduePlace() != null) {
+                residuePlaceText.setText(String.valueOf(parkData.getResiduePlace()));
+            }
+
+            // 设置免费时长(从chargeInfo中解析,这里简化处理)
+            Text freeDurationText = (Text) rootLayout.findComponentById(ResourceTable.Id_text_free_duration);
+            if (freeDurationText != null) {
+                // 这里可以根据chargeInfo解析免费时长,暂时显示"15分"
+                freeDurationText.setText("15分");
+            }
+
+            // 设置标签
+            DirectionalLayout tagsContainer = (DirectionalLayout) rootLayout.findComponentById(ResourceTable.Id_tags_container);
+            if (tagsContainer != null) {
+                tagsContainer.removeAllComponents();
+
+                // 根据数据添加标签
+                if (parkData.getIsreserver() != null && parkData.getIsreserver() == 1) {
+                    addTag(tagsContainer, "可预约", "#4CAF50");
+                }
+                if (parkData.getPowerEnable() != null && parkData.getPowerEnable() == 1) {
+                    addTag(tagsContainer, "可充电", "#4CAF50");
+                }
+                if (parkData.getReductionEnable() != null && parkData.getReductionEnable() == 1) {
+                    addTag(tagsContainer, "惠", "#FF0000");
+                }
+            }
+
+            // 设置导航按钮点击事件
+            Image navButton = (Image) rootLayout.findComponentById(ResourceTable.Id_btn_navigate);
+            if (navButton != null) {
+                navButton.setClickedListener(component -> {
+                    // 导航功能
+                    Log.info("导航到: " + parkData.getParkName());
+                    // TODO: 实现导航功能
+                });
+            }
+        } catch (Exception e) {
+            Log.error("绑定数据失败: " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 添加标签
+     */
+    private void addTag(DirectionalLayout container, String text, String bgColor) {
+        Text tag = new Text(getContext());
+        tag.setText(text);
+        tag.setTextSize(11);
+        tag.setTextColor(Color.WHITE);
+        tag.setPadding(8, 4, 8, 4);
+
+        // 创建圆角背景
+        ShapeElement background = new ShapeElement();
+        background.setShape(ShapeElement.RECTANGLE);
+        RgbColor rgbColor = new RgbColor(Color.getIntColor(bgColor));
+        background.setRgbColor(rgbColor);
+        background.setCornerRadius(12);
+        tag.setBackground(background);
+
+        tag.setMarginLeft(4);
+        container.addComponent(tag);
+    }
+
+    /**
+     * 创建普通背景
+     */
+    private ShapeElement createNormalBackground() {
+        ShapeElement background = new ShapeElement();
+        background.setShape(ShapeElement.RECTANGLE);
+        RgbColor normalColor = new RgbColor(Color.getIntColor("#FFFFFFFF"));
+        background.setRgbColor(normalColor);
+        background.setCornerRadius(8);
+        return background;
+    }
+
+    /**
+     * 创建选中背景
+     */
+    private ShapeElement createSelectedBackground() {
+        ShapeElement background = new ShapeElement();
+        background.setShape(ShapeElement.RECTANGLE);
+        RgbColor selectedColor = new RgbColor(255, 236,230, 255);
+        background.setRgbColor(selectedColor);
+        background.setCornerRadius(8);
+        return background;
+    }
+
+    /**
+     * 设置选中状态
+     */
+    public void setSelected(boolean selected) {
+        if (isSelected == selected) {
+            return;
+        }
+        isSelected = selected;
+        setBackground(selected ? createSelectedBackground() : createNormalBackground());
+    }
+
+    /**
+     * 获取选中状态
+     */
+    public boolean isSelected() {
+        return isSelected;
+    }
+
+    /**
+     * 设置选中监听器
+     */
+    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+        this.onItemSelectedListener = listener;
+    }
+
+    /**
+     * 获取停车场数据
+     */
+    public ParkNearRes getParkData() {
+        return parkData;
+    }
+}
+

+ 2 - 8
entry/src/main/java/com/fujica/abk/utils/api.java

@@ -134,11 +134,10 @@ public class api {
         // 显示Loading:默认显示,只有当hideLoading!=null && hideLoading==false时才不显示
         final boolean shouldShowLoading = !(hideLoading != null && hideLoading);
         if (shouldShowLoading) {
-            LoadingDialog.show(context);
+//            LoadingDialog.show(context);
         }
 
         url = mergeUrl(url, method, data);
-        Log.info("请求" + url);
         String token = cache.getToken(context);
         final String _url = url;
         final Boolean _failToast = failToast;
@@ -288,7 +287,7 @@ public class api {
         String token = cache.getToken(context);
 
         // 显示Loading(上传默认显示loading)
-        LoadingDialog.show(context);
+//        LoadingDialog.show(context);
 
         String finalUrl = url;
         return CompletableFuture.supplyAsync(() -> {
@@ -339,7 +338,6 @@ public class api {
                     if (responseCode != 200) {
                         String msg = "操作失败:" + responseCode;
                         Toast.error(context, msg);
-                        Log.info("响应:" + responseCode);
                         result = new R<>(msg);
                     } else {
                         // 读取响应
@@ -360,14 +358,12 @@ public class api {
                             String errorMsg = result.getMsg() != null ? result.getMsg() : "操作失败" + result.getCode();
                             Toast.error(context, errorMsg);
                         }
-                        Log.info("响应:" + resultStr);
                         if (result == null) {
                             result = new R<>("解析响应失败");
                         }
                     }
 
                     // 隐藏Loading
-                    LoadingDialog.hide();
 
                     return result;
                 } catch (Exception e) {
@@ -376,7 +372,6 @@ public class api {
                     Log.error("响应解析错误: " + e.getMessage());
 
                     // 隐藏Loading
-                    LoadingDialog.hide();
 
                     return new R<>(msg);
                 }
@@ -386,7 +381,6 @@ public class api {
                 Log.error("上传错误: " + e.getMessage());
 
                 // 隐藏Loading
-                LoadingDialog.hide();
 
                 return new R<>(msg);
             } catch (Exception e) {

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

@@ -5,6 +5,6 @@
     <corners
         ohos:radius="16vp"/>
     <solid
-        ohos:color="#FFFFFFFF"/>
+        ohos:color="#CC000000"/>
 </shape>
 

+ 5 - 0
entry/src/main/resources/base/layout/ability_main.xml

@@ -223,4 +223,9 @@
         <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>
     </DirectionalLayout>
 
+    <!-- Loading组件放在最后,确保在最上层显示 -->
+    <com.fujica.abk.utils.LoadingComponent 
+        ohos:id="$+id:loading_component"
+        ohos:width="match_parent" 
+        ohos:height="match_parent" />
 </StackLayout>

+ 146 - 135
entry/src/main/resources/base/layout/item_parking.xml

@@ -3,171 +3,182 @@
     xmlns:ohos="http://schemas.huawei.com/res/ohos"
     ohos:height="match_content"
     ohos:width="match_parent"
-    ohos:orientation="horizontal"
-    ohos:padding="12vp"
-    ohos:bottom_margin="12vp"
-    ohos:background_element="#FFFFFFFF"
-    ohos:border_radius="8vp"
-    ohos:shadow="2">
-
-    <!-- 中间内容区域 -->
+    ohos:orientation="vertical"
+    ohos:left_padding="16vp"
+    ohos:right_padding="16vp"
+    ohos:top_padding="16vp"
+    >
+
+
     <DirectionalLayout
         ohos:height="match_content"
-        ohos:width="0vp"
-        ohos:weight="1"
-        ohos:orientation="vertical">
+        ohos:width="match_parent"
 
-        <!-- 停车场名称和标签 -->
+        ohos:orientation="horizontal">
+        <!-- 中间内容区域 -->
         <DirectionalLayout
             ohos:height="match_content"
-            ohos:width="match_parent"
-            ohos:orientation="horizontal"
-            ohos:bottom_margin="8vp"
-            ohos:alignment="center">
+            ohos:width="0vp"
+            ohos:orientation="vertical"
+            ohos:weight="1">
 
-            <Text
-                ohos:id="$+id:parking_name"
-                ohos:height="match_content"
-                ohos:width="0vp"
-                ohos:weight="1"
-                ohos:text="停车场名称"
-                ohos:text_color="#FF000000"
-                ohos:text_size="16fp"
-                ohos:text_weight="1"
-                ohos:end_margin="8vp"/>
-
-            <!-- 标签容器 -->
+            <!-- 停车场名称和标签 -->
             <DirectionalLayout
-                ohos:id="$+id:tags_container"
                 ohos:height="match_content"
-                ohos:width="match_content"
+                ohos:width="match_parent"
+                ohos:alignment="center"
+                ohos:bottom_margin="8vp"
                 ohos:orientation="horizontal">
-            </DirectionalLayout>
-        </DirectionalLayout>
-
-        <!-- 距离和地址 -->
-        <Text
-            ohos:id="$+id:parking_address"
-            ohos:height="match_content"
-            ohos:width="match_parent"
-            ohos:text="0.8km | 地址信息"
-            ohos:text_color="#FF666666"
-            ohos:text_size="12fp"
-            ohos:bottom_margin="8vp"/>
-
-        <!-- 统计信息:总车位、剩余车位、免费时长 -->
-        <DirectionalLayout
-            ohos:height="match_content"
-            ohos:width="match_parent"
-            ohos:orientation="horizontal"
-            ohos:alignment="center">
-
-            <!-- 总车位 -->
-            <DirectionalLayout
-                ohos:height="match_content"
-                ohos:width="0vp"
-                ohos:weight="1"
-                ohos:orientation="vertical"
-                ohos:alignment="center">
 
                 <Text
-                    ohos:id="$+id:text_total_place"
+                    ohos:id="$+id:parking_name"
                     ohos:height="match_content"
-                    ohos:width="match_content"
-                    ohos:text="2000"
+                    ohos:width="0vp"
+                    ohos:end_margin="8vp"
+                    ohos:text="停车场名称"
                     ohos:text_color="#FF000000"
-                    ohos:text_size="14fp"
-                    ohos:text_weight="1"
-                    ohos:text_alignment="center"/>
+                    ohos:text_size="16fp"
+                    ohos:weight="1"/>
 
-                <Text
+                <!-- 标签容器 -->
+                <DirectionalLayout
+                    ohos:id="$+id:tags_container"
                     ohos:height="match_content"
                     ohos:width="match_content"
-                    ohos:text="总车位"
-                    ohos:text_color="#FF666666"
-                    ohos:text_size="12fp"
-                    ohos:text_alignment="center"/>
+                    ohos:orientation="horizontal">
+                </DirectionalLayout>
             </DirectionalLayout>
 
-            <!-- 剩余车位 -->
-            <DirectionalLayout
+            <!-- 距离和地址 -->
+            <Text
+                ohos:id="$+id:parking_address"
                 ohos:height="match_content"
-                ohos:width="0vp"
-                ohos:weight="1"
-                ohos:orientation="vertical"
-                ohos:alignment="center">
-
-                <Text
-                    ohos:id="$+id:text_residue_place"
-                    ohos:height="match_content"
-                    ohos:width="match_content"
-                    ohos:text="50"
-                    ohos:text_color="#FA6332"
-                    ohos:text_size="14fp"
-                    ohos:text_weight="1"
-                    ohos:text_alignment="center"/>
-
-                <Text
-                    ohos:height="match_content"
-                    ohos:width="match_content"
-                    ohos:text="剩余车位"
-                    ohos:text_color="#FF666666"
-                    ohos:text_size="12fp"
-                    ohos:text_alignment="center"/>
-            </DirectionalLayout>
+                ohos:width="match_parent"
+                ohos:bottom_margin="8vp"
+                ohos:text="0.8km | 地址信息"
+                ohos:text_color="#FF666666"
+                ohos:text_size="12fp"/>
 
-            <!-- 免费时长 -->
+            <!-- 统计信息:总车位、剩余车位、免费时长 -->
             <DirectionalLayout
                 ohos:height="match_content"
-                ohos:width="0vp"
-                ohos:weight="1"
-                ohos:orientation="vertical"
-                ohos:alignment="center">
+                ohos:width="match_parent"
+                ohos:alignment="center"
+                ohos:orientation="horizontal">
 
-                <Text
-                    ohos:id="$+id:text_free_duration"
+                <!-- 总车位 -->
+                <DirectionalLayout
                     ohos:height="match_content"
-                    ohos:width="match_content"
-                    ohos:text="15分"
-                    ohos:text_color="#FF000000"
-                    ohos:text_size="14fp"
-                    ohos:text_weight="1"
-                    ohos:text_alignment="center"/>
-
-                <Text
+                    ohos:width="0vp"
+                    ohos:alignment="center"
+                    ohos:orientation="vertical"
+                    ohos:weight="1">
+
+                    <Text
+                        ohos:id="$+id:text_total_place"
+                        ohos:height="match_content"
+                        ohos:width="match_content"
+                        ohos:text="2000"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF000000"
+                        ohos:text_size="14fp"/>
+
+                    <Text
+                        ohos:height="match_content"
+                        ohos:width="match_content"
+                        ohos:text="总车位"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF666666"
+                        ohos:text_size="12fp"/>
+                </DirectionalLayout>
+
+                <!-- 剩余车位 -->
+                <DirectionalLayout
                     ohos:height="match_content"
-                    ohos:width="match_content"
-                    ohos:text="免费时长"
-                    ohos:text_color="#FF666666"
-                    ohos:text_size="12fp"
-                    ohos:text_alignment="center"/>
+                    ohos:width="0vp"
+                    ohos:alignment="center"
+                    ohos:orientation="vertical"
+                    ohos:weight="1">
+
+                    <Text
+                        ohos:id="$+id:text_residue_place"
+                        ohos:height="match_content"
+                        ohos:width="match_content"
+                        ohos:text="50"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FA6332"
+                        ohos:text_size="14fp"/>
+
+                    <Text
+                        ohos:height="match_content"
+                        ohos:width="match_content"
+                        ohos:text="剩余车位"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF666666"
+                        ohos:text_size="12fp"/>
+                </DirectionalLayout>
+
+                <!-- 免费时长 -->
+                <DirectionalLayout
+                    ohos:height="match_content"
+                    ohos:width="0vp"
+                    ohos:alignment="center"
+                    ohos:orientation="vertical"
+                    ohos:weight="1">
+
+                    <Text
+                        ohos:id="$+id:text_free_duration"
+                        ohos:height="match_content"
+                        ohos:width="match_content"
+                        ohos:text="15分"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF000000"
+                        ohos:text_size="14fp"/>
+
+                    <Text
+                        ohos:height="match_content"
+                        ohos:width="match_content"
+                        ohos:text="免费时长"
+                        ohos:text_alignment="center"
+                        ohos:text_color="#FF666666"
+                        ohos:text_size="12fp"/>
+                </DirectionalLayout>
             </DirectionalLayout>
         </DirectionalLayout>
-    </DirectionalLayout>
 
-    <!-- 右侧导航按钮 -->
-    <DirectionalLayout
-        ohos:height="match_content"
-        ohos:width="match_content"
-        ohos:orientation="vertical"
-        ohos:alignment="center"
-        ohos:start_margin="8vp">
-
-        <Image
-            ohos:id="$+id:btn_navigate"
-            ohos:height="48vp"
-            ohos:width="48vp"
-            ohos:image_src="$media:nav"
-            ohos:scale_mode="stretch"/>
-
-        <Text
+        <!-- 右侧导航按钮 -->
+        <DirectionalLayout
             ohos:height="match_content"
             ohos:width="match_content"
-            ohos:text="导航"
-            ohos:text_color="#FF000000"
-            ohos:text_size="12fp"
-            ohos:text_alignment="center"
-            ohos:top_margin="4vp"/>
+            ohos:alignment="center"
+            ohos:orientation="vertical"
+            ohos:start_margin="8vp">
+
+            <Image
+                ohos:id="$+id:btn_navigate"
+                ohos:height="48vp"
+                ohos:width="48vp"
+                ohos:image_src="$media:nav"
+                ohos:scale_mode="stretch"/>
+
+            <Text
+                ohos:height="match_content"
+                ohos:width="match_content"
+                ohos:text="导航"
+                ohos:text_alignment="center"
+                ohos:text_color="#FF000000"
+                ohos:text_size="12fp"
+                ohos:top_margin="4vp"/>
+        </DirectionalLayout>
+
     </DirectionalLayout>
+
+    <!-- 底边灰线 -->
+    <DirectionalLayout
+        xmlns:ohos="http://schemas.huawei.com/res/ohos"
+        ohos:height="1vp"
+        ohos:top_margin="16vp"
+        ohos:width="match_parent"
+        ohos:background_element="#FFE0E0E0"/>
 </DirectionalLayout>
 

+ 3 - 5
entry/src/main/resources/base/layout/layout_find_parking.xml

@@ -4,7 +4,7 @@
     ohos:height="match_parent"
     ohos:width="match_parent"
     ohos:orientation="vertical"
-    ohos:background_element="#FFFFFFFF">
+    ohos:background_element="#CCC">
 
     <!-- 顶部查询条件区域 -->
     <DirectionalLayout
@@ -28,8 +28,7 @@
             ohos:left_padding="12vp"
             ohos:right_padding="12vp"
             ohos:top_padding="6vp"
-            ohos:bottom_padding="6vp"
-            ohos:border_radius="4vp"/>
+            ohos:bottom_padding="6vp"/>
     </DirectionalLayout>
 
     <!-- 停车场列表 -->
@@ -44,8 +43,7 @@
             ohos:id="$+id:parking_list_container"
             ohos:height="match_content"
             ohos:width="match_parent"
-            ohos:orientation="vertical"
-            ohos:padding="16vp">
+            ohos:orientation="vertical">
         </DirectionalLayout>
     </ScrollView>
 </DirectionalLayout>

+ 10 - 16
entry/src/main/resources/base/layout/layout_loading_dialog.xml

@@ -1,8 +1,8 @@
 <?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:height="match_content"
+    ohos:width="match_content"
     ohos:alignment="center"
     ohos:orientation="vertical">
     <!-- 根布局不设置背景,保持全透明 -->
@@ -14,24 +14,18 @@
         ohos:width="match_content"
         ohos:orientation="vertical"
         ohos:alignment="center"
-        ohos:padding="40vp"
+        ohos:padding="20vp"
         ohos:background_element="$graphic:background_loading_content">
 
         <!-- ProgressBar -->
-        <ProgressBar
-            ohos:id="$+id:progress_bar"
-            ohos:height="80vp"
-            ohos:width="80vp"/>
+        <Image
+            ohos:id="$+id:loading_image"
+            ohos:scale_mode="stretch"
+            ohos:image_src="$media:loading"
+            ohos:height="40vp"
+            ohos:width="40vp"/>
+
 
-        <!-- 提示文字 -->
-        <Text
-            ohos:id="$+id:text_loading"
-            ohos:height="match_content"
-            ohos:width="match_content"
-            ohos:text="加载中..."
-            ohos:text_size="14fp"
-            ohos:text_color="#FF666666"
-            ohos:top_margin="16vp"/>
     </DirectionalLayout>
 </DirectionalLayout>
 

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