linee 1 tuần trước cách đây
mục cha
commit
82bf3f50fb
39 tập tin đã thay đổi với 1476 bổ sung481 xóa
  1. 0 3
      entry/build.gradle
  2. 298 0
      entry/docs/JAVA_TO_JS_ABILITY.md
  3. 271 0
      entry/docs/QUICK_EXAMPLE.java
  4. BIN
      entry/libs/mapslibrary-release.har
  5. 2 49
      entry/src/main/config.json
  6. 4 5
      entry/src/main/java/com/fujica/abk/api/auth.java
  7. 6 0
      entry/src/main/java/com/fujica/abk/api/cache.java
  8. 1 1
      entry/src/main/java/com/fujica/abk/api/config.java
  9. 1 1
      entry/src/main/java/com/fujica/abk/component/ParkItemComponent.java
  10. 143 76
      entry/src/main/java/com/fujica/abk/component/QRCodeScanDialog.java
  11. 11 11
      entry/src/main/java/com/fujica/abk/component/nav/ChargeComponent.java
  12. 7 4
      entry/src/main/java/com/fujica/abk/component/nav/OrderComponent.java
  13. 34 8
      entry/src/main/java/com/fujica/abk/component/nav/ParkComponent.java
  14. 1 0
      entry/src/main/java/com/fujica/abk/manager/CardTriggerManager.java
  15. 11 0
      entry/src/main/java/com/fujica/abk/model/in/PayRequest.java
  16. 6 5
      entry/src/main/java/com/fujica/abk/model/out/ArrearageOrder.java
  17. 21 2
      entry/src/main/java/com/fujica/abk/model/out/ParkingFeeInfo.java
  18. 21 0
      entry/src/main/java/com/fujica/abk/slice/JsAbility.java
  19. 194 0
      entry/src/main/java/com/fujica/abk/slice/JsAbilityDemoSlice.java
  20. 4 2
      entry/src/main/java/com/fujica/abk/slice/MainAbilitySlice.java
  21. 173 0
      entry/src/main/java/com/fujica/abk/utils/CoordinateUtil.java
  22. 199 0
      entry/src/main/java/com/fujica/abk/utils/JsAbilityHelper.java
  23. 2 1
      entry/src/main/java/com/fujica/abk/utils/api.java
  24. 0 39
      entry/src/main/js/jsability/pages/index/index.css
  25. 0 8
      entry/src/main/js/jsability/pages/index/index.hml
  26. 0 84
      entry/src/main/js/jsability/pages/index/index.js
  27. BIN
      entry/src/main/js/widget1/common/ic_default_image@3x.png
  28. 0 6
      entry/src/main/js/widget1/i18n/en-US.json
  29. 0 6
      entry/src/main/js/widget1/i18n/zh-CN.json
  30. 0 61
      entry/src/main/js/widget1/pages/index/index.css
  31. 0 11
      entry/src/main/js/widget1/pages/index/index.hml
  32. 0 17
      entry/src/main/js/widget1/pages/index/index.json
  33. 0 11
      entry/src/main/js/widget1/pages/index/index1.hml
  34. 12 0
      entry/src/main/resources/base/element/string.json
  35. 7 9
      entry/src/main/resources/base/layout/ability_main.xml
  36. 8 8
      entry/src/main/resources/base/layout/dialog_authorization.xml
  37. 1 0
      entry/src/main/resources/base/layout/layout_charge.xml
  38. 38 53
      entry/src/main/resources/base/layout/layout_pay_detail_dialog.xml
  39. BIN
      entry/src/main/resources/base/media/bg.png

+ 0 - 3
entry/build.gradle

@@ -44,9 +44,6 @@ dependencies {
     implementation 'com.google.zxing:core:3.5.2'
     // 华为支付 SDK 建议取最新的版本
     implementation 'com.huawei.hms:paymentservice:6.12.0.300'
-
-    // hms jsb adapter
-//    implementation 'com.huawei.hms:jsb-ohos-adapter:6.5.0.300'
 }
 decc {
     supportType = ['html', 'xml']

+ 298 - 0
entry/docs/JAVA_TO_JS_ABILITY.md

@@ -0,0 +1,298 @@
+# Java Ability 调用 JS Ability 完整示例
+
+## 📋 概述
+
+本示例展示了在 HarmonyOS Java API 7 项目中,如何从 Java Ability 调用 JS Ability 的多种方式。
+
+## 🎯 使用场景
+
+- 从 Java Ability 跳转到 JS 页面
+- Java 和 JS 之间传递数据
+- JS Ability 返回结果给 Java Ability
+- 跨语言混合开发
+
+## 📂 文件结构
+
+```
+entry/src/main/
+├── java/com/fujica/abk/
+│   ├── utils/
+│   │   └── JsAbilityHelper.java          # 工具类
+│   └── slice/
+│       └── JsAbilityDemoSlice.java       # 演示示例
+├── js/jsability/
+│   └── pages/index/
+│       ├── index.hml                     # JS 页面结构
+│       ├── index.css                     # JS 页面样式
+│       └── index.js                      # JS 页面逻辑
+└── config.json                           # 配置文件
+```
+
+## 🚀 使用方法
+
+### 方式一:简单启动(不需要返回结果)
+
+```java
+JsAbilityHelper.startJsAbility(
+    getAbility(),                         // 当前 Ability
+    "com.fujica.abk",                     // 应用包名
+    "com.fujica.abk.JsAbility",          // JS Ability 名称
+    "来自 Java 的问候",                   // 消息参数
+    "这是传递的数据"                      // 数据参数
+);
+```
+
+### 方式二:启动并等待返回结果
+
+```java
+JsAbilityHelper.startJsAbilityForResult(
+    getAbility(),
+    "com.fujica.abk",
+    "com.fujica.abk.JsAbility",
+    "请返回数据",
+    "Request ID: 12345"
+);
+
+// 在 Ability 中重写 onAbilityResult 方法接收返回结果
+@Override
+protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
+    super.onAbilityResult(requestCode, resultCode, resultData);
+    
+    if (requestCode == JsAbilityHelper.getRequestCode()) {
+        if (resultData != null) {
+            String status = resultData.getStringParam("status");
+            String data = resultData.getStringParam("data");
+            // 处理返回的数据
+        }
+    }
+}
+```
+
+### 方式三:从 AbilitySlice 启动
+
+```java
+JsAbilityHelper.startJsAbilityFromSlice(
+    this,                                 // 当前 AbilitySlice
+    "com.fujica.abk",
+    "com.fujica.abk.JsAbility",
+    "从 Slice 发送",
+    "Slice 数据"
+);
+```
+
+### 方式四:传递 JSON 复杂对象
+
+```java
+// 创建 JSON 对象
+ZSONObject jsonData = new ZSONObject();
+jsonData.put("userId", "123456");
+jsonData.put("userName", "张三");
+jsonData.put("action", "query");
+jsonData.put("timestamp", System.currentTimeMillis());
+
+JsAbilityHelper.startJsAbilityWithJson(
+    getAbility(),
+    "com.fujica.abk",
+    "com.fujica.abk.JsAbility",
+    jsonData
+);
+```
+
+## 📥 JS Ability 接收参数
+
+在 JS 端的 `index.js` 中:
+
+```javascript
+import featureAbility from '@ohos.ability.featureAbility';
+
+export default {
+    data: {
+        receivedData: '无'
+    },
+    
+    onInit() {
+        // 获取从 Java 传递过来的参数
+        var context = featureAbility.getContext();
+        context.getWant((error, want) => {
+            if (!error && want.parameters) {
+                var dataFromJava = want.parameters.data;
+                var messageFromJava = want.parameters.message;
+                
+                this.receivedData = dataFromJava;
+                console.info('接收到的数据: ' + dataFromJava);
+            }
+        });
+    }
+}
+```
+
+## 📤 JS Ability 返回数据
+
+在 JS 端返回数据并关闭页面:
+
+```javascript
+import featureAbility from '@ohos.ability.featureAbility';
+
+// 返回数据给 Java
+returnData() {
+    var result = {
+        resultCode: 1,
+        want: {
+            parameters: {
+                status: 'success',
+                data: 'JS 返回的数据',
+                timestamp: new Date().getTime()
+            }
+        }
+    };
+    
+    var context = featureAbility.getContext();
+    context.terminateSelfWithResult(result, (error) => {
+        if (!error) {
+            console.info('成功返回数据');
+        }
+    });
+}
+```
+
+## ⚙️ config.json 配置
+
+需要在 `config.json` 中注册 JS Ability:
+
+```json
+{
+  "module": {
+    "abilities": [
+      {
+        "name": ".JsAbility",
+        "srcPath": "jsability",
+        "icon": "$media:icon",
+        "description": "JS Ability 示例",
+        "label": "JS Ability",
+        "type": "page",
+        "visible": true,
+        "launchType": "standard"
+      }
+    ],
+    "js": [
+      {
+        "name": "jsability",
+        "pages": [
+          "pages/index/index"
+        ],
+        "window": {
+          "designWidth": 720,
+          "autoDesignWidth": true
+        }
+      }
+    ]
+  }
+}
+```
+
+## 🔧 测试方法
+
+1. **在 MainAbility 中添加 Slice**:
+
+```java
+public class MainAbility extends Ability {
+    @Override
+    public void onStart(Intent intent) {
+        super.onStart(intent);
+        super.setMainRoute(JsAbilityDemoSlice.class.getName());
+    }
+}
+```
+
+2. **运行应用**,点击不同按钮测试各种调用方式
+
+3. **查看日志**:
+```bash
+hdc_std shell hilog | grep JsAbility
+```
+
+## 📝 注意事项
+
+1. **包名和 Ability 名称必须正确**
+   - 包名:`com.fujica.abk`
+   - JS Ability 完整名称:`com.fujica.abk.JsAbility`
+
+2. **JS Ability 必须在 config.json 中正确注册**
+   - abilities 数组中添加 Ability 配置
+   - js 数组中添加 JS 页面配置
+
+3. **参数传递限制**
+   - 基本类型:String, int, long, boolean 等
+   - 复杂对象需要转换为 JSON 字符串
+
+4. **返回结果处理**
+   - 只有使用 `startAbilityForResult` 才能接收返回结果
+   - 必须在 Ability 中重写 `onAbilityResult` 方法
+
+5. **线程安全**
+   - Ability 启动操作在主线程执行
+   - 耗时操作应放在子线程
+
+## 🎨 自定义扩展
+
+### 添加更多参数类型
+
+```java
+intent.setParam("stringParam", "字符串");
+intent.setParam("intParam", 123);
+intent.setParam("longParam", 123456789L);
+intent.setParam("booleanParam", true);
+intent.setParam("doubleParam", 3.14);
+```
+
+### 传递数组
+
+```java
+String[] array = {"item1", "item2", "item3"};
+intent.setParam("arrayParam", array);
+```
+
+### 传递序列化对象
+
+```java
+// 自定义对象需要实现 Sequenceable 接口
+MyData myData = new MyData();
+intent.setParam("objectParam", myData);
+```
+
+## 🐛 常见问题
+
+### 1. JS Ability 无法启动
+
+**原因**:包名或 Ability 名称错误
+
+**解决**:检查 config.json 中的配置和调用代码中的名称是否一致
+
+### 2. 参数无法传递
+
+**原因**:参数类型不支持或 JS 端未正确获取
+
+**解决**:使用支持的基本类型,或将复杂对象转为 JSON 字符串
+
+### 3. 无法接收返回结果
+
+**原因**:使用了 `startAbility` 而不是 `startAbilityForResult`
+
+**解决**:使用 `startAbilityForResult` 并实现 `onAbilityResult` 方法
+
+### 4. JS 端获取不到参数
+
+**原因**:参数获取时机不对或方法使用错误
+
+**解决**:在 `onInit` 或 `onShow` 中使用 `featureAbility.getContext().getWant()` 获取
+
+## 📚 相关资源
+
+- [HarmonyOS API 7 文档](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/api-version-mapping-0000001050154953)
+- [Ability 开发指南](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-brief-0000000000029430)
+- [Intent 使用说明](https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-intent-0000001054278947)
+
+## 📄 许可证
+
+本示例代码遵循项目原有许可证。
+

+ 271 - 0
entry/docs/QUICK_EXAMPLE.java

@@ -0,0 +1,271 @@
+// ============================================
+// 快速示例:在现有 Ability 中调用 JS Ability
+// ============================================
+
+// 1. 在你的 Ability 中导入必要的类
+import ohos.aafwk.content.Intent;
+import ohos.aafwk.content.Operation;
+import com.fujica.abk.utils.JsAbilityHelper;
+
+// ============================================
+// 示例 1:在按钮点击事件中启动 JS Ability
+// ============================================
+public class MainAbilitySlice extends AbilitySlice {
+    
+    @Override
+    public void onStart(Intent intent) {
+        super.onStart(intent);
+        
+        // 创建一个按钮
+        Button button = new Button(this);
+        button.setText("打开 JS 页面");
+        button.setClickedListener(component -> {
+            // 调用 JS Ability
+            JsAbilityHelper.startJsAbility(
+                getAbility(),                  // 当前 Ability
+                "com.fujica.abk",             // 你的应用包名
+                "com.fujica.abk.JsAbility",   // JS Ability 名称
+                "Hello from Java!",           // 传递的消息
+                "测试数据"                     // 传递的数据
+            );
+        });
+        
+        // 添加到界面
+        // ... 你的布局代码
+    }
+}
+
+// ============================================
+// 示例 2:手动创建 Intent 启动(不使用工具类)
+// ============================================
+public void startJsAbilityManually() {
+    // 创建 Intent
+    Intent intent = new Intent();
+    
+    // 设置目标 Ability
+    Operation operation = new Intent.OperationBuilder()
+            .withDeviceId("")                      // 空字符串表示本设备
+            .withBundleName("com.fujica.abk")      // 应用包名
+            .withAbilityName("com.fujica.abk.JsAbility")  // JS Ability 完整名称
+            .build();
+    
+    intent.setOperation(operation);
+    
+    // 添加参数
+    intent.setParam("message", "Hello from Java");
+    intent.setParam("data", "测试数据");
+    intent.setParam("userId", 12345);
+    intent.setParam("isVip", true);
+    
+    // 启动 Ability
+    startAbility(intent);
+}
+
+// ============================================
+// 示例 3:启动 JS Ability 并接收返回结果
+// ============================================
+public class MyAbility extends Ability {
+    
+    private static final int REQUEST_CODE = 1001;
+    
+    // 启动 JS Ability
+    public void callJsAbilityForResult() {
+        Intent intent = new Intent();
+        
+        Operation operation = new Intent.OperationBuilder()
+                .withDeviceId("")
+                .withBundleName("com.fujica.abk")
+                .withAbilityName("com.fujica.abk.JsAbility")
+                .build();
+        
+        intent.setOperation(operation);
+        intent.setParam("action", "getData");
+        
+        // 启动并等待返回结果
+        startAbilityForResult(intent, REQUEST_CODE);
+    }
+    
+    // 接收返回结果
+    @Override
+    protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
+        super.onAbilityResult(requestCode, resultCode, resultData);
+        
+        if (requestCode == REQUEST_CODE && resultData != null) {
+            // 获取 JS Ability 返回的数据
+            String status = resultData.getStringParam("status");
+            String data = resultData.getStringParam("data");
+            long timestamp = resultData.getLongParam("timestamp", 0);
+            
+            // 处理返回的数据
+            HiLog.info(LABEL, "收到返回: status=" + status + ", data=" + data);
+            
+            // 更新 UI 或执行其他操作
+            Toast.info(this, "收到 JS 返回的数据: " + data);
+        }
+    }
+}
+
+// ============================================
+// 示例 4:传递复杂 JSON 数据
+// ============================================
+public void sendJsonData() {
+    // 创建 JSON 对象
+    ZSONObject jsonData = new ZSONObject();
+    jsonData.put("userId", "123456");
+    jsonData.put("userName", "张三");
+    jsonData.put("age", 25);
+    jsonData.put("isVip", true);
+    
+    // 嵌套对象
+    ZSONObject address = new ZSONObject();
+    address.put("city", "北京");
+    address.put("district", "朝阳区");
+    jsonData.put("address", address);
+    
+    // 使用工具类发送
+    JsAbilityHelper.startJsAbilityWithJson(
+        this,
+        "com.fujica.abk",
+        "com.fujica.abk.JsAbility",
+        jsonData
+    );
+}
+
+// ============================================
+// 示例 5:在 JS 端接收和返回数据(index.js)
+// ============================================
+/*
+import featureAbility from '@ohos.ability.featureAbility';
+
+export default {
+    data: {
+        message: '',
+        receivedData: ''
+    },
+    
+    // 接收参数
+    onInit() {
+        console.info('JS Ability 启动');
+        
+        var context = featureAbility.getContext();
+        context.getWant((error, want) => {
+            if (error) {
+                console.error('获取参数失败: ' + JSON.stringify(error));
+                return;
+            }
+            
+            // 获取 Java 传递的参数
+            if (want.parameters) {
+                this.message = want.parameters.message || '';
+                this.receivedData = want.parameters.data || '';
+                
+                console.info('message: ' + this.message);
+                console.info('data: ' + this.receivedData);
+                
+                // 如果传递了 JSON 数据
+                if (want.parameters.jsonData) {
+                    var json = JSON.parse(want.parameters.jsonData);
+                    console.info('userId: ' + json.userId);
+                    console.info('userName: ' + json.userName);
+                }
+            }
+        });
+    },
+    
+    // 返回数据给 Java
+    returnDataToJava() {
+        var result = {
+            resultCode: 1,  // 返回码
+            want: {
+                parameters: {
+                    status: 'success',
+                    data: 'JS 处理后的数据',
+                    timestamp: new Date().getTime(),
+                    result: {
+                        code: 200,
+                        message: '操作成功'
+                    }
+                }
+            }
+        };
+        
+        var context = featureAbility.getContext();
+        context.terminateSelfWithResult(result, (error) => {
+            if (error) {
+                console.error('返回失败: ' + JSON.stringify(error));
+            } else {
+                console.info('成功返回数据并关闭');
+            }
+        });
+    },
+    
+    // 简单关闭(不返回数据)
+    close() {
+        var context = featureAbility.getContext();
+        context.terminateSelf();
+    }
+}
+*/
+
+// ============================================
+// 示例 6:完整的实战场景
+// ============================================
+public class OrderDetailAbility extends Ability {
+    
+    // 场景:从订单详情页面跳转到支付页面(JS 实现)
+    private void gotoPaymentPage(String orderId, double amount) {
+        Intent intent = new Intent();
+        
+        // 设置目标
+        Operation operation = new Intent.OperationBuilder()
+                .withBundleName("com.fujica.abk")
+                .withAbilityName("com.fujica.abk.JsAbility")
+                .build();
+        intent.setOperation(operation);
+        
+        // 传递订单信息
+        intent.setParam("page", "payment");  // 指定打开的页面
+        intent.setParam("orderId", orderId);
+        intent.setParam("amount", String.valueOf(amount));
+        intent.setParam("fromPage", "orderDetail");
+        
+        // 启动支付页面并等待支付结果
+        startAbilityForResult(intent, 2001);
+    }
+    
+    @Override
+    protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
+        if (requestCode == 2001 && resultData != null) {
+            // 处理支付结果
+            String payStatus = resultData.getStringParam("payStatus");
+            String orderId = resultData.getStringParam("orderId");
+            
+            if ("success".equals(payStatus)) {
+                Toast.success(this, "支付成功!");
+                // 刷新订单状态
+                refreshOrderStatus(orderId);
+            } else if ("failed".equals(payStatus)) {
+                Toast.error(this, "支付失败");
+            } else if ("cancelled".equals(payStatus)) {
+                Toast.info(this, "已取消支付");
+            }
+        }
+    }
+    
+    private void refreshOrderStatus(String orderId) {
+        // 刷新订单状态的逻辑
+    }
+}
+
+// ============================================
+// 重要提示
+// ============================================
+/*
+1. 确保 config.json 中已注册 JS Ability
+2. 包名和 Ability 名称必须完全匹配
+3. 参数只能传递基本类型,复杂对象需要序列化为 JSON
+4. 使用 startAbilityForResult 才能接收返回结果
+5. JS 端使用 featureAbility.getContext() 获取上下文
+6. JS 端使用 terminateSelfWithResult 返回数据
+*/
+

BIN
entry/libs/mapslibrary-release.har


+ 2 - 49
entry/src/main/config.json

@@ -3,8 +3,8 @@
     "vendor": "fujica",
     "bundleName": "com.fujica.abk",
     "version": {
-      "code": 1000001,
-      "name": "1.0.1"
+      "code": 1000000,
+      "name": "1.0.0"
     }
   },
   "deviceConfig": {
@@ -125,35 +125,9 @@
             ],
             "updateEnabled": true,
             "updateDuration": 1
-          },
-          {
-            "jsComponentName": "widget1",
-            "isDefault": false,
-            "scheduledUpdateTime": "10:30",
-            "defaultDimension": "2*2",
-            "name": "widget1",
-            "description": "爱泊客停车缴费",
-            "colorMode": "auto",
-            "type": "JS",
-            "supportDimensions": [
-              "2*4","2*2"
-            ],
-            "updateEnabled": true,
-            "updateDuration": 1
           }
         ],
         "launchType": "standard"
-      },
-      {
-        "orientation": "landscape",
-        "visible": true,
-        "name": ".JsAbility",
-        "srcPath": "jsability",
-        "icon": "$media:icon",
-        "description": "JS Ability 示例",
-        "label": "JS Ability",
-        "type": "page",
-        "launchType": "standard"
       }
     ],
     "distro": {
@@ -175,27 +149,6 @@
           "autoDesignWidth": true
         },
         "type": "form"
-      },
-      {
-        "name": "widget1",
-        "pages": [
-          "pages/index/index"
-        ],
-        "window": {
-          "designWidth": 720,
-          "autoDesignWidth": true
-        },
-        "type": "form"
-      },
-      {
-        "name": "jsability",
-        "pages": [
-          "pages/index/index"
-        ],
-        "window": {
-          "designWidth": 720,
-          "autoDesignWidth": true
-        }
       }
     ]
   }

+ 4 - 5
entry/src/main/java/com/fujica/abk/api/auth.java

@@ -110,6 +110,7 @@ public class auth {
             data.put("code", hwResult.getCode()); // 需要从授权结果中获取
             data.put("openId", hwResult.getOpenId());
             data.put("unionId", hwResult.getUnionId());
+            data.put("source", "7");
             option.setData(data);
             processCodeLogin(context, option, hwResult, future);
             return;
@@ -136,6 +137,7 @@ public class auth {
                  data.put("code", hwResult.getCode()); // 需要从授权结果中获取
                 data.put("openId", hwResult.getOpenId());
                 data.put("unionId", hwResult.getUnionId());
+                data.put("source", "7");
                 option.setData(data);
 
                 processCodeLogin(context, option, hwResult, future);
@@ -217,6 +219,7 @@ public class auth {
         //     data.put("openId", hwResult.getOpenId());
         //     data.put("unionId", hwResult.getUnionId());
         //     data.put("appId", config.appId);
+            // data.put("source", 7);
         //     option.setData(data);
         //     
         //     return api.post1(context, option).thenApply(result -> {
@@ -259,11 +262,7 @@ public class auth {
                 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) {
+                Toast.error(context, "登录失败:" + e.getStatusCode());
                 future.complete(new HWResult(false));
                 return future;
             }

+ 6 - 0
entry/src/main/java/com/fujica/abk/api/cache.java

@@ -96,6 +96,12 @@ public class cache {
     public static void setOpenId(Context context, String value) {
         set(context, KEY_OPEN_ID, value);
     }
+    /**
+     * 设置OpenId
+     */
+    public static String getOpenId(Context context) {
+        return get(context, KEY_OPEN_ID);
+    }
 
 
     /**

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

@@ -10,6 +10,6 @@ public class config {
         return  isDebug? "wxd3598cc7953b6a59" : "116162389";
     }
 
-    public static boolean isDebug = true; // 是否调试模式
+    public static boolean isDebug = false; // 是否调试模式
 }
 

+ 1 - 1
entry/src/main/java/com/fujica/abk/component/ParkItemComponent.java

@@ -147,7 +147,7 @@ public class ParkItemComponent extends DirectionalLayout {
 
             // 设置距离和地址
             String distanceStr = parkData.getDistance() != null ?
-                    String.format("%.1fkm", parkData.getDistance() / 1000.0) : "0km";
+                    String.format("%.2fkm", parkData.getDistance() / 1000) : "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);

+ 143 - 76
entry/src/main/java/com/fujica/abk/component/QRCodeScanDialog.java

@@ -15,6 +15,9 @@ import ohos.eventhandler.EventHandler;
 import ohos.eventhandler.EventRunner;
 import ohos.media.image.PixelMap;
 
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 /**
@@ -29,34 +32,37 @@ public class QRCodeScanDialog {
     private OnPayResultListener payResultListener;
     private OnCloseListener closeListener;
     private String paySceneCode = "ALI_PCRE"; // 默认支付宝扫码支付
-    
+
     // UI组件
     private Image imgQRCode;
     private Text txtTitle;
     private Text txtLoading;
     private Button btnCancelPay;
-    
+
     // 倒计时相关
     private static final int COUNTDOWN_SECONDS = 180; // 3分钟 = 180秒
     private int remainingSeconds = COUNTDOWN_SECONDS;
     private EventHandler countdownHandler;
     private boolean isCountdownRunning = false;
-    
+
     // 支付查询相关
     private String payNo;
     private boolean isPollingPayStatus = false;
     private static final int POLL_INTERVAL = 3000; // 轮询间隔3秒
     private boolean isClosedByPayResult = false; // 是否由支付结果关闭的
-    
+    private Runnable startPollingTask; // 延迟启动轮询的任务
+
     /**
      * 支付结果回调接口
      */
     public interface OnPayResultListener {
         void onPaySuccess(String payNo);
+
         void onPayFailed(String errorMsg);
+
         void onPayTimeout();
     }
-    
+
     /**
      * 弹框关闭回调接口
      * 用于在弹框关闭时触发ChargeComponent的刷新
@@ -64,7 +70,7 @@ public class QRCodeScanDialog {
     public interface OnCloseListener {
         void onClose();
     }
-    
+
     /**
      * 构造函数
      */
@@ -72,53 +78,54 @@ public class QRCodeScanDialog {
         this.context = context;
         initDialog();
     }
-    
+
     /**
      * 设置费用信息
      */
     public void setFeeInfo(ParkingFeeInfo feeInfo) {
         this.feeInfo = feeInfo;
     }
-    
+
     /**
      * 设置支付结果监听器
      */
     public void setOnPayResultListener(OnPayResultListener listener) {
         this.payResultListener = listener;
     }
-    
+
     /**
      * 设置弹框关闭监听器
      */
     public void setOnCloseListener(OnCloseListener listener) {
         this.closeListener = listener;
     }
-    
+
     /**
      * 设置支付场景代码
+     *
      * @param paySceneCode 支付场景代码(如:WX_NA-微信Native支付,ALI_PCRE-支付宝扫码支付)
      */
     public void setPaySceneCode(String paySceneCode) {
         this.paySceneCode = paySceneCode;
     }
-    
+
     /**
      * 初始化对话框
      */
     private void initDialog() {
         // 创建 CommonDialog
         dialog = new CommonDialog(context);
-        
+
         // 加载自定义布局
         dialogRootView = LayoutScatter.getInstance(context)
                 .parse(ResourceTable.Layout_layout_qrcode_scan_dialog, null, false);
-        
+
         // 获取UI组件
         imgQRCode = (Image) dialogRootView.findComponentById(ResourceTable.Id_img_qrcode);
         txtTitle = (Text) dialogRootView.findComponentById(ResourceTable.Id_txt_title);
         txtLoading = (Text) dialogRootView.findComponentById(ResourceTable.Id_txt_loading);
         btnCancelPay = (Button) dialogRootView.findComponentById(ResourceTable.Id_btn_cancel_pay);
-        
+
         // 设置关闭按钮点击事件
         Image btnClose = (Image) dialogRootView.findComponentById(ResourceTable.Id_btn_close_scan);
         if (btnClose != null) {
@@ -127,7 +134,7 @@ public class QRCodeScanDialog {
                 hide();
             });
         }
-        
+
         // 设置取消支付按钮点击事件
         if (btnCancelPay != null) {
             btnCancelPay.setClickedListener(component -> {
@@ -135,20 +142,20 @@ public class QRCodeScanDialog {
                 hide();
             });
         }
-        
+
         // 设置对话框内容
         dialog.setContentCustomComponent(dialogRootView);
-        
+
         // 设置对话框属性
         dialog.setTransparent(true); // 设置透明背景
         dialog.setSize(ComponentContainer.LayoutConfig.MATCH_PARENT,
                 ComponentContainer.LayoutConfig.MATCH_PARENT);
         dialog.setAlignment(LayoutAlignment.CENTER);
-        
+
         // 初始化倒计时Handler
         countdownHandler = new EventHandler(EventRunner.getMainEventRunner());
     }
-    
+
     /**
      * 调用支付接口生成订单和二维码
      */
@@ -157,10 +164,34 @@ public class QRCodeScanDialog {
             showError("支付信息缺失");
             return;
         }
-        
+
         // 显示加载提示
         showLoading(true);
-        
+
+
+        ArrayList<String> subOrderIdList = new ArrayList<>();
+        String trueOrderId = "";
+        //车道码有临停和欠费补缴逻辑
+        if (feeInfo.getActualAmount() > 0 && (feeInfo.getFollowList() == null || feeInfo.getFollowList().isEmpty())) {
+            trueOrderId = feeInfo.getOrderId();
+        } else if (feeInfo.getActualAmount() == 0 && feeInfo.getFollowList()!=null && feeInfo.getFollowList().size() == 1) {
+            //如果没有停车费只有一笔欠费,取followId
+            trueOrderId = feeInfo.getFollowList().get(0).getFollowId();
+        } else {
+            //多笔缴费取mainOrderId
+            trueOrderId = feeInfo.getMainOrderId();
+            if (feeInfo.getActualAmount() > 0) {
+                subOrderIdList.add(feeInfo.getOrderId());
+                for (com.fujica.abk.model.out.ArrearageOrder item : feeInfo.getFollowList()) {
+                    subOrderIdList.add(item.getFollowId());
+                }
+            } else {
+                for (com.fujica.abk.model.out.ArrearageOrder item : feeInfo.getFollowList()) {
+                    subOrderIdList.add(item.getFollowId());
+                }
+            }
+        }
+
         // 构建支付请求参数
         PayRequest request = new PayRequest();
         request.setActualAmount(feeInfo.getActualAmount() != null ? feeInfo.getActualAmount() : 1);
@@ -168,41 +199,45 @@ public class QRCodeScanDialog {
         request.setDiscountAmount(feeInfo.getDiscountAmount() != null ? feeInfo.getDiscountAmount() : 0);
         request.setDoubleConfirm(true);
         request.setGoodsName(feeInfo.getPlateNo() != null ? feeInfo.getPlateNo() : "停车费");
-        request.setOrderId(feeInfo.getOrderId());
+        request.setOrderId(trueOrderId);
+        request.setSubOrderIdList(subOrderIdList);
         request.setParkId(feeInfo.getParkId());
         request.setParkName(feeInfo.getParkName());
         request.setPaySceneCode(paySceneCode); // 使用设置的支付场景代码
         request.setPaySourceCode("HW_CAR"); // 华为车机
         request.setProjectNo(feeInfo.getProjectNo()); // 项目编号
-        request.setTotalAmount(feeInfo.getTotalAmount() != null ? feeInfo.getTotalAmount() : 1);
-        
+        request.setTotalAmount(calculateActualAmount());
+
         Log.info("发起支付请求: orderId=" + request.getOrderId());
-        
+
         // 调用支付接口
         CompletableFuture<R<PayResponse>> future = pay.payByUnify(context, request);
         future.thenAccept(result -> {
             context.getUITaskDispatcher().asyncDispatch(() -> {
                 showLoading(false);
-                
+
                 if (result != null && result.isSuccess() && result.getData() != null) {
                     PayResponse payData = result.getData();
                     String qrCode = payData.getQrCode();
                     payNo = payData.getOutTradeNo();
-                    
+
                     if (qrCode != null && !qrCode.isEmpty()) {
                         // 生成并显示二维码
                         displayQRCode(qrCode);
-                        
+
                         // 开始倒计时
                         startCountdown();
-                        
-                        // 开始轮询支付状态
-                        startPaymentPolling();
+
+                        // 延迟10秒后开始轮询支付状态
+                        startPollingTask = () -> {
+                            startPaymentPolling();
+                        };
+                        countdownHandler.postTask(startPollingTask, 10000); // 10000毫秒 = 10秒
                     } else {
                         showError("未获取到支付二维码");
                     }
                 } else {
-                    String errorMsg = result != null && result.getMsg() != null ? 
+                    String errorMsg = result != null && result.getMsg() != null ?
                             result.getMsg() : "生成支付订单失败";
                     showError(errorMsg);
                 }
@@ -216,7 +251,7 @@ public class QRCodeScanDialog {
             return null;
         });
     }
-    
+
     /**
      * 显示二维码
      */
@@ -225,7 +260,7 @@ public class QRCodeScanDialog {
             // 生成二维码图片
             int qrCodeSize = 800; // 二维码像素大小
             PixelMap qrCodePixelMap = QRCodeUtil.generateQRCode(qrCodeContent, qrCodeSize);
-            
+
             if (qrCodePixelMap != null && imgQRCode != null) {
                 imgQRCode.setPixelMap(qrCodePixelMap);
                 Log.info("二维码生成成功");
@@ -239,7 +274,7 @@ public class QRCodeScanDialog {
             showError("二维码显示失败");
         }
     }
-    
+
     /**
      * 开始倒计时
      */
@@ -247,15 +282,15 @@ public class QRCodeScanDialog {
         if (isCountdownRunning) {
             return;
         }
-        
+
         isCountdownRunning = true;
         remainingSeconds = COUNTDOWN_SECONDS;
         updateCountdownText();
-        
+
         // 使用Handler进行倒计时
         countdownRunnable.run();
     }
-    
+
     /**
      * 停止倒计时
      */
@@ -263,9 +298,13 @@ public class QRCodeScanDialog {
         isCountdownRunning = false;
         if (countdownHandler != null) {
             countdownHandler.removeTask(countdownRunnable);
+            // 移除延迟启动轮询的任务
+            if (startPollingTask != null) {
+                countdownHandler.removeTask(startPollingTask);
+            }
         }
     }
-    
+
     /**
      * 倒计时Runnable
      */
@@ -275,10 +314,10 @@ public class QRCodeScanDialog {
             if (!isCountdownRunning) {
                 return;
             }
-            
+
             remainingSeconds--;
             updateCountdownText();
-            
+
             if (remainingSeconds <= 0) {
                 // 倒计时结束
                 onCountdownFinished();
@@ -288,7 +327,7 @@ public class QRCodeScanDialog {
             }
         }
     };
-    
+
     /**
      * 更新倒计时文本
      */
@@ -304,23 +343,23 @@ public class QRCodeScanDialog {
             txtTitle.setText(titleText);
         }
     }
-    
+
     /**
      * 倒计时结束处理
      */
     private void onCountdownFinished() {
         stopCountdown();
         stopPaymentPolling();
-        
+
         // 标记为由支付结果关闭
         isClosedByPayResult = true;
         hide();
-        
+
         // 回调支付超时
         if (payResultListener != null) {
             payResultListener.onPayTimeout();
         }
-        
+
         // 显示支付失败弹窗(超时)
         PayFailDialog failDialog = new PayFailDialog(context);
         failDialog.setErrorMsg("支付超时,请重新支付");
@@ -330,11 +369,11 @@ public class QRCodeScanDialog {
                 closeListener.onClose();
             }
         });
-        
+
         // 显示失败对话框
         failDialog.show();
     }
-    
+
     /**
      * 开始轮询支付状态
      */
@@ -343,18 +382,18 @@ public class QRCodeScanDialog {
             Log.error("payNo为空,无法轮询支付状态");
             return;
         }
-        
+
         isPollingPayStatus = true;
-        
+
         // 创建轮询任务
         new Thread(() -> {
             while (isPollingPayStatus && remainingSeconds > 0) {
                 try {
                     Thread.sleep(POLL_INTERVAL);
-                    
+
                     // 查询支付状态
                     checkPaymentStatus();
-                    
+
                 } catch (InterruptedException e) {
                     Log.error("支付状态查询线程中断: " + e.getMessage());
                     break;
@@ -362,14 +401,36 @@ public class QRCodeScanDialog {
             }
         }).start();
     }
-    
+
     /**
      * 停止轮询支付状态
      */
     private void stopPaymentPolling() {
         isPollingPayStatus = false;
     }
-    
+
+
+    /**
+     * 计算实际支付金额
+     * 参考 pay.vue 中的 actualAmount computed 属性
+     */
+    private int calculateActualAmount() {
+//        DecimalFormat df = new DecimalFormat("0.00");
+        int total = 0;
+
+        // 实付金额
+        if (feeInfo.getActualAmount() != null) {
+            total = feeInfo.getActualAmount();
+        }
+
+        // 加上历史欠费(如果有)
+        if (feeInfo.getFollowSum() != null && feeInfo.getFollowSum() > 0) {
+            total += feeInfo.getFollowSum();
+        }
+        return total;
+//        return df.format(total);
+    }
+
     /**
      * 查询支付状态
      */
@@ -377,7 +438,7 @@ public class QRCodeScanDialog {
         if (payNo == null || payNo.isEmpty()) {
             return;
         }
-        
+
         CompletableFuture<R<PayStatusResponse>> future = pay.queryPayStatus(context, payNo);
         future.thenAccept(result -> {
             // 检查是否应该继续处理响应:
@@ -388,7 +449,7 @@ public class QRCodeScanDialog {
                 Log.info("支付状态查询响应被忽略:对话框已关闭或轮询已停止");
                 return;
             }
-            
+
             if (result != null && result.isSuccess() && result.getData() != null) {
                 Integer status = result.getData().getPayStatus();
 
@@ -413,7 +474,7 @@ public class QRCodeScanDialog {
             return null;
         });
     }
-    
+
     /**
      * 支付成功处理
      */
@@ -421,11 +482,11 @@ public class QRCodeScanDialog {
         context.getUITaskDispatcher().asyncDispatch(() -> {
             stopCountdown();
             stopPaymentPolling();
-            
+
             // 标记为由支付结果关闭
             isClosedByPayResult = true;
             hide();
-            
+
             // 显示支付成功弹窗
             PaySuccessDialog successDialog = new PaySuccessDialog(context);
             successDialog.setPayAmount(feeInfo != null ? feeInfo.getActualAmount() : 0);
@@ -435,28 +496,28 @@ public class QRCodeScanDialog {
                     closeListener.onClose();
                 }
             });
-            
+
             // 显示成功对话框
             successDialog.show();
-            
+
             // 回调支付成功
             if (payResultListener != null) {
                 payResultListener.onPaySuccess(payNo);
             }
         });
     }
-    
+
     /**
      * 支付失败处理
      */
     private void onPaymentFailed(String errorMsg) {
         stopCountdown();
         stopPaymentPolling();
-        
+
         // 标记为由支付结果关闭
         isClosedByPayResult = true;
         hide();
-        
+
         // 显示支付失败弹窗
         PayFailDialog failDialog = new PayFailDialog(context);
         failDialog.setErrorMsg(errorMsg);
@@ -466,16 +527,16 @@ public class QRCodeScanDialog {
                 closeListener.onClose();
             }
         });
-        
+
         // 显示失败对话框
         failDialog.show();
-        
+
         // 回调支付失败
         if (payResultListener != null) {
             payResultListener.onPayFailed(errorMsg);
         }
     }
-    
+
     /**
      * 显示/隐藏加载提示
      */
@@ -490,20 +551,20 @@ public class QRCodeScanDialog {
             btnCancelPay.setVisibility(show ? Component.HIDE : Component.VISIBLE);
         }
     }
-    
+
     /**
      * 显示错误信息
      */
     private void showError(String errorMsg) {
         Toast.error(context, errorMsg);
         hide();
-        
+
         // 回调支付失败
         if (payResultListener != null) {
             payResultListener.onPayFailed(errorMsg);
         }
     }
-    
+
     /**
      * 显示对话框
      */
@@ -514,38 +575,44 @@ public class QRCodeScanDialog {
         // 弹框显示时自动调用支付接口
         createPayOrder();
     }
-    
+
     /**
      * 隐藏对话框
      */
     public void hide() {
         stopCountdown();
         stopPaymentPolling();
-        
+
         // 只有在手动关闭(非支付结果关闭)时,才触发刷新回调
         // 支付结果关闭时,会在支付成功/失败弹窗关闭后才触发回调
         if (!isClosedByPayResult && closeListener != null) {
             closeListener.onClose();
         }
-        
+
         // 重置标志
         isClosedByPayResult = false;
-        
+
         // 隐藏对话框
         if (dialog != null) {
             dialog.hide();
         }
     }
-    
+
     /**
      * 销毁对话框,释放资源
      */
     public void destroy() {
         stopCountdown();
         stopPaymentPolling();
+        
+        // 清理延迟任务
+        if (countdownHandler != null && startPollingTask != null) {
+            countdownHandler.removeTask(startPollingTask);
+        }
+        
         payResultListener = null;
         closeListener = null;
-        
+
         // 释放二维码图片资源
         if (imgQRCode != null && imgQRCode.getPixelMap() != null) {
             imgQRCode.getPixelMap().release();

+ 11 - 11
entry/src/main/java/com/fujica/abk/component/nav/ChargeComponent.java

@@ -383,17 +383,17 @@ public class ChargeComponent extends DirectionalLayout {
                     updateParkingInfo(feeInfo);
 
                     // 处理 feeType 16:有历史欠费订单(临停加欠费补缴)
-                    if (feeInfo.getFeeType() == 16 && feeInfo.getFollowList() != null && !feeInfo.getFollowList().isEmpty()) {
-                        int arrearageCount = feeInfo.getFollowList().size();
-                        String message = "您有" + arrearageCount + "笔历史欠费订单(不含本次停车订单)尚未支付,请尽快处理";
-                        showArrearageDialog(message, feeInfo, "立即补缴");
-                    }
-                    // 处理 feeType 13:本次停车未产生费用,但有历史欠费订单
-                    else if (feeInfo.getFeeType() == 13 && feeInfo.getFollowList() != null && !feeInfo.getFollowList().isEmpty()) {
-                        int arrearageCount = feeInfo.getFollowList().size();
-                        String message = "本次停车未产生费用,但您仍有" + arrearageCount + "笔历史欠费订单尚未支付,请尽快处理";
-                        showArrearageDialog(message, feeInfo, "立即补缴");
-                    }
+//                    if (feeInfo.getFeeType() == 16 && feeInfo.getFollowList() != null && !feeInfo.getFollowList().isEmpty()) {
+//                        int arrearageCount = feeInfo.getFollowList().size();
+//                        String message = "您有" + arrearageCount + "笔历史欠费订单(不含本次停车订单)尚未支付,请尽快处理";
+//                        showArrearageDialog(message, feeInfo, "立即补缴");
+//                    }
+//                    // 处理 feeType 13:本次停车未产生费用,但有历史欠费订单
+//                    else if (feeInfo.getFeeType() == 13 && feeInfo.getFollowList() != null && !feeInfo.getFollowList().isEmpty()) {
+//                        int arrearageCount = feeInfo.getFollowList().size();
+//                        String message = "本次停车未产生费用,但您仍有" + arrearageCount + "笔历史欠费订单尚未支付,请尽快处理";
+//                        showArrearageDialog(message, feeInfo, "立即补缴");
+//                    }
 
                     // TODO: 检查车辆认证状态
                     // 这里需要获取用户的车辆列表,检查当前车牌是否已认证(status == 2)

+ 7 - 4
entry/src/main/java/com/fujica/abk/component/nav/OrderComponent.java

@@ -1,6 +1,7 @@
 package com.fujica.abk.component.nav;
 
 import com.fujica.abk.ResourceTable;
+import com.fujica.abk.api.cache;
 import com.fujica.abk.component.LoadingComponent;
 import com.fujica.abk.component.OrderItemComponent;
 import com.fujica.abk.model.out.OrderRes;
@@ -34,7 +35,7 @@ public class OrderComponent extends DirectionalLayout {
     private DirectionalLayout orderListContainer; // 订单列表容器
 
     // 筛选参数
-    private String bizType = "全部"; // 业务类型:全部、停车、月卡
+    private String bizType = "停车"; // 业务类型:全部、停车、月卡(暂时只使用"停车")
     private String paySuccessTime = ""; // 支付成功时间(格式:YYYY-MM)
 
     // 分页相关
@@ -86,8 +87,8 @@ public class OrderComponent extends DirectionalLayout {
         int year = calendar.get(Calendar.YEAR);
         int month = calendar.get(Calendar.MONTH) + 1;
 
-        year = 2024;
-        month = 8;
+//        year = 2024;
+//        month = 8;
 
         paySuccessTime = String.format("%d-%02d", year, month);
 
@@ -206,7 +207,8 @@ public class OrderComponent extends DirectionalLayout {
      * 显示业务类型筛选下拉对话框
      */
     private void showBizTypeFilterDialog() {
-        String[] options = {"全部", "停车", "月卡"};
+        // 暂时只使用"停车"作为查询条件
+        String[] options = {"停车"}; // {"全部", "停车", "月卡"};
         
         // 找到当前选中的索引
         int currentIndex = -1;
@@ -311,6 +313,7 @@ public class OrderComponent extends DirectionalLayout {
         if (bizTypeValue != 0) {
             params.put("bizType", bizTypeValue);
         }
+        params.put("goodsName", cache.getDefaultPlateNo(getContext()));
 
         // 构建请求URL
         ApiOption option = new ApiOption();

+ 34 - 8
entry/src/main/java/com/fujica/abk/component/nav/ParkComponent.java

@@ -147,6 +147,17 @@ public class ParkComponent extends DirectionalLayout {
 
                     // 延迟执行查询,实现防抖效果
                     searchHandler.postTask(() -> {
+                        // 根据是否有输入来控制距离下拉框的显示/隐藏
+                        if (btnDistanceFilter != null) {
+                            if (s != null && !s.trim().isEmpty()) {
+                                // 有输入时隐藏距离下拉框
+                                btnDistanceFilter.setVisibility(HIDE);
+                            } else {
+                                // 无输入时显示距离下拉框
+                                btnDistanceFilter.setVisibility(VISIBLE);
+                            }
+                        }
+                        
                         // 重新加载数据
                         switchTab(filterType);
                         // 加载数据
@@ -330,15 +341,22 @@ public class ParkComponent extends DirectionalLayout {
                     @Override
                     public void onLocationReport(Location location) {
                         Log.info("onLocationReport: ");
-                        // 保存当前位置坐标
-                        double latitude = location.getLatitude();
-                        double longitude = location.getLongitude();
-                        if (latitude == 0 && longitude == 0) {
+                        // 保存当前位置坐标(WGS84坐标)
+                        double wgsLatitude = location.getLatitude();
+                        double wgsLongitude = location.getLongitude();
+                        if (wgsLatitude == 0 && wgsLongitude == 0) {
                             Toast.error(getContext(), "无法获取到您附近车场");
                         } else {
-                            // 保存位置到缓存
+                            // 将WGS84坐标转换为GCJ-02坐标(火星坐标系)
+                            // 中国地图服务通常使用GCJ-02坐标系,GPS原始坐标会有50-600米偏差
+                            double[] gcj02 = CoordinateUtil.wgs84ToGcj02(wgsLatitude, wgsLongitude);
+                            double latitude = gcj02[0];
+                            double longitude = gcj02[1];
+                            
+                            // 保存转换后的GCJ-02坐标到缓存
                             cache.setLocation(context, latitude, longitude);
-                            Log.info("位置已保存到缓存: 纬度=" + latitude + ", 经度=" + longitude);
+                            Log.info("GPS坐标(WGS84): 纬度=" + wgsLatitude + ", 经度=" + wgsLongitude);
+                            Log.info("转换后坐标(GCJ-02): 纬度=" + latitude + ", 经度=" + longitude);
                         }
                         DialogUtil.postTask(() -> {
                             switchTab(filterType);
@@ -402,9 +420,11 @@ public class ParkComponent extends DirectionalLayout {
 
         // 获取车场名称输入框的值
         String parkName = "";
+        boolean hasParkName = false;
         if (inputParkName != null) {
             String inputText = inputParkName.getText();
             if (inputText != null && !inputText.trim().isEmpty()) {
+                hasParkName = true;
                 try {
                     parkName = URLEncoder.encode(inputText.trim(), "UTF-8");
                 } catch (Exception e) {
@@ -415,8 +435,14 @@ public class ParkComponent extends DirectionalLayout {
 
         // 构建请求URL(使用锁定的页码)
         ApiOption option = new ApiOption();
-        option.setUrl(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));
+        // 如果有输入车场名称,则不传递distance参数
+        if (hasParkName) {
+            option.setUrl(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));
+        } else {
+            option.setUrl(String.format("/park/near/page?distance=%d&type=%d&filter=%d&latitude=%f&longitude=%f&current=%d&size=%d&parkName=%s",
+                   this.selectedDistance, filterType, selectedFilter, latitude, longitude, requestPage, pageSize, parkName));
+        }
         option.setMethod(ApiOption.GET);
 
         // 发送请求(网络请求已在后台线程)

+ 1 - 0
entry/src/main/java/com/fujica/abk/manager/CardTriggerManager.java

@@ -224,6 +224,7 @@ public class CardTriggerManager {
         // 构建请求URL
         ApiOption option = new ApiOption();
         option.setUrl(String.format("/park/near/page?type=2&filter=2&latitude=%f&longitude=%f&current=1&size=10", latitude, longitude));
+        // option.setUrl(String.format("/park/near/page?type=2&filter=2&distance=20000&latitude=%f&longitude=%f&current=1&size=10", latitude, longitude));
         option.setMethod(ApiOption.GET);
 
         CompletableFuture<R<Page<ParkNearRes>>> future = api.http(context, option, new TypeToken<R<Page<ParkNearRes>>>() {

+ 11 - 0
entry/src/main/java/com/fujica/abk/model/in/PayRequest.java

@@ -1,5 +1,7 @@
 package com.fujica.abk.model.in;
 
+import java.util.ArrayList;
+
 /**
  * 支付请求参数
  */
@@ -10,6 +12,7 @@ public class PayRequest {
     private Boolean doubleConfirm;     // 是否需要二次确认
     private String goodsName;          // 商品名称(如车牌号)
     private String orderId;            // 订单ID
+    private ArrayList<String> subOrderIdList;   //多笔订单
     private String parkId;             // 车场ID
     private String parkName;           // 车场名称
     private String paySceneCode;       // 支付场景编码: WX_NA-微信Native支付
@@ -20,6 +23,14 @@ public class PayRequest {
     public PayRequest() {
     }
 
+    public ArrayList<String> getSubOrderIdList() {
+        return subOrderIdList;
+    }
+
+    public void setSubOrderIdList(ArrayList<String> subOrderIdList) {
+        this.subOrderIdList = subOrderIdList;
+    }
+
     public Integer getActualAmount() {
         return actualAmount;
     }

+ 6 - 5
entry/src/main/java/com/fujica/abk/model/out/ArrearageOrder.java

@@ -7,18 +7,19 @@ import com.fujica.abk.utils.api;
  * 欠费订单信息类
  */
 public class ArrearageOrder {
-    private String orderId;        // 订单ID
+    private String followId;        // 订单ID
     private String parkName;       // 车场名称
     private int amount;            // 欠费金额(分)
     private String createTime;     // 创建时间
     private String plateNo;        // 车牌号
 
-    public String getOrderId() {
-        return orderId;
+
+    public String getFollowId() {
+        return followId;
     }
 
-    public void setOrderId(String orderId) {
-        this.orderId = orderId;
+    public void setFollowId(String followId) {
+        this.followId = followId;
     }
 
     public String getParkName() {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 21 - 2
entry/src/main/java/com/fujica/abk/model/out/ParkingFeeInfo.java


+ 21 - 0
entry/src/main/java/com/fujica/abk/slice/JsAbility.java

@@ -0,0 +1,21 @@
+package com.fujica.abk.slice;
+
+import ohos.aafwk.content.Intent;
+import ohos.ace.ability.AceAbility;
+
+/**
+ * Java Ability 调用 JS Ability 示例
+ * 演示多种调用方式
+ */
+public class JsAbility extends AceAbility {
+    @Override
+    public void onStart(Intent intent) {
+        super.onStart(intent);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+    }
+}
+

+ 194 - 0
entry/src/main/java/com/fujica/abk/slice/JsAbilityDemoSlice.java

@@ -0,0 +1,194 @@
+package com.fujica.abk.slice;
+
+import com.fujica.abk.ResourceTable;
+import com.fujica.abk.utils.JsAbilityHelper;
+import ohos.aafwk.ability.AbilitySlice;
+import ohos.aafwk.content.Intent;
+import ohos.agp.components.Button;
+import ohos.agp.components.Component;
+import ohos.agp.components.DirectionalLayout;
+import ohos.agp.components.Text;
+import ohos.agp.utils.Color;
+import ohos.agp.utils.LayoutAlignment;
+import ohos.hiviewdfx.HiLog;
+import ohos.hiviewdfx.HiLogLabel;
+import ohos.utils.zson.ZSONObject;
+
+/**
+ * Java Ability 调用 JS Ability 示例
+ * 演示多种调用方式
+ */
+public class JsAbilityDemoSlice extends AbilitySlice {
+    
+    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "JsAbilityDemo");
+    private static final String BUNDLE_NAME = "com.fujica.abk";
+    private static final String JS_ABILITY_NAME = "com.fujica.abk.JsAbility";
+    
+    private Text resultText;
+    
+    @Override
+    public void onStart(Intent intent) {
+        super.onStart(intent);
+        
+        // 创建布局
+        DirectionalLayout layout = createLayout();
+        super.setUIContent(layout);
+        
+        HiLog.info(LABEL, "JsAbilityDemoSlice 已启动");
+    }
+    
+    /**
+     * 创建演示界面
+     */
+    private DirectionalLayout createLayout() {
+        DirectionalLayout layout = new DirectionalLayout(this);
+        layout.setWidth(DirectionalLayout.LayoutConfig.MATCH_PARENT);
+        layout.setHeight(DirectionalLayout.LayoutConfig.MATCH_PARENT);
+        layout.setOrientation(Component.VERTICAL);
+        layout.setPadding(50, 50, 50, 50);
+        layout.setAlignment(LayoutAlignment.CENTER);
+        
+        // 标题
+        Text title = new Text(this);
+        title.setText("Java 调用 JS Ability 示例");
+        title.setTextSize(60);
+        title.setTextColor(Color.BLACK);
+        title.setMarginBottom(40);
+        layout.addComponent(title);
+        
+        // 按钮1:简单启动
+        Button button1 = createButton("方式一:启动 JS Ability");
+        button1.setClickedListener(component -> {
+            HiLog.info(LABEL, "点击:启动 JS Ability");
+            JsAbilityHelper.startJsAbility(
+                getAbility(),
+                BUNDLE_NAME,
+                JS_ABILITY_NAME,
+                "来自 Java 的问候",
+                "这是传递的数据"
+            );
+        });
+        layout.addComponent(button1);
+        
+        // 按钮2:启动并等待返回
+        Button button2 = createButton("方式二:启动并等待返回结果");
+        button2.setClickedListener(component -> {
+            HiLog.info(LABEL, "点击:启动 JS Ability 并等待返回");
+            JsAbilityHelper.startJsAbilityForResult(
+                getAbility(),
+                BUNDLE_NAME,
+                JS_ABILITY_NAME,
+                "请返回数据",
+                "Request ID: " + System.currentTimeMillis()
+            );
+        });
+        layout.addComponent(button2);
+        
+        // 按钮3:传递 JSON 数据
+        Button button3 = createButton("方式三:传递 JSON 数据");
+        button3.setClickedListener(component -> {
+            HiLog.info(LABEL, "点击:传递 JSON 数据");
+            
+            // 创建 JSON 对象
+            ZSONObject jsonData = new ZSONObject();
+            jsonData.put("userId", "123456");
+            jsonData.put("userName", "张三");
+            jsonData.put("action", "query");
+            jsonData.put("timestamp", System.currentTimeMillis());
+            
+            JsAbilityHelper.startJsAbilityWithJson(
+                getAbility(),
+                BUNDLE_NAME,
+                JS_ABILITY_NAME,
+                jsonData
+            );
+        });
+        layout.addComponent(button3);
+        
+        // 按钮4:从 Slice 启动
+        Button button4 = createButton("方式四:从 Slice 启动");
+        button4.setClickedListener(component -> {
+            HiLog.info(LABEL, "点击:从 Slice 启动");
+            JsAbilityHelper.startJsAbilityFromSlice(
+                this,
+                BUNDLE_NAME,
+                JS_ABILITY_NAME,
+                "从 Slice 发送",
+                "Slice 数据"
+            );
+        });
+        layout.addComponent(button4);
+        
+        // 显示返回结果的文本
+        resultText = new Text(this);
+        resultText.setText("等待 JS Ability 返回结果...");
+        resultText.setTextSize(40);
+        resultText.setTextColor(new Color(0xFF666666));
+        resultText.setMarginTop(60);
+        resultText.setMultipleLine(true);
+        resultText.setMaxTextLines(5);
+        layout.addComponent(resultText);
+        
+        return layout;
+    }
+    
+    /**
+     * 创建按钮
+     */
+    private Button createButton(String text) {
+        Button button = new Button(this);
+        button.setText(text);
+        button.setTextSize(40);
+        button.setTextColor(Color.WHITE);
+        button.setWidth(800);
+        button.setHeight(100);
+        button.setMarginTop(20);
+//        button.setBackgroundColor(new Color(0xFF007DFF));
+        return button;
+    }
+    
+    @Override
+    protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
+        super.onAbilityResult(requestCode, resultCode, resultData);
+        
+        HiLog.info(LABEL, "收到 JS Ability 返回结果");
+        HiLog.info(LABEL, "requestCode: " + requestCode);
+        HiLog.info(LABEL, "resultCode: " + resultCode);
+        
+        if (requestCode == JsAbilityHelper.getRequestCode()) {
+            if (resultData != null) {
+                // 获取返回的数据
+                String status = resultData.getStringParam("status");
+                String data = resultData.getStringParam("data");
+                long timestamp = resultData.getLongParam("timestamp", 0);
+                
+                String result = "返回结果:\n" +
+                        "状态: " + status + "\n" +
+                        "数据: " + data + "\n" +
+                        "时间戳: " + timestamp;
+                
+                HiLog.info(LABEL, result);
+                
+                // 显示在界面上
+                if (resultText != null) {
+                    resultText.setText(result);
+                }
+            } else {
+                resultText.setText("JS Ability 未返回数据");
+            }
+        }
+    }
+    
+    @Override
+    public void onActive() {
+        super.onActive();
+        HiLog.info(LABEL, "JsAbilityDemoSlice onActive");
+    }
+    
+    @Override
+    public void onForeground(Intent intent) {
+        super.onForeground(intent);
+        HiLog.info(LABEL, "JsAbilityDemoSlice onForeground");
+    }
+}
+

+ 4 - 2
entry/src/main/java/com/fujica/abk/slice/MainAbilitySlice.java

@@ -126,7 +126,9 @@ public class MainAbilitySlice extends AbilitySlice {
 
         Button mBtnHuaweiIdSignIn = findComponentById(ResourceTable.Id_btn_hwid_sign_in);
         mBtnHuaweiIdSignIn.setClickedListener((Component c) -> {
-            huaweiIdSignIn();
+//            huaweiIdSignIn();
+            
+
         });
 
         // 订阅登录成功事件
@@ -400,7 +402,7 @@ public class MainAbilitySlice extends AbilitySlice {
                     // 登录成功后切换到缴费记录页面
                     DialogUtil.postTask(() -> switchToPage(index));
                 } else {
-                    Toast.error(this, "登录失败,请重试");
+//                    Toast.error(this, "登录失败,请重试");
                 }
             }).exceptionally(e -> {
                 Log.error("登录异常: " + e.getMessage());

+ 173 - 0
entry/src/main/java/com/fujica/abk/utils/CoordinateUtil.java

@@ -0,0 +1,173 @@
+package com.fujica.abk.utils;
+
+/**
+ * 坐标转换工具类
+ * 用于处理中国地图坐标系偏移问题
+ * 
+ * 坐标系说明:
+ * - WGS84:GPS原始坐标系(国际标准,地球坐标系)
+ * - GCJ-02:中国国家测绘局坐标系(火星坐标系),在WGS84基础上加密偏移
+ * - BD-09:百度坐标系,在GCJ-02基础上再次偏移
+ */
+public class CoordinateUtil {
+    
+    // 常量定义 - GCJ-02坐标转换使用克拉索夫斯基(Krasovsky 1940)椭球参数
+    private static final double PI = 3.14159265358979324; // 圆周率
+    private static final double A = 6378245.0; // 长半轴(米)
+    private static final double EE = 0.00669342162296594323; // 偏心率平方
+    
+    /**
+     * 判断坐标是否在中国境内
+     * 不在中国境内则不做偏移
+     */
+    private static boolean outOfChina(double lat, double lon) {
+        if (lon < 72.004 || lon > 137.8347) {
+            return true;
+        }
+        if (lat < 0.8293 || lat > 55.8271) {
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * 转换纬度
+     */
+    private static double transformLat(double x, double y) {
+        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y 
+                     + 0.2 * Math.sqrt(Math.abs(x));
+        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
+        ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
+        ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
+        return ret;
+    }
+    
+    /**
+     * 转换经度
+     */
+    private static double transformLon(double x, double y) {
+        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y 
+                     + 0.1 * Math.sqrt(Math.abs(x));
+        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
+        ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
+        ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
+        return ret;
+    }
+    
+    /**
+     * WGS84坐标转GCJ-02坐标(火星坐标)
+     * 
+     * @param wgsLat WGS84纬度
+     * @param wgsLon WGS84经度
+     * @return double数组,[0]为GCJ-02纬度,[1]为GCJ-02经度
+     */
+    public static double[] wgs84ToGcj02(double wgsLat, double wgsLon) {
+        // 如果不在中国境内,不进行转换
+        if (outOfChina(wgsLat, wgsLon)) {
+            return new double[]{wgsLat, wgsLon};
+        }
+        
+        double dLat = transformLat(wgsLon - 105.0, wgsLat - 35.0);
+        double dLon = transformLon(wgsLon - 105.0, wgsLat - 35.0);
+        
+        double radLat = wgsLat / 180.0 * PI;
+        double magic = Math.sin(radLat);
+        magic = 1 - EE * magic * magic;
+        double sqrtMagic = Math.sqrt(magic);
+        
+        dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
+        dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
+        
+        double gcjLat = wgsLat + dLat;
+        double gcjLon = wgsLon + dLon;
+        
+        return new double[]{gcjLat, gcjLon};
+    }
+    
+    /**
+     * GCJ-02坐标转WGS84坐标
+     * 
+     * @param gcjLat GCJ-02纬度
+     * @param gcjLon GCJ-02经度
+     * @return double数组,[0]为WGS84纬度,[1]为WGS84经度
+     */
+    public static double[] gcj02ToWgs84(double gcjLat, double gcjLon) {
+        // 如果不在中国境内,不进行转换
+        if (outOfChina(gcjLat, gcjLon)) {
+            return new double[]{gcjLat, gcjLon};
+        }
+        
+        double dLat = transformLat(gcjLon - 105.0, gcjLat - 35.0);
+        double dLon = transformLon(gcjLon - 105.0, gcjLat - 35.0);
+        
+        double radLat = gcjLat / 180.0 * PI;
+        double magic = Math.sin(radLat);
+        magic = 1 - EE * magic * magic;
+        double sqrtMagic = Math.sqrt(magic);
+        
+        dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
+        dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
+        
+        double wgsLat = gcjLat - dLat;
+        double wgsLon = gcjLon - dLon;
+        
+        return new double[]{wgsLat, wgsLon};
+    }
+    
+    /**
+     * GCJ-02坐标转BD-09坐标(百度坐标)
+     * 
+     * @param gcjLat GCJ-02纬度
+     * @param gcjLon GCJ-02经度
+     * @return double数组,[0]为BD-09纬度,[1]为BD-09经度
+     */
+    public static double[] gcj02ToBd09(double gcjLat, double gcjLon) {
+        double z = Math.sqrt(gcjLon * gcjLon + gcjLat * gcjLat) + 0.00002 * Math.sin(gcjLat * PI);
+        double theta = Math.atan2(gcjLat, gcjLon) + 0.000003 * Math.cos(gcjLon * PI);
+        double bdLon = z * Math.cos(theta) + 0.0065;
+        double bdLat = z * Math.sin(theta) + 0.006;
+        return new double[]{bdLat, bdLon};
+    }
+    
+    /**
+     * BD-09坐标转GCJ-02坐标
+     * 
+     * @param bdLat BD-09纬度
+     * @param bdLon BD-09经度
+     * @return double数组,[0]为GCJ-02纬度,[1]为GCJ-02经度
+     */
+    public static double[] bd09ToGcj02(double bdLat, double bdLon) {
+        double x = bdLon - 0.0065;
+        double y = bdLat - 0.006;
+        double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * PI);
+        double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * PI);
+        double gcjLon = z * Math.cos(theta);
+        double gcjLat = z * Math.sin(theta);
+        return new double[]{gcjLat, gcjLon};
+    }
+    
+    /**
+     * WGS84坐标转BD-09坐标(百度坐标)
+     * 
+     * @param wgsLat WGS84纬度
+     * @param wgsLon WGS84经度
+     * @return double数组,[0]为BD-09纬度,[1]为BD-09经度
+     */
+    public static double[] wgs84ToBd09(double wgsLat, double wgsLon) {
+        double[] gcj02 = wgs84ToGcj02(wgsLat, wgsLon);
+        return gcj02ToBd09(gcj02[0], gcj02[1]);
+    }
+    
+    /**
+     * BD-09坐标转WGS84坐标
+     * 
+     * @param bdLat BD-09纬度
+     * @param bdLon BD-09经度
+     * @return double数组,[0]为WGS84纬度,[1]为WGS84经度
+     */
+    public static double[] bd09ToWgs84(double bdLat, double bdLon) {
+        double[] gcj02 = bd09ToGcj02(bdLat, bdLon);
+        return gcj02ToWgs84(gcj02[0], gcj02[1]);
+    }
+}
+

+ 199 - 0
entry/src/main/java/com/fujica/abk/utils/JsAbilityHelper.java

@@ -0,0 +1,199 @@
+package com.fujica.abk.utils;
+
+import ohos.aafwk.ability.Ability;
+import ohos.aafwk.ability.AbilitySlice;
+import ohos.aafwk.content.Intent;
+import ohos.aafwk.content.Operation;
+import ohos.hiviewdfx.HiLog;
+import ohos.hiviewdfx.HiLogLabel;
+import ohos.utils.zson.ZSONObject;
+
+/**
+ * Java Ability 调用 JS Ability 工具类
+ * 适用于 HarmonyOS API 7
+ */
+public class JsAbilityHelper {
+    
+    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "JsAbilityHelper");
+    private static final int REQUEST_CODE = 1001;
+    
+    /**
+     * 方式一:启动 JS Ability(不需要返回结果)
+     * 
+     * @param ability 当前的 Ability
+     * @param bundleName 应用包名
+     * @param abilityName JS Ability 名称
+     * @param message 要传递的消息
+     * @param data 要传递的数据
+     */
+    public static void startJsAbility(Ability ability, String bundleName, String abilityName, 
+                                     String message, String data) {
+        HiLog.info(LABEL, "准备启动 JS Ability: " + abilityName);
+        
+        try {
+            // 创建 Intent
+            Intent intent = new Intent();
+            
+            // 设置 Operation
+            Operation operation = new Intent.OperationBuilder()
+                    .withDeviceId("")  // 空字符串表示本设备
+                    .withBundleName(bundleName)
+                    .withAbilityName(abilityName)
+                    .build();
+            
+            intent.setOperation(operation);
+            
+            // 添加参数
+            if (message != null) {
+                intent.setParam("message", message);
+            }
+            if (data != null) {
+                intent.setParam("data", data);
+            }
+            
+            // 启动 Ability
+            ability.startAbility(intent);
+            
+            HiLog.info(LABEL, "成功启动 JS Ability");
+            
+        } catch (Exception e) {
+            HiLog.error(LABEL, "启动 JS Ability 失败: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * 方式二:启动 JS Ability(需要返回结果)
+     * 
+     * @param ability 当前的 Ability
+     * @param bundleName 应用包名
+     * @param abilityName JS Ability 名称
+     * @param message 要传递的消息
+     * @param data 要传递的数据
+     */
+    public static void startJsAbilityForResult(Ability ability, String bundleName, 
+                                               String abilityName, String message, String data) {
+        HiLog.info(LABEL, "准备启动 JS Ability 并等待返回结果: " + abilityName);
+        
+        try {
+            // 创建 Intent
+            Intent intent = new Intent();
+            
+            // 设置 Operation
+            Operation operation = new Intent.OperationBuilder()
+                    .withDeviceId("")
+                    .withBundleName(bundleName)
+                    .withAbilityName(abilityName)
+                    .build();
+            
+            intent.setOperation(operation);
+            
+            // 添加参数
+            if (message != null) {
+                intent.setParam("message", message);
+            }
+            if (data != null) {
+                intent.setParam("data", data);
+            }
+            
+            // 启动 Ability 并等待返回结果
+            ability.startAbilityForResult(intent, REQUEST_CODE);
+            
+            HiLog.info(LABEL, "成功启动 JS Ability 等待返回");
+            
+        } catch (Exception e) {
+            HiLog.error(LABEL, "启动 JS Ability 失败: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * 方式三:从 AbilitySlice 启动 JS Ability(不需要返回结果)
+     * 
+     * @param slice 当前的 AbilitySlice
+     * @param bundleName 应用包名
+     * @param abilityName JS Ability 名称
+     * @param message 要传递的消息
+     * @param data 要传递的数据
+     */
+    public static void startJsAbilityFromSlice(AbilitySlice slice, String bundleName, 
+                                               String abilityName, String message, String data) {
+        HiLog.info(LABEL, "从 Slice 启动 JS Ability: " + abilityName);
+        
+        try {
+            // 创建 Intent
+            Intent intent = new Intent();
+            
+            // 设置 Operation
+            Operation operation = new Intent.OperationBuilder()
+                    .withDeviceId("")
+                    .withBundleName(bundleName)
+                    .withAbilityName(abilityName)
+                    .build();
+            
+            intent.setOperation(operation);
+            
+            // 添加参数
+            if (message != null) {
+                intent.setParam("message", message);
+            }
+            if (data != null) {
+                intent.setParam("data", data);
+            }
+            
+            // 从 Slice 启动 Ability
+            slice.startAbility(intent);
+            
+            HiLog.info(LABEL, "成功从 Slice 启动 JS Ability");
+            
+        } catch (Exception e) {
+            HiLog.error(LABEL, "从 Slice 启动 JS Ability 失败: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * 方式四:传递复杂对象(使用 JSON)
+     * 
+     * @param ability 当前的 Ability
+     * @param bundleName 应用包名
+     * @param abilityName JS Ability 名称
+     * @param jsonData JSON 数据对象
+     */
+    public static void startJsAbilityWithJson(Ability ability, String bundleName, 
+                                              String abilityName, ZSONObject jsonData) {
+        HiLog.info(LABEL, "启动 JS Ability 并传递 JSON 数据");
+        
+        try {
+            // 创建 Intent
+            Intent intent = new Intent();
+            
+            // 设置 Operation
+            Operation operation = new Intent.OperationBuilder()
+                    .withDeviceId("")
+                    .withBundleName(bundleName)
+                    .withAbilityName(abilityName)
+                    .build();
+            
+            intent.setOperation(operation);
+            
+            // 添加 JSON 数据
+            if (jsonData != null) {
+                intent.setParam("jsonData", jsonData.toString());
+            }
+            
+            // 启动 Ability
+            ability.startAbility(intent);
+            
+            HiLog.info(LABEL, "成功启动 JS Ability (JSON)");
+            
+        } catch (Exception e) {
+            HiLog.error(LABEL, "启动 JS Ability 失败: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * 获取请求码(用于处理返回结果)
+     */
+    public static int getRequestCode() {
+        return REQUEST_CODE;
+    }
+}
+

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

@@ -58,7 +58,8 @@ public class api {
     // 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"; //UAT环境
     // private static String host = "https://gatewayservicev2test.fujica.com.cn/transfer/mobile"; //PRE环境
 
     // 前端nginx连接

+ 0 - 39
entry/src/main/js/jsability/pages/index/index.css

@@ -1,39 +0,0 @@
-.container {
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
-    align-items: center;
-    width: 100%;
-    height: 100%;
-    background-color: #f5f5f5;
-}
-
-.title {
-    font-size: 48px;
-    color: #1a1a1a;
-    margin-bottom: 20px;
-    font-weight: bold;
-}
-
-.message {
-    font-size: 32px;
-    color: #333333;
-    margin-bottom: 16px;
-}
-
-.data {
-    font-size: 28px;
-    color: #666666;
-    margin-bottom: 40px;
-}
-
-.button {
-    width: 400px;
-    height: 80px;
-    font-size: 32px;
-    background-color: #007dff;
-    color: #ffffff;
-    border-radius: 8px;
-    margin-top: 20px;
-}
-

+ 0 - 8
entry/src/main/js/jsability/pages/index/index.hml

@@ -1,8 +0,0 @@
-<div class="container">
-    <text class="title">JS Ability 页面</text>
-    <text class="message">{{ message }}</text>
-    <text class="data">接收到的数据: {{ receivedData }}</text>
-    <input class="button" type="button" value="返回数据给 Java" onclick="returnData"></input>
-    <input class="button" type="button" value="关闭页面" onclick="closePage"></input>
-</div>
-

+ 0 - 84
entry/src/main/js/jsability/pages/index/index.js

@@ -1,84 +0,0 @@
-import router from '@system.router';
-import featureAbility from '@ohos.ability.featureAbility';
-
-export default {
-    data: {
-        message: '欢迎来到 JS Ability',
-        receivedData: '无'
-    },
-    onInit() {
-        console.info('JS Ability onInit');
-        // 获取从 Java Ability 传递过来的参数
-        this.getIntentParams();
-    },
-    onShow() {
-        console.info('JS Ability onShow');
-    },
-    onHide() {
-        console.info('JS Ability onHide');
-    },
-    onDestroy() {
-        console.info('JS Ability onDestroy');
-    },
-    
-    // 获取 Intent 参数
-    getIntentParams() {
-        var context = featureAbility.getContext();
-        context.getWant((error, want) => {
-            if (error) {
-                console.error('获取 Intent 参数失败: ' + JSON.stringify(error));
-                return;
-            }
-            console.info('获取到的 Want: ' + JSON.stringify(want));
-            
-            // 获取传递的参数
-            if (want.parameters) {
-                var dataFromJava = want.parameters.data;
-                var messageFromJava = want.parameters.message;
-                
-                if (dataFromJava) {
-                    this.receivedData = dataFromJava;
-                }
-                if (messageFromJava) {
-                    this.message = messageFromJava;
-                }
-            }
-        });
-    },
-    
-    // 返回数据给 Java Ability
-    returnData() {
-        var result = {
-            resultCode: 1,
-            want: {
-                parameters: {
-                    status: 'success',
-                    data: 'JS Ability 返回的数据',
-                    timestamp: new Date().getTime()
-                }
-            }
-        };
-        
-        var context = featureAbility.getContext();
-        context.terminateSelfWithResult(result, (error) => {
-            if (error) {
-                console.error('返回数据失败: ' + JSON.stringify(error));
-            } else {
-                console.info('成功返回数据并关闭页面');
-            }
-        });
-    },
-    
-    // 关闭页面
-    closePage() {
-        var context = featureAbility.getContext();
-        context.terminateSelf((error) => {
-            if (error) {
-                console.error('关闭页面失败: ' + JSON.stringify(error));
-            } else {
-                console.info('成功关闭页面');
-            }
-        });
-    }
-}
-

BIN
entry/src/main/js/widget1/common/ic_default_image@3x.png


+ 0 - 6
entry/src/main/js/widget1/i18n/en-US.json

@@ -1,6 +0,0 @@
-{
-  "strings": {
-    "title": "Today's delicious food",
-    "detail": "A bowl of fragrant fried noodles, back to childhood memories"
-  }
-}

+ 0 - 6
entry/src/main/js/widget1/i18n/zh-CN.json

@@ -1,6 +0,0 @@
-{
-  "strings": {
-    "title": "爱泊客",
-    "detail": "富士智能大厦停车场"
-  }
-}

+ 0 - 61
entry/src/main/js/widget1/pages/index/index.css

@@ -1,61 +0,0 @@
-.container {
-    flex-direction: column;
-    justify-content: center;
-    align-items: center;
-}
-.bg-img{
-    flex-shrink: 0;
-    height: 100%;
-}
-.container-inner {
-    flex-direction: column;
-    justify-content: flex-end;
-    align-items: flex-start;
-    height: 100%;
-    width: 100%;
-    padding: 12px;
-}
-.title {
-    font-size: 19px;
-    font-weight: bold;
-    color: white;
-    text-overflow: ellipsis;
-    max-lines: 1;
-}
-.detail_text {
-    font-size: 16px;
-    color: white;
-    opacity: 0.66;
-    text-overflow: ellipsis;
-    max-lines: 1;
-    margin-top: 6px;
-}
-@media (device-type: tablet) {
-    .bg-img {
-        object-fit: fill;
-    }
-}
-@media (device-type: wearable) {
-    .container-inner {
-        justify-content: center;
-        align-items: center;
-        margin: 40px 26px;
-        padding: 0;
-    }
-    .title {
-        text-align: center;
-    }
-    .detail_text {
-        max-lines: 2;
-        text-align: center;
-    }
-}
-
-@media (device-type: tv) {
-    .title {
-        font-size: 16px;
-    }
-    .detail_text {
-        font-size: 12px;
-    }
-}

+ 0 - 11
entry/src/main/js/widget1/pages/index/index.hml

@@ -1,11 +0,0 @@
-<div class="container">
-    <stack>
-        <div class="container-img">
-            <image src="/common/ic_default_image@3x.png" class="bg-img" onclick="routerEvent"></image>
-        </div>
-        <div class="container-inner">
-            <text class="title">{{ $t('strings.title') }}</text>
-            <text class="detail_text"> {{ $t('strings.detail') }}</text>
-        </div>
-    </stack>
-</div>

+ 0 - 17
entry/src/main/js/widget1/pages/index/index.json

@@ -1,17 +0,0 @@
-{
-  "data": {
-    "title": "Title",
-    "detail": "Text",
-    "iconTitle": "Picture"
-  },
-  "actions": {
-    "routerEvent": {
-      "action": "router",
-      "bundleName": "com.fujica.abk",
-      "abilityName": "com.fujica.abk.MainAbility",
-      "params": {
-        "message": "add detail"
-      }
-    }
-  }
-}

+ 0 - 11
entry/src/main/js/widget1/pages/index/index1.hml

@@ -1,11 +0,0 @@
-<div class="container">
-    <stack>
-        <div class="container-img">
-            <image src="/common/ic_default_image@3x.png" class="bg-img" onclick="routerEvent"></image>
-        </div>
-        <div class="container-inner">
-            <text class="title">{{ $t('strings.title') }}</text>
-            <text class="detail_text"> {{ $t('strings.detail') }}</text>
-        </div>
-    </stack>
-</div>

+ 12 - 0
entry/src/main/resources/base/element/string.json

@@ -31,6 +31,18 @@
     {
       "name": "code_layout_title",
       "value": "代码布局页面"
+    },
+    {
+      "name": "jsability_label",
+      "value": "JS Ability"
+    },
+    {
+      "name": "jsability_description",
+      "value": "JS Ability 示例"
+    },
+    {
+      "name": "widget_description",
+      "value": "爱泊客停车缴费"
     }
   ]
 }

+ 7 - 9
entry/src/main/resources/base/layout/ability_main.xml

@@ -3,14 +3,14 @@
     xmlns:ohos="http://schemas.huawei.com/res/ohos"
     ohos:height="match_parent"
     ohos:width="match_parent"
-    ohos:background_element="#404040"
+    ohos:background_element="$media:bg"
     ohos:orientation="horizontal">
-
-    <PositionLayout
-        xmlns:ohos="http://schemas.huawei.com/res/ohos"
-        ohos:height="match_parent"
-        ohos:width="match_parent">
-    </PositionLayout>
+<!--ohos:background_element="#404040"-->
+<!--    <PositionLayout-->
+<!--        xmlns:ohos="http://schemas.huawei.com/res/ohos"-->
+<!--        ohos:height="match_parent"-->
+<!--        ohos:width="match_parent">-->
+<!--    </PositionLayout>-->
 
     <!-- 主内容区域 - 水平布局 -->
     <DirectionalLayout
@@ -20,8 +20,6 @@
         ohos:orientation="horizontal">
 
         <!-- 左侧内容区域 - 垂直布局 -->
-
-
         <StackLayout
             xmlns:ohos="http://schemas.huawei.com/res/ohos"
             ohos:height="match_parent"

+ 8 - 8
entry/src/main/resources/base/layout/dialog_authorization.xml

@@ -47,18 +47,18 @@
             ohos:bottom_margin="12vp"
             ohos:orientation="horizontal">
 
-            <Text
-                ohos:height="match_content"
-                ohos:width="match_content"
-                ohos:right_margin="8vp"
-                ohos:text="·"
-                ohos:text_color="#FF666666"
-                ohos:text_size="16fp"/>
+<!--            <Text-->
+<!--                ohos:height="match_content"-->
+<!--                ohos:width="match_content"-->
+<!--                ohos:right_margin="8vp"-->
+<!--                ohos:text="·"-->
+<!--                ohos:text_color="#FF666666"-->
+<!--                ohos:text_size="16fp"/>-->
 
             <Text
                 ohos:height="match_content"
                 ohos:width="match_content"
-                ohos:text="获取您的手机号"
+                ohos:text="获取您的华为账号授权一键登录"
                 ohos:text_color="#FF666666"
                 ohos:text_size="16fp"/>
         </DirectionalLayout>

+ 1 - 0
entry/src/main/resources/base/layout/layout_charge.xml

@@ -291,6 +291,7 @@
 
             <Button
                 ohos:id="$+id:btn_renew"
+                ohos:visibility="hide"
                 ohos:height="48vp"
                 ohos:width="match_parent"
                 ohos:background_element="$graphic:button"

+ 38 - 53
entry/src/main/resources/base/layout/layout_pay_detail_dialog.xml

@@ -42,7 +42,7 @@
             ohos:width="match_parent"
             ohos:left_padding="16vp"
             ohos:right_padding="16vp"
-            ohos:bottom_padding="16vp"
+            ohos:bottom_padding="12vp"
             ohos:top_padding="4vp"
             ohos:weight="1">
 
@@ -157,18 +157,11 @@
 
                 </DirectionalLayout>
 
-                <!-- 分隔线 -->
-                <DirectionalLayout
-                    ohos:height="1vp"
-                    ohos:width="match_parent"
-                    ohos:background_element="#FFEEEEEE"
-                    ohos:bottom_margin="16vp"/>
-
                 <!-- 费用信息组 -->
                 <DirectionalLayout
                     ohos:height="match_content"
                     ohos:width="match_parent"
-                    ohos:bottom_margin="16vp"
+                    ohos:bottom_margin="12vp"
                     ohos:orientation="vertical">
 
                     <!-- 停车费 -->
@@ -232,7 +225,7 @@
                         ohos:width="match_parent"
                         ohos:bottom_margin="12vp"
                         ohos:orientation="horizontal"
-                        ohos:visibility="hide">
+                        ohos:visibility="visible">
 
                         <Text
                             ohos:height="match_content"
@@ -258,12 +251,6 @@
                                 ohos:text_alignment="right"
                                 ohos:text_color="#FF333333"
                                 ohos:text_size="16fp"/>
-
-                            <Image
-                                ohos:height="16vp"
-                                ohos:width="16vp"
-                                ohos:image_src="$media:close"
-                                ohos:scale_mode="zoom_center"/>
                         </DirectionalLayout>
                     </DirectionalLayout>
 
@@ -308,62 +295,60 @@
                         </DirectionalLayout>
                     </DirectionalLayout>
 
-                </DirectionalLayout>
-
-                <!-- 总计区域 -->
-                <DirectionalLayout
-                    ohos:height="match_content"
-                    ohos:width="match_parent"
-                    ohos:background_element="#FFF5F5F5"
-                    ohos:bottom_margin="12vp"
-                    ohos:orientation="horizontal"
-                    ohos:padding="12vp">
-
-                    <Text
-                        ohos:height="match_content"
-                        ohos:width="match_content"
-                        ohos:right_margin="20vp"
-                        ohos:text="总计"
-                        ohos:text_color="#FF999999"
-                        ohos:text_size="16fp"/>
 
                     <DirectionalLayout
                         ohos:height="match_content"
-                        ohos:width="0vp"
-                        ohos:alignment="right"
-                        ohos:orientation="horizontal"
-                        ohos:weight="1">
+                        ohos:width="match_parent"
+                        ohos:orientation="horizontal">
 
                         <Text
                             ohos:height="match_content"
                             ohos:width="match_content"
-                            ohos:text="¥"
-                            ohos:text_color="#FF333333"
-                            ohos:text_size="18fp"
-                            ohos:text_weight="700"/>
+                            ohos:right_margin="20vp"
+                            ohos:text="总计"
+                            ohos:text_color="#FF999999"
+                            ohos:text_size="16fp"/>
 
-                        <Text
-                            ohos:id="$+id:pay_detail_actual_amount"
+                        <DirectionalLayout
                             ohos:height="match_content"
-                            ohos:width="match_content"
-                            ohos:text="0.00"
-                            ohos:text_alignment="right"
-                            ohos:text_color="#FF333333"
-                            ohos:text_size="20fp"
-                            ohos:text_weight="700"/>
+                            ohos:width="0vp"
+                            ohos:alignment="right"
+                            ohos:orientation="horizontal"
+                            ohos:weight="1">
+
+                            <Text
+                                ohos:height="match_content"
+                                ohos:width="match_content"
+                                ohos:text="¥"
+                                ohos:text_color="#FF333333"
+                                ohos:text_size="18fp"
+                                ohos:text_weight="700"/>
+
+                            <Text
+                                ohos:id="$+id:pay_detail_actual_amount"
+                                ohos:height="match_content"
+                                ohos:width="match_content"
+                                ohos:text="0.00"
+                                ohos:text_alignment="right"
+                                ohos:text_color="#FF333333"
+                                ohos:text_size="20fp"
+                                ohos:text_weight="700"/>
+                        </DirectionalLayout>
                     </DirectionalLayout>
+
                 </DirectionalLayout>
 
+
                 <!-- 提示信息 -->
                 <Text
                     ohos:id="$+id:pay_detail_tip"
                     ohos:height="match_content"
                     ohos:width="match_parent"
-                    ohos:bottom_margin="16vp"
+                    ohos:bottom_margin="12vp"
                     ohos:text=""
                     ohos:text_color="#FF999999"
-                    ohos:text_size="12fp"
-                    ohos:visibility="hide"/>
+                    ohos:visibility="hide"
+                    ohos:text_size="12fp"/>
 
             </DirectionalLayout>
 

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