linee 3 tuần trước cách đây
mục cha
commit
3aebead8b4

+ 81 - 21
entry/src/main/java/com/fujica/abk/api/auth.java

@@ -1,6 +1,7 @@
 package com.fujica.abk.api;
 
 import com.fujica.abk.common.EventBus;
+import com.fujica.abk.component.AuthorizationDialog;
 import com.fujica.abk.model.out.LoginRes;
 import com.fujica.abk.utils.Log;
 import com.fujica.abk.utils.R;
@@ -25,6 +26,9 @@ import java.util.concurrent.CompletableFuture;
  * 认证工具类
  */
 public class auth {
+    // 登录状态标志,防止并发登录
+    private static boolean authing = false;
+    
     /**
      * 登录
      *
@@ -34,11 +38,51 @@ public class auth {
     public static CompletableFuture<Boolean> login(Context context) {
         CompletableFuture<Boolean> future = new CompletableFuture<>();
 
+        // 检查是否正在登录
+        if (authing) {
+            Log.info("正在登录中,请勿重复操作");
+            Toast.info(context, "正在登录中...");
+            future.complete(false);
+            return future;
+        }
+
         if (cache.isAuth(context)) {
             future.complete(true);
             return future;
         }
+        
+        // 设置登录状态
+        authing = true;
+        
+        // 登录之前先显示授权确认弹框
+        // 确保在主线程中执行
+        context.getUITaskDispatcher().asyncDispatch(() -> {
+            AuthorizationDialog authDialog = new AuthorizationDialog(context);
+            authDialog.setOnAuthorizationListener(new AuthorizationDialog.OnAuthorizationListener() {
+                @Override
+                public void onAuthorized() {
+                    // 用户确认授权后,继续登录流程
+                    proceedWithLogin(context, future);
+                }
+
+                @Override
+                public void onCancelled() {
+                    // 用户取消授权
+                    Toast.error(context, "已取消授权");
+                    authing = false; // 重置登录状态
+                    future.complete(false);
+                }
+            });
+            authDialog.show();
+        });
+        
+        return future;
+    }
 
+    /**
+     * 执行实际的登录流程
+     */
+    private static void proceedWithLogin(Context context, CompletableFuture<Boolean> future) {
         if (true) {
             HWResult hwResult = new HWResult();
 
@@ -62,7 +106,7 @@ public class auth {
             data.put("unionId", hwResult.getUnionId());
             option.setData(data);
             processCodeLogin(context, option, hwResult, future);
-            return future;
+            return;
         }
 
         try {
@@ -89,16 +133,22 @@ public class auth {
 
                 processCodeLogin(context, option, hwResult, future);
             }).exceptionally(e -> {
-                Log.error(e);
-                future.complete(false);
-                return null;
+                try {
+                    Log.error(e);
+                    future.complete(false);
+                    return null;
+                } finally {
+                    authing = false;
+                }
             });
         } catch (Exception e) {
-            Log.error(e);
-            future.complete(false);
+            try {
+                Log.error(e);
+                future.complete(false);
+            } finally {
+                authing = false;
+            }
         }
-
-        return future;
     }
 
     /**
@@ -112,21 +162,31 @@ public class auth {
     private static void processCodeLogin(Context context, ApiOption option, HWResult hwResult, CompletableFuture<Boolean> future) {
         api.http(context, option, new TypeToken<R<LoginRes>>() {
         }).thenAccept((R<LoginRes> result) -> {
-            if (result != null && result.isSuccess() && result.getData() != null) {
-                LoginRes res = result.getData();
-                cache.setOpenId(context, res.getOpenId());
-                cache.setToken(context, res.getToken());
-                cache.setMobile(context, res.getMobile());
-                // 发布登录成功事件,通知UI更新
-                EventBus.getInstance().emit("onLoginSuccess");
-                future.complete(true);
-            } else {
-                future.complete(false);
+            try {
+                if (result != null && result.isSuccess() && result.getData() != null) {
+                    LoginRes res = result.getData();
+                    cache.setOpenId(context, res.getOpenId());
+                    cache.setToken(context, res.getToken());
+                    cache.setMobile(context, res.getMobile());
+                    // 发布登录成功事件,通知UI更新
+                    EventBus.getInstance().emit("onLoginSuccess");
+                    future.complete(true);
+                } else {
+                    future.complete(false);
+                }
+            } finally {
+                // 确保最终重置登录状态
+                authing = false;
             }
         }).exceptionally(e -> {
-            Log.error(e);
-            future.complete(false);
-            return null;
+            try {
+                Log.error(e);
+                future.complete(false);
+                return null;
+            } finally {
+                // 确保最终重置登录状态
+                authing = false;
+            }
         });
     }
 

+ 87 - 0
entry/src/main/java/com/fujica/abk/component/AuthorizationDialog.java

@@ -0,0 +1,87 @@
+package com.fujica.abk.component;
+
+import com.fujica.abk.ResourceTable;
+import ohos.agp.components.Button;
+import ohos.agp.components.Component;
+import ohos.agp.components.LayoutScatter;
+import ohos.agp.window.dialog.CommonDialog;
+import ohos.app.Context;
+
+/**
+ * 授权确认对话框
+ */
+public class AuthorizationDialog extends CommonDialog {
+    private Context context;
+    private OnAuthorizationListener listener;
+
+    public AuthorizationDialog(Context context) {
+        super(context);
+        this.context = context;
+        initDialog();
+    }
+
+    /**
+     * 初始化对话框
+     */
+    private void initDialog() {
+        setAutoClosable(true);
+        setTransparent(true);
+        
+        // 加载自定义布局
+        Component dialogComponent = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_dialog_authorization, null, false);
+        setContentCustomComponent(dialogComponent);
+
+        // 授权按钮
+        Button btnAuthorize = (Button) dialogComponent.findComponentById(ResourceTable.Id_btn_authorize);
+        if (btnAuthorize != null) {
+            btnAuthorize.setClickedListener(v -> {
+                if (listener != null) {
+                    listener.onAuthorized();
+                }
+                destroy();
+            });
+        }
+
+        // 取消按钮
+        Button btnBack = (Button) dialogComponent.findComponentById(ResourceTable.Id_btn_back);
+        if (btnBack != null) {
+            btnBack.setClickedListener(v -> {
+                if (listener != null) {
+                    listener.onCancelled();
+                }
+                destroy();
+            });
+        }
+
+        // 设置对话框关闭监听
+        setDestroyedListener(() -> {
+            // 如果对话框被其他方式关闭(如点击外部),也视为取消
+            if (listener != null) {
+                // 这里可以根据需要决定是否调用 onCancelled
+            }
+        });
+    }
+
+    /**
+     * 设置授权监听器
+     */
+    public void setOnAuthorizationListener(OnAuthorizationListener listener) {
+        this.listener = listener;
+    }
+
+    /**
+     * 授权监听器接口
+     */
+    public interface OnAuthorizationListener {
+        /**
+         * 用户确认授权
+         */
+        void onAuthorized();
+
+        /**
+         * 用户取消授权
+         */
+        void onCancelled();
+    }
+}
+

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

@@ -604,6 +604,17 @@ public class MainAbilitySlice extends AbilitySlice {
                 }
                 // 可以在这里添加其他需要更新的UI逻辑
             });
+                // 认证过期后重新登录
+                auth.login(MainAbilitySlice.this).thenAccept(success -> {
+                    if (success) {
+                        Log.info("重新登录成功");
+                    } else {
+                        Log.error("重新登录失败");
+                    }
+                }).exceptionally(e -> {
+                    Log.error("重新登录异常: " + e.getMessage());
+                    return null;
+                });
         };
         EventBus.getInstance().on("onLoginExpired", authChangedListener);
     }

+ 9 - 0
entry/src/main/resources/base/graphic/button_authorize_bg.xml

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

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

@@ -0,0 +1,109 @@
+<?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:alignment="center"
+    ohos:orientation="vertical">
+
+    <DirectionalLayout
+        ohos:height="match_content"
+        ohos:width="400vp"
+        ohos:background_element="$graphic:background_circle_16"
+        ohos:orientation="vertical"
+        ohos:padding="32vp">
+
+        <!-- 顶部返回按钮和标题 -->
+        <DirectionalLayout
+            ohos:height="match_content"
+            ohos:width="match_parent"
+            ohos:bottom_margin="24vp"
+            ohos:orientation="horizontal">
+
+            <Text
+                ohos:height="match_content"
+                ohos:width="match_content"
+                ohos:text="华为账号登录"
+                ohos:text_color="#FF333333"
+                ohos:text_size="20fp"
+                ohos:text_weight="700"/>
+        </DirectionalLayout>
+
+        <!-- 申请标题 -->
+        <Text
+            ohos:height="match_content"
+            ohos:width="match_parent"
+            ohos:bottom_margin="16vp"
+            ohos:text="申请"
+            ohos:text_color="#FF666666"
+            ohos:text_size="16fp"
+            ohos:text_weight="600"/>
+
+        <!-- 申请项1 -->
+        <DirectionalLayout
+            ohos:height="match_content"
+            ohos:width="match_parent"
+            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:text="获取您的手机号"
+                ohos:text_color="#FF666666"
+                ohos:text_size="16fp"/>
+        </DirectionalLayout>
+
+        <!-- 授权说明 -->
+        <Text
+            ohos:height="match_content"
+            ohos:width="match_parent"
+            ohos:bottom_margin="32vp"
+            ohos:multiple_lines="true"
+            ohos:text="授权给【爱泊客】使用的数据由其隐私政策管理,您可随时在华为账号隐私中心取消授权。"
+            ohos:text_color="#FF999999"
+            ohos:text_size="13fp"/>
+
+        <DirectionalLayout
+            ohos:height="match_content"
+            ohos:width="match_parent"
+            ohos:orientation="horizontal">
+
+            <!-- 授权按钮 -->
+            <Button
+                ohos:id="$+id:btn_back"
+                ohos:height="48vp"
+                ohos:width="0"
+                ohos:background_element="$graphic:button_cancel"
+                ohos:text="取消"
+                ohos:text_color="#FFFFFFFF"
+                ohos:text_size="16fp"
+                ohos:text_weight="600"
+                ohos:weight="1"/>
+
+            <Button
+                ohos:id="$+id:btn_authorize"
+                ohos:height="48vp"
+                ohos:width="0"
+                ohos:left_margin="20vp"
+                ohos:background_element="$graphic:button"
+                ohos:text="授权登录"
+                ohos:text_color="#FFFFFFFF"
+                ohos:text_size="16fp"
+                ohos:text_weight="600"
+                ohos:weight="1"/>
+        </DirectionalLayout>
+
+    </DirectionalLayout>
+
+
+</DirectionalLayout>

+ 12 - 0
entry/src/main/resources/base/media/ic_back.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+    xmlns:ohos="http://schemas.huawei.com/res/ohos"
+    ohos:height="24vp"
+    ohos:width="24vp"
+    ohos:viewportHeight="24"
+    ohos:viewportWidth="24">
+    <path
+        ohos:fillColor="#FF333333"
+        ohos:pathData="M15.41,16.59L10.83,12l4.58-4.59L14,6l-6,6l6,6z"/>
+</vector>
+