Browse Source

feat: 引入最新鸿蒙工程(过滤 md/txt/sh/py/sql 等脚本文档)

wangmeng 5 days ago
parent
commit
7d9ad664b5
100 changed files with 12232 additions and 213 deletions
  1. 10 1
      .gitignore
  2. 3 3
      base-common/.preview/default/intermediates/merge_profile/default/module.json
  3. 0 1
      base-common/oh_modules/@xdz/base-core
  4. 30 0
      base-common/oh_modules/@xdz/base-core/.preview/default/intermediates/merge_profile/default/module.json
  5. 17 0
      base-common/oh_modules/@xdz/base-core/BuildProfile.ets
  6. 28 0
      base-common/oh_modules/@xdz/base-core/build-profile.json5
  7. 7 0
      base-common/oh_modules/@xdz/base-core/hvigorfile.ts
  8. 11 0
      base-common/oh_modules/@xdz/base-core/oh-package.json5
  9. 81 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/error/AppError.ets
  10. 117 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/FloatingLogButton.ets
  11. 175 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/ILog.ets
  12. 68 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/HilogLogger.ets
  13. 46 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/NoOpLogger.ets
  14. 390 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/network/NetworkManager.ets
  15. 279 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/permission/PermissionHelper.ets
  16. 76 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/push/IPush.ets
  17. 76 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/push/IPushService.ets
  18. 152 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/share/IShare.ets
  19. 29 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareCallback.ets
  20. 166 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareService.ets
  21. 30 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/storage/IStorage.ets
  22. 346 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageImpl.ets
  23. 16 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageKeys.ets
  24. 1170 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/util/IUtil.ets
  25. 201 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/core/util/JWTUtil.ets
  26. 36 0
      base-common/oh_modules/@xdz/base-core/src/main/ets/index.ets
  27. 13 0
      base-common/oh_modules/@xdz/base-core/src/main/module.json5
  28. 0 1
      base-common/oh_modules/@xdz/capability-socketio
  29. 31 0
      base-common/oh_modules/@xdz/capability-socketio/.preview/default/intermediates/merge_profile/default/module.json
  30. 17 0
      base-common/oh_modules/@xdz/capability-socketio/BuildProfile.ets
  31. 28 0
      base-common/oh_modules/@xdz/capability-socketio/build-profile.json5
  32. 7 0
      base-common/oh_modules/@xdz/capability-socketio/hvigorfile.ts
  33. 19 0
      base-common/oh_modules/@xdz/capability-socketio/oh-package-lock.json5
  34. 12 0
      base-common/oh_modules/@xdz/capability-socketio/oh-package.json5
  35. 30 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/.preview/default/intermediates/merge_profile/default/module.json
  36. 17 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/BuildProfile.ets
  37. 28 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/build-profile.json5
  38. 7 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/hvigorfile.ts
  39. 11 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/oh-package.json5
  40. 81 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/error/AppError.ets
  41. 117 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/FloatingLogButton.ets
  42. 175 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/ILog.ets
  43. 68 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/HilogLogger.ets
  44. 46 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/NoOpLogger.ets
  45. 390 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/network/NetworkManager.ets
  46. 279 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/permission/PermissionHelper.ets
  47. 76 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/push/IPush.ets
  48. 76 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/push/IPushService.ets
  49. 152 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/share/IShare.ets
  50. 29 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareCallback.ets
  51. 166 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareService.ets
  52. 30 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/storage/IStorage.ets
  53. 346 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageImpl.ets
  54. 16 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageKeys.ets
  55. 1170 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/util/IUtil.ets
  56. 201 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/util/JWTUtil.ets
  57. 36 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/index.ets
  58. 13 0
      base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/module.json5
  59. 38 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/index.ets
  60. 104 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/api/SocketIOService.ets
  61. 45 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/factory/SocketIORepositoryFactory.ets
  62. 37 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/factory/SocketIOServiceFactory.ets
  63. 588 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/impl/SocketIOServiceImpl.ets
  64. 32 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/model/SocketIOEvent.ets
  65. 21 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/model/SocketIOResponse.ets
  66. 280 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/protocol/SocketIOProtocol.ets
  67. 192 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/repository/SocketIORepository.ets
  68. 75 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/repository/StateFlow.ets
  69. 299 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/transport/PollingTransport.ets
  70. 58 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/transport/Transport.ets
  71. 160 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/transport/WebSocketTransport.ets
  72. 14 0
      base-common/oh_modules/@xdz/capability-socketio/src/main/module.json5
  73. 17 0
      base-common/src/main/ets/common/auth/AuthGuardHolder.ets
  74. 15 0
      base-common/src/main/ets/common/auth/IAuthGuard.ets
  75. 1 1
      base-common/src/main/ets/common/camera/CameraHelper.ets
  76. 58 21
      base-common/src/main/ets/common/config/ServerConfigManager.ets
  77. 134 0
      base-common/src/main/ets/common/dialog/CascadePickerDialog.ets
  78. 90 0
      base-common/src/main/ets/common/dialog/ServerConfigDialog.ets
  79. 147 0
      base-common/src/main/ets/common/media/MediaPickerHelper.ets
  80. 45 3
      base-common/src/main/ets/common/network/ApiBaseRemoteDataSource.ets
  81. 126 26
      base-common/src/main/ets/common/network/ApiBaseService.ets
  82. 40 8
      base-common/src/main/ets/common/network/ApiResponseParser.ets
  83. 52 1
      base-common/src/main/ets/common/network/NetworkHelper.ets
  84. 357 0
      base-common/src/main/ets/common/router/ARouter.ets
  85. 150 0
      base-common/src/main/ets/common/router/ARouterExample.ets
  86. 44 72
      base-common/src/main/ets/common/router/NavigationHelper.ets
  87. 207 0
      base-common/src/main/ets/common/router/RouteConfig.ets
  88. 41 0
      base-common/src/main/ets/common/router/RouteConstants.ets
  89. 202 0
      base-common/src/main/ets/common/router/RouteInterceptor.ets
  90. 121 0
      base-common/src/main/ets/common/router/RouteParamsHelper.ets
  91. 205 0
      base-common/src/main/ets/common/router/RoutePath.ets
  92. 729 0
      base-common/src/main/ets/common/router/RouterManager.ets
  93. 13 18
      base-common/src/main/ets/common/socketio/SocketIOManager.ets
  94. 0 40
      base-common/src/main/ets/common/ui/BasePage.ets
  95. 6 2
      base-common/src/main/ets/common/ui/BaseViewModel.ets
  96. 28 0
      base-common/src/main/ets/common/ui/BreakpointHelper.ets
  97. 142 0
      base-common/src/main/ets/common/ui/GlassmorphismAnimator.ets
  98. 63 0
      base-common/src/main/ets/common/ui/LayoutConstants.ets
  99. 9 15
      base-common/src/main/ets/common/ui/MessageHelper.ets
  100. 0 0
      base-common/src/main/ets/common/ui/PageHelper.ets

+ 10 - 1
.gitignore

@@ -9,4 +9,13 @@
 /.clang-format
 /.clang-tidy
 **/.test
-/.appanalyzer
+/.appanalyzer
+# Ignore docs & scripts & node_modules per project rule
+.DS_Store
+*.md
+*.txt
+*.sh
+*.ps1
+*.py
+*.sql
+hvigor/node_modules/

+ 3 - 3
base-common/.preview/default/intermediates/merge_profile/default/module.json

@@ -4,12 +4,12 @@
 		"debug": true,
 		"versionCode": 1000000,
 		"versionName": "1.0.0",
-		"minAPIVersion": 60001021,
-		"targetAPIVersion": 60001021,
+		"minAPIVersion": 50000012,
+		"targetAPIVersion": 50000012,
 		"apiReleaseType": "Release",
 		"targetMinorAPIVersion": 0,
 		"targetPatchAPIVersion": 0,
-		"compileSdkVersion": "6.0.1.112",
+		"compileSdkVersion": "6.0.2.130",
 		"compileSdkType": "HarmonyOS",
 		"appEnvironments": [],
 		"bundleType": "app",

+ 0 - 1
base-common/oh_modules/@xdz/base-core

@@ -1 +0,0 @@
-../../../base-core

+ 30 - 0
base-common/oh_modules/@xdz/base-core/.preview/default/intermediates/merge_profile/default/module.json

@@ -0,0 +1,30 @@
+{
+	"app": {
+		"bundleName": "com.narutohuo.xdz",
+		"debug": true,
+		"versionCode": 1000000,
+		"versionName": "1.0.0",
+		"minAPIVersion": 50000012,
+		"targetAPIVersion": 50000012,
+		"apiReleaseType": "Release",
+		"targetMinorAPIVersion": 0,
+		"targetPatchAPIVersion": 0,
+		"compileSdkVersion": "6.0.2.130",
+		"compileSdkType": "HarmonyOS",
+		"appEnvironments": [],
+		"bundleType": "app",
+		"buildMode": "debug"
+	},
+	"module": {
+		"name": "base_core",
+		"type": "har",
+		"description": "基础设施层 - 定义接口和基础实现",
+		"mainElement": "",
+		"deviceTypes": [
+			"phone",
+			"tablet"
+		],
+		"packageName": "@xdz/base-core",
+		"installationFree": false
+	}
+}

+ 17 - 0
base-common/oh_modules/@xdz/base-core/BuildProfile.ets

@@ -0,0 +1,17 @@
+/**
+ * Use these variables when you tailor your ArkTS code. They must be of the const type.
+ */
+export const HAR_VERSION = '1.0.0';
+export const BUILD_MODE_NAME = 'debug';
+export const DEBUG = true;
+export const TARGET_NAME = 'default';
+
+/**
+ * BuildProfile Class is used only for compatibility purposes.
+ */
+export default class BuildProfile { 
+	static readonly HAR_VERSION = HAR_VERSION;
+	static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
+	static readonly DEBUG = DEBUG;
+	static readonly TARGET_NAME = TARGET_NAME;
+}

+ 28 - 0
base-common/oh_modules/@xdz/base-core/build-profile.json5

@@ -0,0 +1,28 @@
+{
+  "apiType": "stageMode",
+  "buildOption": {
+    "resOptions": {
+      "copyCodeResource": {
+        "enable": false
+      }
+    }
+  },
+  "buildOptionSet": [
+    {
+      "name": "release",
+      "arkOptions": {
+        "obfuscation": {
+          "ruleOptions": {
+            "enable": false
+          }
+        }
+      }
+    }
+  ],
+  "targets": [
+    {
+      "name": "default"
+    }
+  ]
+}
+

+ 7 - 0
base-common/oh_modules/@xdz/base-core/hvigorfile.ts

@@ -0,0 +1,7 @@
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+  system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+  plugins: []       /* Custom plugin to extend the functionality of Hvigor. */
+}
+

+ 11 - 0
base-common/oh_modules/@xdz/base-core/oh-package.json5

@@ -0,0 +1,11 @@
+{
+  "name": "@xdz/base-core",
+  "version": "1.0.0",
+  "description": "基础设施层 - 定义接口和基础实现",
+  "main": "src/main/ets/index.ets",
+  "dependencies": {
+  },
+  "license": "MIT",
+  "keywords": ["base", "core", "infrastructure"]
+}
+

+ 81 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/error/AppError.ets

@@ -0,0 +1,81 @@
+/**
+ * 统一异常模型(3.1)
+ * 
+ * 所有业务异常统一使用 AppError,避免直接使用 Error
+ */
+
+/**
+ * 错误类型枚举
+ */
+export enum ErrorType {
+  BIZ = 'BIZ',           // 业务错误
+  NETWORK = 'NETWORK',   // 网络错误
+  TIMEOUT = 'TIMEOUT',   // 超时错误
+  PARSE = 'PARSE',       // 解析错误
+  UNKNOWN = 'UNKNOWN'    // 未知错误
+}
+
+/**
+ * 原始错误类型(可以是 Error、字符串或其他类型)
+ */
+export type AppErrorRaw = Error | string | object;
+
+/**
+ * 统一异常类
+ */
+export class AppError extends Error {
+  readonly type: ErrorType;
+  readonly code: number;
+  readonly context: string;
+  readonly raw: AppErrorRaw | null;
+
+  constructor(
+    message: string,
+    type: ErrorType,
+    code: number = 0,
+    context: string = '',
+    raw: AppErrorRaw | null = null
+  ) {
+    super(message);
+    this.type = type;
+    this.code = code;
+    this.context = context;
+    this.raw = raw;
+    this.name = 'AppError';
+  }
+
+  /**
+   * 创建业务错误
+   */
+  static biz(message: string, code: number, context: string = ''): AppError {
+    return new AppError(message, ErrorType.BIZ, code, context);
+  }
+
+  /**
+   * 创建网络错误
+   */
+  static network(message: string, raw: AppErrorRaw | null = null): AppError {
+    return new AppError(message, ErrorType.NETWORK, 0, '', raw);
+  }
+
+  /**
+   * 创建超时错误
+   */
+  static timeout(message: string, raw: AppErrorRaw | null = null): AppError {
+    return new AppError(message, ErrorType.TIMEOUT, 0, '', raw);
+  }
+
+  /**
+   * 创建解析错误
+   */
+  static parse(message: string, context: string = ''): AppError {
+    return new AppError(message, ErrorType.PARSE, 0, context);
+  }
+
+  /**
+   * 创建未知错误
+   */
+  static unknown(message: string, raw: AppErrorRaw | null = null): AppError {
+    return new AppError(message, ErrorType.UNKNOWN, 0, '', raw);
+  }
+}

+ 117 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/FloatingLogButton.ets

@@ -0,0 +1,117 @@
+import { Context } from '@kit.AbilityKit';
+import { ILog } from './ILog';
+
+const TAG = "FloatingLogButton";
+
+/**
+ * 悬浮日志按钮
+ * 
+ * 提供悬浮窗显示日志功能,常用于开发调试
+ * 
+ * 功能:
+ * - 显示悬浮日志按钮
+ * - 点击按钮显示日志查看器
+ * - 隐藏悬浮按钮
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { FloatingLogButton } from '@xdz/base-core';
+ * 
+ * // 显示悬浮日志按钮
+ * FloatingLogButton.show(context);
+ * 
+ * // 隐藏悬浮日志按钮
+ * FloatingLogButton.hide();
+ * ```
+ */
+export class FloatingLogButton {
+  private static isShowing: boolean = false;
+  private static context: Context | null = null;
+  
+  /**
+   * 显示悬浮日志按钮
+   * 
+   * @param context 上下文
+   */
+  static show(context: Context): void {
+    try {
+      if (FloatingLogButton.isShowing) {
+        ILog.w(TAG, "悬浮日志按钮已显示");
+        return;
+      }
+      
+      FloatingLogButton.context = context;
+      FloatingLogButton.isShowing = true;
+      
+      // TODO: 使用 HarmonyOS 悬浮窗 API 实现悬浮日志按钮
+      // 注意:HarmonyOS 的悬浮窗实现方式与 Android 不同
+      // 可能需要使用 WindowStage 或其他 API
+      ILog.d(TAG, "悬浮日志按钮已显示(功能待实现)");
+    } catch (e) {
+      ILog.e(TAG, "显示悬浮日志按钮失败", e as Error);
+    }
+  }
+  
+  /**
+   * 隐藏悬浮日志按钮
+   */
+  static hide(): void {
+    try {
+      if (!FloatingLogButton.isShowing) {
+        ILog.w(TAG, "悬浮日志按钮未显示");
+        return;
+      }
+      
+      FloatingLogButton.isShowing = false;
+      FloatingLogButton.context = null;
+      
+      // TODO: 实现隐藏悬浮日志按钮功能
+      ILog.d(TAG, "悬浮日志按钮已隐藏(功能待实现)");
+    } catch (e) {
+      ILog.e(TAG, "隐藏悬浮日志按钮失败", e as Error);
+    }
+  }
+  
+  /**
+   * 检查悬浮日志按钮是否显示
+   * 
+   * @return 是否显示
+   */
+  static isVisible(): boolean {
+    return FloatingLogButton.isShowing;
+  }
+  
+  /**
+   * 切换悬浮日志按钮显示/隐藏状态
+   * 
+   * @param context 上下文(仅在显示时需要)
+   */
+  static toggle(context?: Context): void {
+    if (FloatingLogButton.isShowing) {
+      FloatingLogButton.hide();
+    } else {
+      if (context) {
+        FloatingLogButton.show(context);
+      } else if (FloatingLogButton.context) {
+        FloatingLogButton.show(FloatingLogButton.context);
+      } else {
+        ILog.w(TAG, "无法切换:缺少 context");
+      }
+    }
+  }
+}
+
+/**
+ * 使用示例:
+ * 
+ * ```typescript
+ * // 在开发模式下显示悬浮日志按钮
+ * if (__DEV__) {
+ *   FloatingLogButton.show(context);
+ * }
+ * 
+ * // 点击悬浮按钮时显示日志查看器
+ * // 注意:日志查看器功能需要在 ILog 中实现
+ * ```
+ */
+

+ 175 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/ILog.ets

@@ -0,0 +1,175 @@
+import { HilogLogger } from './impl/HilogLogger';
+import { NoOpLogger } from './impl/NoOpLogger';
+
+/**
+ * 日志级别枚举
+ */
+export enum LogLevel {
+  DEBUG,    // 调试信息
+  INFO,     // 一般信息
+  WARN,     // 警告信息
+  ERROR     // 错误信息
+}
+
+/**
+ * 日志服务接口
+ * 统一封装日志记录、日志文件管理、日志上传、崩溃收集
+ * 
+ * 实现类:HilogLogger(开发环境)、NoOpLogger(生产环境)
+ */
+export interface ILogger {
+  /**
+   * 调试日志
+   */
+  d(tag: string, message: string): void;
+  
+  /**
+   * 信息日志
+   */
+  i(tag: string, message: string): void;
+  
+  /**
+   * 警告日志
+   */
+  w(tag: string, message: string): void;
+  
+  /**
+   * 错误日志
+   */
+  e(tag: string, message: string, throwable?: Error): void;
+  
+  /**
+   * 按级别记录日志
+   * 
+   * @param level 日志级别
+   * @param tag 标签
+   * @param message 消息
+   * @param throwable 异常(可选)
+   */
+  log(level: LogLevel, tag: string, message: string, throwable?: Error): void;
+  
+  /**
+   * 上传日志文件
+   */
+  uploadLogs(): void;
+  
+  /**
+   * 收集崩溃信息
+   */
+  collectCrash(throwable: Error): void;
+}
+
+/**
+ * 日志工具类(类似 Android Log 类)
+ * 
+ * 所有模块通过静态方法进行日志记录
+ * 
+ * **实现选择**:
+ * - **开发环境**(Debug):使用 HilogLogger(输出详细日志)
+ * - **生产环境**(Release):使用 NoOpLogger(不输出日志,提升性能)
+ * 
+ * **使用示例**:
+ * ```typescript
+ * // 1. 在 Application 中初始化(推荐)
+ * // Debug 版本自动启用日志,Release 版本自动禁用
+ * ILog.init(true);
+ * 
+ * // 2. 静态方法调用(推荐,类似 Android Log.d())
+ * ILog.d("Tag", "调试信息");
+ * ILog.e("Tag", "错误信息", exception);
+ * 
+ * // 3. 手动控制(可选)
+ * ILog.init(false); // 生产环境禁用日志
+ * ILog.init(true);  // 开发环境启用日志
+ * ```
+ */
+export class ILog {
+  private static instance: ILogger | null = null;
+  
+  /**
+   * 初始化日志实现(在 Application 中调用,可选)
+   * 
+   * **自动选择实现**:
+   * - 如果 `enableLogging = true`(默认):使用 HilogLogger(开发环境)
+   * - 如果 `enableLogging = false`:使用 NoOpLogger(生产环境,不输出日志)
+   * 
+   * @param enableLogging 是否启用日志(默认 true)
+   * @param logImpl 自定义日志实现(可选,如果指定则忽略 enableLogging 参数)
+   */
+  static init(enableLogging: boolean = true, logImpl?: ILogger): void {
+    if (logImpl) {
+      ILog.instance = logImpl; // 如果指定了自定义实现,优先使用
+    } else if (enableLogging) {
+      // 启用日志(开发环境)
+      ILog.instance = HilogLogger.getInstance();
+    } else {
+      // 禁用日志(生产环境)
+      ILog.instance = NoOpLogger.getInstance();
+    }
+  }
+  
+  /**
+   * 获取日志实现实例(单例)
+   * 
+   * 如果未初始化,默认使用 HilogLogger(开发环境)
+   * 生产环境建议在 Application 中调用 init() 进行初始化
+   */
+  private static getInstance(): ILogger {
+    if (!ILog.instance) {
+      // 默认使用 HilogLogger(开发环境)
+      // 生产环境建议在 Application 中调用 init(false)
+      ILog.instance = HilogLogger.getInstance();
+    }
+    return ILog.instance;
+  }
+  
+  /**
+   * 调试日志(静态方法)
+   */
+  static d(tag: string, message: string): void {
+    ILog.getInstance().d(tag, message);
+  }
+  
+  /**
+   * 信息日志(静态方法)
+   */
+  static i(tag: string, message: string): void {
+    ILog.getInstance().i(tag, message);
+  }
+  
+  /**
+   * 警告日志(静态方法)
+   */
+  static w(tag: string, message: string): void {
+    ILog.getInstance().w(tag, message);
+  }
+  
+  /**
+   * 错误日志(静态方法)
+   */
+  static e(tag: string, message: string, throwable?: Error): void {
+    ILog.getInstance().e(tag, message, throwable);
+  }
+  
+  /**
+   * 按级别记录日志(静态方法)
+   */
+  static log(level: LogLevel, tag: string, message: string, throwable?: Error): void {
+    ILog.getInstance().log(level, tag, message, throwable);
+  }
+  
+  /**
+   * 上传日志文件(静态方法)
+   */
+  static uploadLogs(): void {
+    ILog.getInstance().uploadLogs();
+  }
+  
+  /**
+   * 收集崩溃信息(静态方法)
+   */
+  static collectCrash(throwable: Error): void {
+    ILog.getInstance().collectCrash(throwable);
+  }
+}
+

+ 68 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/HilogLogger.ets

@@ -0,0 +1,68 @@
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { ILogger, LogLevel } from '../ILog';
+
+const DOMAIN = 0x0000;
+
+/**
+ * 基于 HarmonyOS hilog 的日志实现
+ * 
+ * 开发环境使用,输出详细日志
+ */
+export class HilogLogger implements ILogger {
+  private static instance: HilogLogger | null = null;
+  
+  static getInstance(): HilogLogger {
+    if (!HilogLogger.instance) {
+      HilogLogger.instance = new HilogLogger();
+    }
+    return HilogLogger.instance;
+  }
+  
+  d(tag: string, message: string): void {
+    hilog.debug(DOMAIN, tag, '%{public}s', message);
+  }
+  
+  i(tag: string, message: string): void {
+    hilog.info(DOMAIN, tag, '%{public}s', message);
+  }
+  
+  w(tag: string, message: string): void {
+    hilog.warn(DOMAIN, tag, '%{public}s', message);
+  }
+  
+  e(tag: string, message: string, throwable?: Error): void {
+    if (throwable) {
+      hilog.error(DOMAIN, tag, '%{public}s, error: %{public}s', message, throwable.message || 'Unknown error');
+    } else {
+      hilog.error(DOMAIN, tag, '%{public}s', message);
+    }
+  }
+  
+  log(level: LogLevel, tag: string, message: string, throwable?: Error): void {
+    switch (level) {
+      case LogLevel.DEBUG:
+        this.d(tag, message);
+        break;
+      case LogLevel.INFO:
+        this.i(tag, message);
+        break;
+      case LogLevel.WARN:
+        this.w(tag, message);
+        break;
+      case LogLevel.ERROR:
+        this.e(tag, message, throwable);
+        break;
+    }
+  }
+  
+  uploadLogs(): void {
+    // TODO: 实现日志上传功能
+    hilog.info(DOMAIN, 'HilogLogger', 'uploadLogs: 日志上传功能待实现');
+  }
+  
+  collectCrash(throwable: Error): void {
+    hilog.error(DOMAIN, 'Crash', '崩溃信息: %{public}s', throwable.message || 'Unknown crash');
+    // TODO: 实现崩溃收集功能
+  }
+}
+

+ 46 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/NoOpLogger.ets

@@ -0,0 +1,46 @@
+import { ILogger, LogLevel } from '../ILog';
+
+/**
+ * 空日志实现(生产环境使用)
+ * 
+ * 不输出任何日志,提升性能
+ */
+export class NoOpLogger implements ILogger {
+  private static instance: NoOpLogger | null = null;
+  
+  static getInstance(): NoOpLogger {
+    if (!NoOpLogger.instance) {
+      NoOpLogger.instance = new NoOpLogger();
+    }
+    return NoOpLogger.instance;
+  }
+  
+  d(tag: string, message: string): void {
+    // 空实现,不输出日志
+  }
+  
+  i(tag: string, message: string): void {
+    // 空实现,不输出日志
+  }
+  
+  w(tag: string, message: string): void {
+    // 空实现,不输出日志
+  }
+  
+  e(tag: string, message: string, throwable?: Error): void {
+    // 空实现,不输出日志
+  }
+  
+  log(level: LogLevel, tag: string, message: string, throwable?: Error): void {
+    // 空实现,不输出日志
+  }
+  
+  uploadLogs(): void {
+    // 空实现
+  }
+  
+  collectCrash(throwable: Error): void {
+    // 空实现
+  }
+}
+

+ 390 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/network/NetworkManager.ets

@@ -0,0 +1,390 @@
+import { http } from '@kit.NetworkKit';
+import { ILog } from '../log/ILog';
+
+/**
+ * HTTP 请求管理器(单例模式)
+ * 
+ * 基于 HarmonyOS @kit.NetworkKit/http 封装
+ * 提供统一的 HTTP 请求接口
+ * 
+ * 使用方式:
+ * ```typescript
+ * const response = await NetworkManager.getInstance().request<ResponseType>(
+ *   'https://api.example.com/data',
+ *   {
+ *     method: http.RequestMethod.GET,
+ *     header: { 'Content-Type': 'application/json' }
+ *   }
+ * );
+ * ```
+ */
+export class NetworkManager {
+  private static instance: NetworkManager | null = null;
+  private httpRequest: http.HttpRequest | null = null;
+  private readonly TAG = 'NetworkManager';
+  
+  /**
+   * Token 刷新提供器(可选,用于自动刷新过期的 Token)
+   * 
+   * 当请求返回 401/402 时,会自动调用此方法刷新 Token
+   * 刷新成功后会自动重试原请求
+   */
+  static refreshTokenProvider: (() => Promise<string | null>) | null = null;
+  
+  /**
+   * Token 刷新失败回调(可选,用于刷新失败时跳转登录)
+   * 
+   * 当 Token 刷新失败时,会自动调用此回调
+   * 可以在 AppInitializer 中设置,实现跳转登录界面
+   */
+  static onTokenRefreshFailed: (() => void) | null = null;
+  
+  /**
+   * Token 提供器(可选,用于自动添加 Token 到请求头)
+   */
+  static tokenProvider: (() => Promise<string | null>) | null = null;
+  
+  // Token 刷新状态(并发控制)
+  private static isRefreshing: boolean = false;
+  
+  private constructor() {
+    // 私有构造函数,单例模式
+  }
+  
+  /**
+   * 获取单例实例
+   */
+  static getInstance(): NetworkManager {
+    if (!NetworkManager.instance) {
+      NetworkManager.instance = new NetworkManager();
+      NetworkManager.instance.httpRequest = http.createHttp();
+    }
+    return NetworkManager.instance;
+  }
+  
+  /**
+   * 发送 HTTP 请求
+   * 
+   * 自动处理 Token 刷新:
+   * - 拦截 401/402 响应(Token 过期/无效)
+   * - 自动调用 refreshTokenProvider 刷新 Token
+   * - 使用新 Token 重试原请求
+   * - 并发控制:多个请求同时 401 时,只刷新一次,其他请求等待
+   * 
+   * @param url 请求 URL
+   * @param options 请求选项
+   * @returns Promise<T> 响应数据
+   */
+  async request<T>(url: string, options: http.HttpRequestOptions): Promise<T> {
+    if (!this.httpRequest) {
+      this.httpRequest = http.createHttp();
+    }
+    
+    try {
+      const response: http.HttpResponse = await this.httpRequest.request(url, options);
+      
+      // 打印响应信息
+      ILog.d(this.TAG, `========== [NetworkManager 响应] ==========`);
+      ILog.d(this.TAG, `[NetworkManager 响应] URL: ${url}`);
+      ILog.d(this.TAG, `[NetworkManager 响应] HTTP状态码: ${response.responseCode}`);
+      if (response.result) {
+        const resultStr = typeof response.result === 'string' 
+          ? response.result 
+          : JSON.stringify(response.result);
+        ILog.d(this.TAG, `[NetworkManager 响应] 响应体: ${resultStr}`);
+      } else {
+        ILog.d(this.TAG, `[NetworkManager 响应] 响应体: (空)`);
+      }
+      
+      // 检查响应状态
+      if (response.responseCode >= 200 && response.responseCode < 300) {
+        // 解析 JSON 响应
+        if (response.result) {
+          const resultStr = typeof response.result === 'string' 
+            ? response.result 
+            : JSON.stringify(response.result);
+          return JSON.parse(resultStr) as T;
+        }
+        // 返回空对象(需要类型断言)
+        // 注意:如果响应为空,返回 null,调用方需要处理
+        return null as T;
+      } else if (response.responseCode === 401 || response.responseCode === 402) {
+        // 拦截 401/402 响应(Token 过期/无效)
+        ILog.w(this.TAG, `[NetworkManager 响应] 收到 401/402,尝试刷新Token`);
+        return await this.handleTokenRefresh<T>(url, options, response);
+      } else {
+        const errorMsg = `HTTP ${response.responseCode}: ${response.result}`;
+        ILog.e(this.TAG, `[NetworkManager 响应] 请求失败: ${errorMsg}`);
+        const error = new Error(errorMsg);
+        throw error;
+      }
+    } catch (error) {
+      ILog.e(this.TAG, `Request failed: ${url}`, error as Error);
+      if (error instanceof Error) {
+        throw error;
+      } else {
+        throw new Error(String(error));
+      }
+    }
+  }
+  
+  /**
+   * 处理 Token 刷新
+   * 
+   * 当收到 401/402 响应时:
+   * 1. 检查是否有 refreshTokenProvider
+   * 2. 如果有,调用刷新 Token
+   * 3. 使用新 Token 重试原请求
+   * 4. 如果刷新失败,调用 onTokenRefreshFailed 回调
+   * 
+   * @param url 请求 URL
+   * @param options 请求选项
+   * @param originalResponse 原始响应(401/402)
+   * @returns Promise<T> 响应数据
+   */
+  private async handleTokenRefresh<T>(
+    url: string,
+    options: http.HttpRequestOptions,
+    originalResponse: http.HttpResponse
+  ): Promise<T> {
+    // 如果没有提供刷新回调,直接抛出错误
+    if (!NetworkManager.refreshTokenProvider) {
+      ILog.w(this.TAG, '收到 401/402 响应,但未设置 refreshTokenProvider,无法自动刷新');
+      const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+      throw new Error(errorMsg);
+    }
+    
+    // 并发控制:如果正在刷新,等待刷新完成
+    if (NetworkManager.isRefreshing) {
+      ILog.d(this.TAG, 'Token 正在刷新中,等待刷新完成...');
+      // 等待刷新完成,最多等待 3 秒
+      let waitCount = 0;
+      while (NetworkManager.isRefreshing && waitCount < 30) {
+        await new Promise<void>((resolve) => {
+          setTimeout(() => {
+            resolve();
+          }, 100);
+        });
+        waitCount++;
+      }
+      
+      // 刷新完成后,使用新 Token 重试
+      if (NetworkManager.tokenProvider) {
+        const newToken = await NetworkManager.tokenProvider();
+        if (newToken && newToken !== '') {
+          ILog.d(this.TAG, '使用刷新后的新 Token 重试请求');
+          // 更新请求头中的 Token
+          const newOptions = this.updateTokenInOptions(options, newToken);
+          const retryResponse: http.HttpResponse = await this.httpRequest!.request(url, newOptions);
+          
+          if (retryResponse.responseCode >= 200 && retryResponse.responseCode < 300) {
+            if (retryResponse.result) {
+              const resultStr = typeof retryResponse.result === 'string' 
+                ? retryResponse.result 
+                : JSON.stringify(retryResponse.result);
+              return JSON.parse(resultStr) as T;
+            }
+            return null as T;
+          } else {
+              const errorMsg = `HTTP ${retryResponse.responseCode}: ${retryResponse.result}`;
+              throw new Error(errorMsg);
+          }
+        } else {
+          ILog.w(this.TAG, '等待刷新完成后,Token 仍为空,返回 401 响应');
+          const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+          throw new Error(errorMsg);
+        }
+      } else {
+        const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+        throw new Error(errorMsg);
+      }
+    } else {
+      // 开始刷新
+      NetworkManager.isRefreshing = true;
+      try {
+        ILog.d(this.TAG, '检测到 401/402 响应,开始刷新 Token...');
+        const newToken = await NetworkManager.refreshTokenProvider();
+        
+        if (newToken && newToken !== '') {
+          ILog.d(this.TAG, 'Token 刷新成功,使用新 Token 重试请求');
+          
+          // 更新请求头中的 Token
+          const newOptions = this.updateTokenInOptions(options, newToken);
+          const retryResponse: http.HttpResponse = await this.httpRequest!.request(url, newOptions);
+          
+          // 如果重试后仍然是 401,说明刷新失败或 Token 无效
+          if (retryResponse.responseCode === 401 || retryResponse.responseCode === 402) {
+            ILog.w(this.TAG, '使用新 Token 重试后仍返回 401/402,Token 刷新可能失败,需要重新登录');
+            // 调用刷新失败回调
+            if (NetworkManager.onTokenRefreshFailed) {
+              NetworkManager.onTokenRefreshFailed();
+            }
+            const errorMsg = `HTTP ${retryResponse.responseCode}: ${retryResponse.result}`;
+            throw new Error(errorMsg);
+          }
+          
+          if (retryResponse.responseCode >= 200 && retryResponse.responseCode < 300) {
+            if (retryResponse.result) {
+              const resultStr = typeof retryResponse.result === 'string' 
+                ? retryResponse.result 
+                : JSON.stringify(retryResponse.result);
+              return JSON.parse(resultStr) as T;
+            }
+            return null as T;
+          } else {
+            const errorMsg = `HTTP ${retryResponse.responseCode}: ${retryResponse.result}`;
+            throw new Error(errorMsg);
+          }
+        } else {
+          ILog.w(this.TAG, 'Token 刷新失败(返回 null),返回 401 响应,需要重新登录');
+          // 调用刷新失败回调
+          if (NetworkManager.onTokenRefreshFailed) {
+            NetworkManager.onTokenRefreshFailed();
+          }
+          const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+          throw new Error(errorMsg);
+        }
+      } catch (e) {
+        ILog.e(this.TAG, 'Token 刷新异常', e as Error);
+        // 调用刷新失败回调
+        if (NetworkManager.onTokenRefreshFailed) {
+          NetworkManager.onTokenRefreshFailed();
+        }
+        if (e instanceof Error) {
+          throw e;
+        } else {
+          throw new Error(String(e));
+        }
+      } finally {
+        NetworkManager.isRefreshing = false;
+      }
+    }
+  }
+  
+  /**
+   * 更新请求选项中的 Token
+   * 
+   * @param options 原始请求选项
+   * @param token 新的 Token
+   * @returns 更新后的请求选项
+   */
+  private updateTokenInOptions(
+    options: http.HttpRequestOptions,
+    token: string
+  ): http.HttpRequestOptions {
+    // ArkTS 不支持展开运算符,手动复制 header
+    const newHeader: Record<string, string> = {};
+    if (options.header) {
+      const keys = Object.keys(options.header);
+      for (let i = 0; i < keys.length; i++) {
+        const key = keys[i];
+        newHeader[key] = options.header[key];
+      }
+    }
+    
+    // 更新 Authorization 头
+    newHeader['Authorization'] = `Bearer ${token}`;
+    
+    const newOptions: http.HttpRequestOptions = {
+      method: options.method,
+      header: newHeader,
+      extraData: options.extraData,
+      readTimeout: options.readTimeout,
+      connectTimeout: options.connectTimeout
+    };
+    
+    return newOptions;
+  }
+  
+  /**
+   * GET 请求
+   */
+  async get<T>(url: string, headers?: Record<string, string>): Promise<T> {
+    const options: http.HttpRequestOptions = {
+      method: http.RequestMethod.GET,
+      header: headers
+    };
+    return this.request<T>(url, options);
+  }
+  
+  /**
+   * POST 请求
+   */
+  async post<T>(url: string, data?: object, headers?: Record<string, string>): Promise<T> {
+    const header: Record<string, string> = {
+      'Content-Type': 'application/json'
+    };
+    if (headers) {
+      const keys = Object.keys(headers);
+      for (let i = 0; i < keys.length; i++) {
+        const key = keys[i];
+        header[key] = headers[key];
+      }
+    }
+    
+    // 打印实际发送的请求信息
+    ILog.d(this.TAG, `========== [NetworkManager POST] ==========`);
+    ILog.d(this.TAG, `[NetworkManager POST] 完整URL: ${url}`);
+    if (data) {
+      const requestBody = JSON.stringify(data);
+      ILog.d(this.TAG, `[NetworkManager POST] 请求体: ${requestBody}`);
+    } else {
+      ILog.d(this.TAG, `[NetworkManager POST] 请求体: (无)`);
+    }
+    ILog.d(this.TAG, `[NetworkManager POST] 请求头: ${JSON.stringify(header)}`);
+    
+    const postOptions: http.HttpRequestOptions = {
+      method: http.RequestMethod.POST,
+      header: header,
+      extraData: data ? JSON.stringify(data) : undefined
+    };
+    return this.request<T>(url, postOptions);
+  }
+  
+  /**
+   * PUT 请求
+   */
+  async put<T>(url: string, data?: object, headers?: Record<string, string>): Promise<T> {
+    const header: Record<string, string> = {
+      'Content-Type': 'application/json'
+    };
+    if (headers) {
+      const keys = Object.keys(headers);
+      for (let i = 0; i < keys.length; i++) {
+        const key = keys[i];
+        header[key] = headers[key];
+      }
+    }
+    const putOptions: http.HttpRequestOptions = {
+      method: http.RequestMethod.PUT,
+      header: header,
+      extraData: data ? JSON.stringify(data) : undefined
+    };
+    return this.request<T>(url, putOptions);
+  }
+  
+  /**
+   * DELETE 请求
+   */
+  async delete<T>(url: string, headers?: Record<string, string>): Promise<T> {
+    const deleteOptions: http.HttpRequestOptions = {
+      method: http.RequestMethod.DELETE,
+      header: headers
+    };
+    return this.request<T>(url, deleteOptions);
+  }
+  
+  /**
+   * 销毁 HTTP 请求实例
+   */
+  destroy(): void {
+    if (this.httpRequest) {
+      this.httpRequest.destroy();
+      this.httpRequest = null;
+    }
+  }
+}
+
+// 导出单例实例,方便使用
+export const networkManager = NetworkManager.getInstance();
+

+ 279 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/permission/PermissionHelper.ets

@@ -0,0 +1,279 @@
+import { abilityAccessCtrl, common, Context } from '@kit.AbilityKit';
+import { ILog } from '../log/ILog';
+
+const TAG = "PermissionHelper";
+
+// HarmonyOS API 类型定义辅助
+// requestPermissionsFromUser 返回的数据结构
+interface PermissionRequestData {
+  authResults: Array<number>; // GrantStatus 数组
+}
+
+/**
+ * 权限管理封装
+ * 
+ * 统一封装 HarmonyOS 权限请求功能,提供便捷的权限管理方式
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 检查权限(异步方法)
+ * const hasPermission = await PermissionHelper.checkPermission(context, 'ohos.permission.CAMERA');
+ * 
+ * // 请求单个权限
+ * PermissionHelper.requestPermission(context, 'ohos.permission.CAMERA', (granted) => {
+ *   if (granted) {
+ *     // 权限已授予
+ *   }
+ * })
+ * 
+ * // 请求多个权限
+ * PermissionHelper.requestPermissions(context, [
+ *   'ohos.permission.CAMERA',
+ *   'ohos.permission.READ_MEDIA'
+ * ], (permissions) => {
+ *   // 处理权限结果
+ * })
+ * ```
+ */
+export class PermissionHelper {
+  /**
+   * 检查权限是否已授予(异步方法)
+   * 
+   * HarmonyOS 权限检查是异步的,必须使用此方法
+   * 
+   * @param context Context 实例
+   * @param permission 权限名称(如 'ohos.permission.CAMERA')
+   * @return Promise<boolean> true 表示已授予,false 表示未授予
+   */
+  static async checkPermission(context: Context, permission: string): Promise<boolean> {
+    try {
+      const atManager = abilityAccessCtrl.createAtManager();
+      // HarmonyOS 权限检查:使用 checkAccessToken,需要 tokenId 和 permission
+      // tokenId 通过 context 获取,permission 需要转换为正确的类型
+      const tokenId = context.applicationInfo?.accessTokenId ?? 0;
+      if (tokenId === 0) {
+        ILog.w(TAG, "无法获取 tokenId,权限检查失败");
+        return false;
+      }
+      // checkAccessToken 接受 permission 参数,需要类型转换
+      // Permissions 类型未导出,使用类型断言处理
+      // 使用函数类型断言绕过类型检查
+      const checkAccessTokenFunc = atManager.checkAccessToken as (
+        tokenId: number,
+        permission: string
+      ) => Promise<abilityAccessCtrl.GrantStatus>;
+      const grantStatus = await checkAccessTokenFunc(tokenId, permission);
+      return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
+    } catch (e) {
+      ILog.e(TAG, `检查权限失败: ${permission}`, e as Error);
+      return false;
+    }
+  }
+
+  /**
+   * 检查多个权限是否已授予(异步方法)
+   * 
+   * @param context Context 实例
+   * @param permissions 权限名称数组
+   * @return Promise<Map<权限名, 是否授予>>
+   */
+  static async checkPermissions(context: Context, permissions: string[]): Promise<Record<string, boolean>> {
+    const result: Record<string, boolean> = {};
+    for (let i = 0; i < permissions.length; i++) {
+      const permission = permissions[i];
+      result[permission] = await PermissionHelper.checkPermission(context, permission);
+    }
+    return result;
+  }
+  
+  /**
+   * 检查所有权限是否都已授予(异步方法)
+   * 
+   * @param context Context 实例
+   * @param permissions 权限名称数组
+   * @return Promise<boolean> true 表示所有权限都已授予
+   */
+  static async checkAllPermissionsGranted(context: Context, permissions: string[]): Promise<boolean> {
+    const results = await PermissionHelper.checkPermissions(context, permissions);
+    return Object.values(results).every(granted => granted);
+  }
+  
+  /**
+   * 请求单个权限
+   * 
+   * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
+   * 
+   * @param context Context 实例(必须是 UIAbilityContext)
+   * @param permission 权限名称
+   * @param onResult 权限请求结果回调(是否授予)
+   */
+  static async requestPermission(
+    context: Context,
+    permission: string,
+    onResult: (granted: boolean) => void
+  ): Promise<void> {
+    try {
+      // 先异步检查权限是否已授予
+      const hasPermission = await PermissionHelper.checkPermission(context, permission);
+      if (hasPermission) {
+        onResult(true);
+        return;
+      }
+      
+      // 请求权限(HarmonyOS 推荐方式)
+      const atManager = abilityAccessCtrl.createAtManager();
+      const permissionsArray: Array<string> = [permission];
+      
+      // HarmonyOS API 类型定义问题:requestPermissionsFromUser 要求 Permissions[] 类型
+      // 但 Permissions 类型未导出,实际运行时接受 string[]
+      // 使用类型断言处理:将 string[] 断言为方法期望的类型
+      // 注意:这是 HarmonyOS API 类型定义的问题,运行时不会有问题
+      // 使用双重类型断言绕过类型检查
+      const requestResult = await (atManager.requestPermissionsFromUser as (
+        context: Context,
+        permissions: Array<string>
+      ) => Promise<PermissionRequestData>)(context, permissionsArray);
+      
+      const grantResults = requestResult.authResults;
+      const grantStatus = grantResults[0];
+      const granted = grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
+      onResult(granted);
+    } catch (e) {
+      ILog.e(TAG, `请求权限异常: ${permission}`, e as Error);
+      onResult(false);
+    }
+  }
+  
+  /**
+   * 请求多个权限
+   * 
+   * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
+   * 
+   * @param context Context 实例(必须是 UIAbilityContext)
+   * @param permissions 权限名称数组
+   * @param onResult 权限请求结果回调(Map<权限名, 是否授予>)
+   */
+  static async requestPermissions(
+    context: Context,
+    permissions: string[],
+    onResult: (permissions: Record<string, boolean>) => void
+  ): Promise<void> {
+    try {
+      // 先异步检查已授予的权限
+      const checkedPermissions: Record<string, boolean> = {};
+      const ungrantedPermissions: string[] = [];
+      
+      for (let i = 0; i < permissions.length; i++) {
+        const permission = permissions[i];
+        const hasPermission = await PermissionHelper.checkPermission(context, permission);
+        checkedPermissions[permission] = hasPermission;
+        if (!hasPermission) {
+          ungrantedPermissions.push(permission);
+        }
+      }
+      
+      if (ungrantedPermissions.length === 0) {
+        // 所有权限都已授予
+        onResult(checkedPermissions);
+        return;
+      }
+      
+      // 请求未授予的权限(HarmonyOS 推荐方式)
+      const atManager = abilityAccessCtrl.createAtManager();
+      const permissionsArray: Array<string> = [];
+      for (let i = 0; i < ungrantedPermissions.length; i++) {
+        permissionsArray.push(ungrantedPermissions[i]);
+      }
+      
+      // HarmonyOS API 类型定义问题:requestPermissionsFromUser 要求 Permissions[] 类型
+      // 但 Permissions 类型未导出,实际运行时接受 string[]
+      // 使用函数类型断言绕过类型检查
+      const requestPermissionsFunc = atManager.requestPermissionsFromUser as (
+        context: Context,
+        permissions: Array<string>
+      ) => Promise<PermissionRequestData>;
+      const requestResult = await requestPermissionsFunc(context, permissionsArray);
+      
+      const grantResults = requestResult.authResults;
+      const result: Record<string, boolean> = {};
+      // 复制已检查的权限结果
+      const checkedKeys = Object.keys(checkedPermissions);
+      for (let i = 0; i < checkedKeys.length; i++) {
+        const key = checkedKeys[i];
+        result[key] = checkedPermissions[key];
+      }
+      
+      // 更新请求的权限结果
+      for (let i = 0; i < ungrantedPermissions.length; i++) {
+        const permission = ungrantedPermissions[i];
+        const grantStatus = grantResults[i];
+        result[permission] = grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
+      }
+      
+      onResult(result);
+    } catch (e) {
+      ILog.e(TAG, `请求多个权限异常`, e as Error);
+      // 返回已检查的结果(即使有异常也返回部分结果)
+      const checkedPermissions: Record<string, boolean> = {};
+      for (let i = 0; i < permissions.length; i++) {
+        const permission = permissions[i];
+        try {
+          checkedPermissions[permission] = await PermissionHelper.checkPermission(context, permission);
+        } catch (checkError) {
+          checkedPermissions[permission] = false;
+        }
+      }
+      onResult(checkedPermissions);
+    }
+  }
+  
+  /**
+   * 请求权限(带说明对话框)
+   * 
+   * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
+   * 
+   * @param context Context 实例
+   * @param permission 权限名称
+   * @param rationale 权限说明文本
+   * @param onResult 权限请求结果回调
+   */
+  static async requestPermissionWithRationale(
+    context: Context,
+    permission: string,
+    rationale: string,
+    onResult: (granted: boolean) => void
+  ): Promise<void> {
+    // 先异步检查权限是否已授予
+    const hasPermission = await PermissionHelper.checkPermission(context, permission);
+    if (hasPermission) {
+      onResult(true);
+      return;
+    }
+    
+    // HarmonyOS 权限系统与 Android 不同,这里简化处理
+    // 直接请求权限(不显示对话框,因为 base-core 不应该依赖 base-common 的 DialogHelper)
+    // 如果需要显示对话框,应该在业务层(base-common)中实现
+    PermissionHelper.requestPermission(context, permission, onResult);
+  }
+  
+  /**
+   * 获取权限说明文本(根据权限类型)
+   * 
+   * @param permission 权限名称
+   * @return 权限说明文本
+   */
+  static getPermissionRationale(permission: string): string {
+    const rationaleMap: Record<string, string> = {
+      'ohos.permission.CAMERA': '需要访问相机以拍摄照片',
+      'ohos.permission.READ_MEDIA': '需要访问媒体文件以选择图片',
+      'ohos.permission.WRITE_MEDIA': '需要保存文件到设备',
+      'ohos.permission.READ_CONTACTS': '需要访问通讯录',
+      'ohos.permission.WRITE_CONTACTS': '需要修改通讯录',
+      'ohos.permission.LOCATION': '需要访问位置信息',
+      'ohos.permission.MICROPHONE': '需要访问麦克风以录制音频',
+    };
+    
+    return rationaleMap[permission] || `需要${permission}权限以完成操作`;
+  }
+}
+

+ 76 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/push/IPush.ets

@@ -0,0 +1,76 @@
+import { Context } from '@kit.AbilityKit';
+
+/**
+ * 推送服务接口
+ * 
+ * 用于 base-core 与 push 模块之间的解耦
+ * push 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IPush {
+  /**
+   * 初始化推送服务
+   * 
+   * @param context Application 上下文
+   * @param appKey 极光推送 AppKey
+   * @param channel 推送渠道(可选,默认为 "developer-default")
+   * @param debugMode 是否开启调试模式
+   */
+  initialize(context: Context, appKey: string, channel?: string, debugMode?: boolean): Promise<void>;
+  
+  /**
+   * 设置别名(用于推送)
+   * 
+   * @param alias 别名(通常是用户ID)
+   */
+  setAlias(alias: string): Promise<void>;
+  
+  /**
+   * 设置标签(用于推送)
+   * 
+   * @param tags 标签列表
+   */
+  setTags(tags: string[]): Promise<void>;
+  
+  /**
+   * 设置消息监听器(自定义消息/透传消息)
+   * 
+   * @param listener 消息接收回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setMessageListener(listener: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 设置通知点击监听器(用户点击通知栏通知时触发)
+   * 
+   * @param listener 通知点击回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setNotificationClickListener(listener?: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 注册推送(开启推送)
+   */
+  register(): Promise<void>;
+  
+  /**
+   * 注销推送(关闭推送)
+   */
+  unregister(): Promise<void>;
+  
+  /**
+   * 获取注册ID(用于标识设备)
+   * 
+   * @returns 设备注册ID,如果未初始化或获取失败返回 null
+   */
+  getRegistrationId(): Promise<string | null>;
+  
+  /**
+   * 检查推送是否已开启
+   * 
+   * @returns true 表示推送已开启,false 表示推送已停止或未初始化
+   */
+  isPushEnabled(): Promise<boolean>;
+}
+

+ 76 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/push/IPushService.ets

@@ -0,0 +1,76 @@
+import { Context } from '@kit.AbilityKit';
+
+/**
+ * 推送服务接口
+ * 
+ * 用于 base-core 与 push 模块之间的解耦
+ * push 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IPushService {
+  /**
+   * 初始化推送服务
+   * 
+   * @param context Application 上下文
+   * @param appKey 极光推送 AppKey
+   * @param channel 推送渠道(可选,默认为 "developer-default")
+   * @param debugMode 是否开启调试模式
+   */
+  initialize(context: Context, appKey: string, channel?: string, debugMode?: boolean): Promise<void>;
+  
+  /**
+   * 设置别名(用于推送)
+   * 
+   * @param alias 别名(通常是用户ID)
+   */
+  setAlias(alias: string): Promise<void>;
+  
+  /**
+   * 设置标签(用于推送)
+   * 
+   * @param tags 标签列表
+   */
+  setTags(tags: string[]): Promise<void>;
+  
+  /**
+   * 设置消息监听器(自定义消息/透传消息)
+   * 
+   * @param listener 消息接收回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setMessageListener(listener: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 设置通知点击监听器(用户点击通知栏通知时触发)
+   * 
+   * @param listener 通知点击回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setNotificationClickListener(listener?: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 注册推送(开启推送)
+   */
+  register(): Promise<void>;
+  
+  /**
+   * 注销推送(关闭推送)
+   */
+  unregister(): Promise<void>;
+  
+  /**
+   * 获取注册ID(用于标识设备)
+   * 
+   * @returns 设备注册ID,如果未初始化或获取失败返回 null
+   */
+  getRegistrationId(): Promise<string | null>;
+  
+  /**
+   * 检查推送是否已开启
+   * 
+   * @returns true 表示推送已开启,false 表示推送已停止或未初始化
+   */
+  isPushEnabled(): Promise<boolean>;
+}
+

+ 152 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/share/IShare.ets

@@ -0,0 +1,152 @@
+import { Context } from '@kit.AbilityKit';
+import { Want } from '@kit.AbilityKit';
+import { IShareCallback } from './IShareCallback';
+
+/**
+ * 分享服务接口
+ * 
+ * 用于 base-core 与 share 模块之间的解耦
+ * share 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IShare {
+  /**
+   * 初始化分享服务
+   * 
+   * @param context Application 上下文
+   * @param umengAppKey 友盟 AppKey(可选,如果为空则从资源文件读取)
+   * @param umengChannel 友盟渠道(可选,默认为 "developer-default")
+   * @param weChatAppId 微信 AppID(可选)
+   * @param weChatAppSecret 微信 AppSecret(可选)
+   * @param qqAppId QQ AppID(可选)
+   * @param qqAppKey QQ AppKey(可选)
+   * @param weiboAppKey 微博 AppKey(可选)
+   * @param weiboAppSecret 微博 AppSecret(可选)
+   * @param weiboRedirectUrl 微博回调地址(可选)
+   */
+  initialize(
+    context: Context,
+    umengAppKey?: string,
+    umengChannel?: string,
+    weChatAppId?: string,
+    weChatAppSecret?: string,
+    qqAppId?: string,
+    qqAppKey?: string,
+    weiboAppKey?: string,
+    weiboAppSecret?: string,
+    weiboRedirectUrl?: string
+  ): Promise<void>;
+  
+  /**
+   * 处理分享回调(内部使用)
+   * 
+   * @param want Want 对象(HarmonyOS 的回调方式)
+   */
+  onShareResult(want: Want): void;
+  
+  /**
+   * 统一分享方法(推荐使用)
+   * 
+   * @param context Context 上下文
+   * @param title 分享标题
+   * @param description 分享描述
+   * @param url 分享链接(可选)
+   * @param imageUrl 图片URL(可选)
+   * @param thumbImageUrl 缩略图URL(可选)
+   * @param platform 分享平台(可选,如果为 null 则显示分享弹窗)
+   * @param callback 分享结果回调
+   *                 参数:success (boolean), platform (string?), errorMessage (string?)
+   */
+  share(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    platform?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信
+   */
+  shareToWeChat(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信朋友圈
+   */
+  shareToWeChatMoments(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ
+   */
+  shareToQQ(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ空间
+   */
+  shareToQZone(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微博
+   */
+  shareToWeibo(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 系统分享(调用系统分享菜单)
+   */
+  shareToSystem(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+}
+
+// IShareCallback 接口已分离到 IShareCallback.ets 文件中
+

+ 29 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareCallback.ets

@@ -0,0 +1,29 @@
+/**
+ * 分享回调接口
+ * 
+ * 用于处理分享结果回调
+ */
+export interface IShareCallback {
+  /**
+   * 分享成功回调
+   * 
+   * @param platform 分享平台(如:wechat, qq, weibo)
+   */
+  onSuccess(platform: string): void;
+  
+  /**
+   * 分享失败回调
+   * 
+   * @param platform 分享平台(如:wechat, qq, weibo)
+   * @param errorMessage 错误信息
+   */
+  onError(platform: string, errorMessage: string): void;
+  
+  /**
+   * 分享取消回调
+   * 
+   * @param platform 分享平台(如:wechat, qq, weibo)
+   */
+  onCancel(platform: string): void;
+}
+

+ 166 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareService.ets

@@ -0,0 +1,166 @@
+import { Context } from '@kit.AbilityKit';
+import { Want } from '@kit.AbilityKit';
+
+/**
+ * 分享服务接口
+ * 
+ * 用于 base-core 与 share 模块之间的解耦
+ * share 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IShareService {
+  /**
+   * 初始化分享服务
+   * 
+   * @param context Application 上下文
+   * @param umengAppKey 友盟 AppKey(可选,如果为空则从资源文件读取)
+   * @param umengChannel 友盟渠道(可选,默认为 "developer-default")
+   * @param weChatAppId 微信 AppID(可选)
+   * @param weChatAppSecret 微信 AppSecret(可选)
+   * @param qqAppId QQ AppID(可选)
+   * @param qqAppKey QQ AppKey(可选)
+   * @param weiboAppKey 微博 AppKey(可选)
+   * @param weiboAppSecret 微博 AppSecret(可选)
+   * @param weiboRedirectUrl 微博回调地址(可选)
+   */
+  initialize(
+    context: Context,
+    umengAppKey?: string,
+    umengChannel?: string,
+    weChatAppId?: string,
+    weChatAppSecret?: string,
+    qqAppId?: string,
+    qqAppKey?: string,
+    weiboAppKey?: string,
+    weiboAppSecret?: string,
+    weiboRedirectUrl?: string
+  ): Promise<void>;
+  
+  /**
+   * 处理分享回调(内部使用)
+   * 
+   * @param want Want 对象(HarmonyOS 的回调方式)
+   */
+  onShareResult(want: Want): void;
+  
+  /**
+   * 统一分享方法(推荐使用)
+   * 
+   * @param context Context 上下文
+   * @param title 分享标题
+   * @param description 分享描述
+   * @param url 分享链接(可选)
+   * @param imageUrl 图片URL(可选)
+   * @param thumbImageUrl 缩略图URL(可选)
+   * @param platform 分享平台(可选,如果为 null 则显示分享弹窗)
+   * @param callback 分享结果回调
+   *                 参数:success (boolean), platform (string?), errorMessage (string?)
+   */
+  share(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    platform?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信
+   */
+  shareToWeChat(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信朋友圈
+   */
+  shareToWeChatMoments(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ
+   */
+  shareToQQ(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ空间
+   */
+  shareToQZone(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微博
+   */
+  shareToWeibo(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 系统分享(调用系统分享菜单)
+   */
+  shareToSystem(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+}
+
+/**
+ * 分享回调接口
+ * 
+ * 用于 base-core 与 share 模块之间的解耦
+ * base-core 中的 WXEntryAbility 等回调 Ability 通过此接口调用 share 模块的实现
+ * 
+ * share 模块需要实现此接口
+ */
+export interface IShareCallback {
+  /**
+   * 处理微信回调
+   * 
+   * @param want Want 对象(HarmonyOS 的回调方式)
+   */
+  onWeChatCallback(want: Want): void;
+}
+

+ 30 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/storage/IStorage.ets

@@ -0,0 +1,30 @@
+/**
+ * 存储服务接口
+ * 统一封装键值存储、文件存储、数据库存储
+ * 
+ * 实现类:StorageImpl(在 base-core 中提供)
+ * 所有模块都可以直接使用 StorageImpl 进行数据存储
+ */
+export interface IStorage {
+  /**
+   * 键值存储
+   */
+  putString(key: string, value: string): Promise<void>;
+  getString(key: string, defaultValue?: string): Promise<string>;
+  putInt(key: string, value: number): Promise<void>;
+  getInt(key: string, defaultValue?: number): Promise<number>;
+  putLong(key: string, value: number): Promise<void>;
+  getLong(key: string, defaultValue?: number): Promise<number>;
+  putBoolean(key: string, value: boolean): Promise<void>;
+  getBoolean(key: string, defaultValue?: boolean): Promise<boolean>;
+  remove(key: string): Promise<void>;
+  clear(): Promise<void>;
+  
+  /**
+   * 文件存储
+   */
+  saveFile(path: string, data: Uint8Array): Promise<boolean>;
+  readFile(path: string): Promise<Uint8Array | null>;
+  deleteFile(path: string): Promise<boolean>;
+}
+

+ 346 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageImpl.ets

@@ -0,0 +1,346 @@
+import dataPreferences from '@ohos.data.preferences';
+import { Context } from '@kit.AbilityKit';
+import { IStorage } from './IStorage';
+import { fileIo } from '@kit.CoreFileKit';
+import { ILog } from '../log/ILog';
+
+/**
+ * 存储服务实现类(基于 HarmonyOS preferences)
+ * 
+ * 统一提供键值存储和文件存储功能
+ * 单例模式,需要在 Application 中初始化
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 在 Application 中初始化
+ * await StorageImpl.init(context);
+ * 
+ * // 使用存储
+ * await StorageImpl.putString("key", "value");
+ * const value = await StorageImpl.getString("key");
+ * ```
+ */
+export class StorageImpl implements IStorage {
+  private static instance: StorageImpl | null = null;
+  private static readonly PREFS_NAME = 'xdz_storage_prefs';
+  private dataPreferences: dataPreferences.Preferences | null = null;
+  private context: Context | null = null;
+  private initialized = false;
+  
+  private constructor() {
+    // 私有构造函数,单例模式
+  }
+  
+  /**
+   * 获取单例实例
+   */
+  static getInstance(): StorageImpl {
+    if (!StorageImpl.instance) {
+      StorageImpl.instance = new StorageImpl();
+    }
+    return StorageImpl.instance;
+  }
+  
+  /**
+   * 初始化存储服务
+   * 
+   * 需要在 Application.onCreate() 中调用
+   * 
+   * @param ctx 应用上下文
+   */
+  static async init(ctx: Context): Promise<void> {
+    try {
+      const instance = StorageImpl.getInstance();
+      instance.context = ctx;
+      instance.dataPreferences = await dataPreferences.getPreferences(ctx, StorageImpl.PREFS_NAME);
+      instance.initialized = true;
+    } catch (err) {
+      ILog.e('StorageImpl', '初始化失败', err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  /**
+   * 检查是否已初始化
+   */
+  static isInitialized(): boolean {
+    return StorageImpl.getInstance().initialized;
+  }
+  
+  // ========== 键值存储 ==========
+  
+  async putString(key: string, value: string): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush,确保数据立即持久化
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putString操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getString(key: string, defaultValue: string = ''): Promise<string> {
+    try {
+      if (!this.dataPreferences) {
+        ILog.w('StorageImpl', `getString: dataPreferences 未初始化,key=${key}`);
+        return defaultValue;
+      }
+      // ✅ 修复:不使用 defaultValue,让 get() 返回实际值或 undefined
+      const value = await this.dataPreferences.get(key, undefined);
+      
+      // ✅ 修复:明确处理各种情况
+      if (value === undefined || value === null) {
+        return defaultValue;
+      }
+      
+      // ✅ 修复:确保返回字符串类型
+      if (typeof value === 'string') {
+        return value;
+      }
+      
+      // ✅ 修复:如果不是字符串,转换为字符串
+      return String(value);
+    } catch (err) {
+      ILog.e('StorageImpl', `getString操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async putInt(key: string, value: number): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putInt操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getInt(key: string, defaultValue: number = 0): Promise<number> {
+    try {
+      if (!this.dataPreferences) {
+        return defaultValue;
+      }
+      const value = await this.dataPreferences.get(key, defaultValue);
+      return typeof value === 'number' ? value : defaultValue;
+    } catch (err) {
+      ILog.e('StorageImpl', 'getInt操作失败', err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async putLong(key: string, value: number): Promise<void> {
+    try {
+      // HarmonyOS preferences 使用 number 类型,可以存储 Long 值
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putLong操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getLong(key: string, defaultValue: number = 0): Promise<number> {
+    try {
+      if (!this.dataPreferences) {
+        return defaultValue;
+      }
+      const value = await this.dataPreferences.get(key, defaultValue);
+      return typeof value === 'number' ? value : defaultValue;
+    } catch (err) {
+      ILog.e('StorageImpl', 'getLong操作失败', err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async putBoolean(key: string, value: boolean): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putBoolean操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
+    try {
+      if (!this.dataPreferences) {
+        return defaultValue;
+      }
+      const value = await this.dataPreferences.get(key, defaultValue);
+      return typeof value === 'boolean' ? value : defaultValue;
+    } catch (err) {
+      ILog.e('StorageImpl', 'getBoolean操作失败', err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async remove(key: string): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        return;
+      }
+      // ✅ 修复:delete 后立即 flush
+      await this.dataPreferences.delete(key);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `remove操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+    }
+  }
+  
+  async clear(): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        return;
+      }
+      await this.dataPreferences.clear();
+      // clear 操作后可以调用 flush 确保立即持久化
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', 'clear操作失败', err instanceof Error ? err : new Error(String(err)));
+    }
+  }
+  
+  /**
+   * 手动刷新数据到磁盘(可选方法)
+   * 
+   * 在批量操作后可以调用此方法确保数据立即持久化
+   */
+  async flush(): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        ILog.w('StorageImpl', 'flush: dataPreferences 未初始化');
+        return;
+      }
+      // ✅ 修复:flush 必须等待完成,如果失败要抛出错误
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', 'flush操作失败', err instanceof Error ? err : new Error(String(err)));
+      // ✅ 修复:抛出错误,让调用方知道失败(ArkTS 要求必须是 Error 类型)
+      if (err instanceof Error) {
+        throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  // ========== 文件存储 ==========
+  
+  async saveFile(path: string, data: Uint8Array): Promise<boolean> {
+    try {
+      const ctx = this.context;
+      if (!ctx) {
+        return false;
+      }
+      
+      const filesDir = ctx.filesDir;
+      const filePath = `${filesDir}/${path}`;
+      
+      // 确保目录存在
+      const dirPath = filePath.substring(0, filePath.lastIndexOf('/'));
+      await fileIo.mkdir(dirPath, true);
+      
+      // 写入文件
+      const file = await fileIo.open(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY);
+      await fileIo.write(file.fd, data.buffer);
+      await fileIo.close(file.fd);
+      
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+  
+  async readFile(path: string): Promise<Uint8Array | null> {
+    try {
+      const ctx = this.context;
+      if (!ctx) {
+        return null;
+      }
+      
+      const filePath = `${ctx.filesDir}/${path}`;
+      
+      // 检查文件是否存在
+      const stat = await fileIo.stat(filePath);
+      if (!stat.isFile()) {
+        return null;
+      }
+      
+      // 读取文件
+      const file = await fileIo.open(filePath, fileIo.OpenMode.READ_ONLY);
+      const statInfo = await fileIo.stat(filePath);
+      const buffer = new ArrayBuffer(statInfo.size);
+      await fileIo.read(file.fd, buffer);
+      await fileIo.close(file.fd);
+      
+      return new Uint8Array(buffer);
+    } catch (e) {
+      return null;
+    }
+  }
+  
+  async deleteFile(path: string): Promise<boolean> {
+    try {
+      const ctx = this.context;
+      if (!ctx) {
+        return false;
+      }
+      
+      const filePath = `${ctx.filesDir}/${path}`;
+      
+      // 检查文件是否存在
+      const stat = await fileIo.stat(filePath);
+      if (!stat.isFile()) {
+        return false;
+      }
+      
+      // 删除文件
+      await fileIo.unlink(filePath);
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+}
+
+// 导出单例实例,方便使用
+export const storageImpl = StorageImpl.getInstance();
+

+ 16 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageKeys.ets

@@ -0,0 +1,16 @@
+/**
+ * 存储键常量定义
+ * 
+ * 统一管理所有存储键,避免硬编码字符串
+ */
+export class StorageKeys {
+  // Token 相关
+  static readonly TOKEN_ACCESS = 'token_access';
+  static readonly TOKEN_REFRESH = 'token_refresh';
+  static readonly TOKEN_USER_ID = 'token_user_id';
+  
+  // 应用配置相关
+  static readonly APP_SERVER_URL = 'app_server_url';
+  static readonly APP_SOCKET_URL = 'app_socket_url';
+  static readonly APP_IS_LOGIN = 'app_is_login';
+}

File diff suppressed because it is too large
+ 1170 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/util/IUtil.ets


+ 201 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/core/util/JWTUtil.ets

@@ -0,0 +1,201 @@
+/**
+ * JWT Token 工具类
+ * 
+ * 提供 JWT Token 解析和验证功能
+ * 参考 iOS 和 Android 实现
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 检查 Token 是否有效(未过期)
+ * const isValid = JWTUtil.isTokenValid(token);
+ * 
+ * // 获取 Token 过期时间
+ * const expiresAt = JWTUtil.getExpiresAt(token);
+ * ```
+ */
+
+/**
+ * JWT Payload 接口
+ * 
+ * 定义 JWT Token payload 的标准字段
+ * 注意:ArkTS 不支持索引签名和 unknown 类型,因此移除了其他字段的定义
+ */
+interface JwtPayload {
+  exp?: number;  // 过期时间(Unix时间戳,单位:秒)
+  iat?: number;  // 签发时间
+  userId?: string;  // 用户ID
+}
+
+/**
+ * JWT Token 工具类
+ * 
+ * 提供 JWT Token 解析和验证功能
+ */
+export class JWTUtil {
+  /**
+   * Base64URL 解码
+   * 
+   * JWT 使用 Base64URL 编码,需要将 URL 安全的字符转换回标准 Base64
+   * - 将 '-' 替换为 '+'
+   * - 将 '_' 替换为 '/'
+   * - 添加必要的 padding
+   * 
+   * @param base64Url Base64URL 编码的字符串
+   * @returns 解码后的 Uint8Array,如果解码失败返回 null
+   */
+  private static base64UrlDecode(base64Url: string): Uint8Array | null {
+    try {
+      // Base64URL 转 Base64
+      let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
+      
+      // 添加 padding
+      const padLength = (4 - base64.length % 4) % 4;
+      base64 = base64 + '='.repeat(padLength);
+      
+      // HarmonyOS 使用手动实现的 Base64 解码
+      return JWTUtil.base64Decode(base64);
+    } catch (e) {
+      return null;
+    }
+  }
+  
+  /**
+   * Base64 解码(手动实现)
+   * 
+   * @param base64 Base64 编码的字符串
+   * @returns 解码后的 Uint8Array
+   */
+  private static base64Decode(base64: string): Uint8Array {
+    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+    let output = '';
+    
+    base64 = base64.replace(/[^A-Za-z0-9\+\/\=]/g, '');
+    
+    for (let i = 0; i < base64.length; i += 4) {
+      const enc1 = chars.indexOf(base64.charAt(i));
+      const enc2 = chars.indexOf(base64.charAt(i + 1));
+      const enc3 = chars.indexOf(base64.charAt(i + 2));
+      const enc4 = chars.indexOf(base64.charAt(i + 3));
+      
+      const chr1 = (enc1 << 2) | (enc2 >> 4);
+      const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+      const chr3 = ((enc3 & 3) << 6) | enc4;
+      
+      output += String.fromCharCode(chr1);
+      
+      if (enc3 !== 64) {
+        output += String.fromCharCode(chr2);
+      }
+      if (enc4 !== 64) {
+        output += String.fromCharCode(chr3);
+      }
+    }
+    
+    const bytes = new Uint8Array(output.length);
+    for (let i = 0; i < output.length; i++) {
+      bytes[i] = output.charCodeAt(i);
+    }
+    return bytes;
+  }
+  
+  /**
+   * 解析 JWT Token 并检查是否过期
+   * 
+   * @param token JWT Token
+   * @returns true 如果 Token 未过期,false 如果过期或无法解析
+   */
+  static isTokenValid(token: string): boolean {
+    if (!token || token === '') {
+      return false;
+    }
+    
+    // JWT 格式:header.payload.signature
+    const parts = token.split('.');
+    if (parts.length !== 3) {
+      return false;
+    }
+    
+    // 解析 payload(第二部分)
+    const payload = parts[1];
+    
+    // Base64URL 解码
+    const payloadData = JWTUtil.base64UrlDecode(payload);
+    if (!payloadData) {
+      return false;
+    }
+    
+    // 转换为 JSON 字符串(手动实现 UTF-8 解码)
+    const payloadString = JWTUtil.uint8ArrayToString(payloadData);
+    
+    try {
+      const payloadJson: JwtPayload = JSON.parse(payloadString) as JwtPayload;
+      const exp = payloadJson.exp;
+      
+      if (typeof exp !== 'number') {
+        return false;
+      }
+      
+      // 检查是否过期(exp 是 Unix 时间戳,单位:秒)
+      const currentTime = Math.floor(Date.now() / 1000);
+      return exp > currentTime;
+    } catch (e) {
+      return false;
+    }
+  }
+  
+  /**
+   * 解析 JWT Token 并获取过期时间
+   * 
+   * @param token JWT Token
+   * @returns 过期时间(Unix 时间戳,单位:秒),如果无法解析返回 null
+   */
+  static getExpiresAt(token: string): number | null {
+    if (!token || token === '') {
+      return null;
+    }
+    
+    // JWT 格式:header.payload.signature
+    const parts = token.split('.');
+    if (parts.length !== 3) {
+      return null;
+    }
+    
+    // 解析 payload(第二部分)
+    const payload = parts[1];
+    
+    // Base64URL 解码
+    const payloadData = JWTUtil.base64UrlDecode(payload);
+    if (!payloadData) {
+      return null;
+    }
+    
+    // 转换为 JSON 字符串(手动实现 UTF-8 解码)
+    const payloadString = JWTUtil.uint8ArrayToString(payloadData);
+    
+    try {
+      const payloadJson: JwtPayload = JSON.parse(payloadString) as JwtPayload;
+      const exp = payloadJson.exp;
+      
+      if (typeof exp === 'number') {
+        return exp;
+      }
+      return null;
+    } catch (e) {
+      return null;
+    }
+  }
+  
+  /**
+   * 将 Uint8Array 转换为 UTF-8 字符串(手动实现)
+   * 
+   * @param bytes Uint8Array
+   * @returns UTF-8 字符串
+   */
+  private static uint8ArrayToString(bytes: Uint8Array): string {
+    let result = '';
+    for (let i = 0; i < bytes.length; i++) {
+      result += String.fromCharCode(bytes[i]);
+    }
+    return result;
+  }
+}

+ 36 - 0
base-common/oh_modules/@xdz/base-core/src/main/ets/index.ets

@@ -0,0 +1,36 @@
+/**
+ * base-core 模块导出入口
+ * 
+ * 统一导出所有核心接口和实现
+ */
+
+// 日志模块
+export { ILog, ILogger, LogLevel } from './core/log/ILog';
+export { HilogLogger } from './core/log/impl/HilogLogger';
+export { NoOpLogger } from './core/log/impl/NoOpLogger';
+export { FloatingLogButton } from './core/log/FloatingLogButton';
+
+// 存储模块
+export { IStorage } from './core/storage/IStorage';
+export { StorageImpl, storageImpl } from './core/storage/StorageImpl';
+export { StorageKeys } from './core/storage/StorageKeys';
+
+// 网络模块
+export { NetworkManager, networkManager } from './core/network/NetworkManager';
+
+// 推送模块
+export { IPush } from './core/push/IPush';
+
+// 分享模块
+export { IShare } from './core/share/IShare';
+export { IShareCallback } from './core/share/IShareCallback';
+
+// 工具模块
+export { JWTUtil } from './core/util/JWTUtil';
+export { IUtil, UtilImpl, utilImpl } from './core/util/IUtil';
+
+// 权限模块
+export { PermissionHelper } from './core/permission/PermissionHelper';
+
+// 统一异常模型(3.1)
+export { AppError, ErrorType, AppErrorRaw } from './core/error/AppError';

+ 13 - 0
base-common/oh_modules/@xdz/base-core/src/main/module.json5

@@ -0,0 +1,13 @@
+{
+  "module": {
+    "name": "base_core",
+    "type": "har",
+    "description": "基础设施层 - 定义接口和基础实现",
+    "mainElement": "",
+    "deviceTypes": [
+      "phone",
+      "tablet"
+    ]
+  }
+}
+

+ 0 - 1
base-common/oh_modules/@xdz/capability-socketio

@@ -1 +0,0 @@
-../../../capability-socketio

+ 31 - 0
base-common/oh_modules/@xdz/capability-socketio/.preview/default/intermediates/merge_profile/default/module.json

@@ -0,0 +1,31 @@
+{
+	"app": {
+		"bundleName": "com.narutohuo.xdz",
+		"debug": true,
+		"versionCode": 1000000,
+		"versionName": "1.0.0",
+		"minAPIVersion": 50000012,
+		"targetAPIVersion": 50000012,
+		"apiReleaseType": "Release",
+		"targetMinorAPIVersion": 0,
+		"targetPatchAPIVersion": 0,
+		"compileSdkVersion": "6.0.2.130",
+		"compileSdkType": "HarmonyOS",
+		"appEnvironments": [],
+		"bundleType": "app",
+		"buildMode": "debug"
+	},
+	"module": {
+		"name": "capability_socketio",
+		"type": "har",
+		"description": "SocketIO 能力层模块",
+		"mainElement": "",
+		"deviceTypes": [
+			"phone",
+			"tablet",
+			"2in1"
+		],
+		"packageName": "@xdz/capability-socketio",
+		"installationFree": false
+	}
+}

+ 17 - 0
base-common/oh_modules/@xdz/capability-socketio/BuildProfile.ets

@@ -0,0 +1,17 @@
+/**
+ * Use these variables when you tailor your ArkTS code. They must be of the const type.
+ */
+export const HAR_VERSION = '1.0.0';
+export const BUILD_MODE_NAME = 'debug';
+export const DEBUG = true;
+export const TARGET_NAME = 'default';
+
+/**
+ * BuildProfile Class is used only for compatibility purposes.
+ */
+export default class BuildProfile { 
+	static readonly HAR_VERSION = HAR_VERSION;
+	static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
+	static readonly DEBUG = DEBUG;
+	static readonly TARGET_NAME = TARGET_NAME;
+}

+ 28 - 0
base-common/oh_modules/@xdz/capability-socketio/build-profile.json5

@@ -0,0 +1,28 @@
+{
+  "apiType": "stageMode",
+  "buildOption": {
+    "resOptions": {
+      "copyCodeResource": {
+        "enable": false
+      }
+    }
+  },
+  "buildOptionSet": [
+    {
+      "name": "release",
+      "arkOptions": {
+        "obfuscation": {
+          "ruleOptions": {
+            "enable": false
+          }
+        }
+      }
+    }
+  ],
+  "targets": [
+    {
+      "name": "default"
+    }
+  ]
+}
+

+ 7 - 0
base-common/oh_modules/@xdz/capability-socketio/hvigorfile.ts

@@ -0,0 +1,7 @@
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+  system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+  plugins: []       /* Custom plugin to extend the functionality of Hvigor. */
+}
+

+ 19 - 0
base-common/oh_modules/@xdz/capability-socketio/oh-package-lock.json5

@@ -0,0 +1,19 @@
+{
+  "meta": {
+    "stableOrder": true,
+    "enableUnifiedLockfile": false
+  },
+  "lockfileVersion": 3,
+  "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+  "specifiers": {
+    "@xdz/base-core@../base-core": "@xdz/base-core@../base-core"
+  },
+  "packages": {
+    "@xdz/base-core@../base-core": {
+      "name": "@xdz/base-core",
+      "version": "1.0.0",
+      "resolved": "../base-core",
+      "registryType": "local"
+    }
+  }
+}

+ 12 - 0
base-common/oh_modules/@xdz/capability-socketio/oh-package.json5

@@ -0,0 +1,12 @@
+{
+  "name": "@xdz/capability-socketio",
+  "version": "1.0.0",
+  "description": "SocketIO 能力层模块 - 提供实时通信能力,可独立打包为 SDK",
+  "main": "src/main/ets/index.ets",
+  "dependencies": {
+    "@xdz/base-core": "file:../base-core"
+  },
+  "license": "MIT",
+  "keywords": ["socketio", "websocket", "realtime", "capability"]
+}
+

+ 30 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/.preview/default/intermediates/merge_profile/default/module.json

@@ -0,0 +1,30 @@
+{
+	"app": {
+		"bundleName": "com.narutohuo.xdz",
+		"debug": true,
+		"versionCode": 1000000,
+		"versionName": "1.0.0",
+		"minAPIVersion": 50000012,
+		"targetAPIVersion": 50000012,
+		"apiReleaseType": "Release",
+		"targetMinorAPIVersion": 0,
+		"targetPatchAPIVersion": 0,
+		"compileSdkVersion": "6.0.2.130",
+		"compileSdkType": "HarmonyOS",
+		"appEnvironments": [],
+		"bundleType": "app",
+		"buildMode": "debug"
+	},
+	"module": {
+		"name": "base_core",
+		"type": "har",
+		"description": "基础设施层 - 定义接口和基础实现",
+		"mainElement": "",
+		"deviceTypes": [
+			"phone",
+			"tablet"
+		],
+		"packageName": "@xdz/base-core",
+		"installationFree": false
+	}
+}

+ 17 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/BuildProfile.ets

@@ -0,0 +1,17 @@
+/**
+ * Use these variables when you tailor your ArkTS code. They must be of the const type.
+ */
+export const HAR_VERSION = '1.0.0';
+export const BUILD_MODE_NAME = 'debug';
+export const DEBUG = true;
+export const TARGET_NAME = 'default';
+
+/**
+ * BuildProfile Class is used only for compatibility purposes.
+ */
+export default class BuildProfile { 
+	static readonly HAR_VERSION = HAR_VERSION;
+	static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
+	static readonly DEBUG = DEBUG;
+	static readonly TARGET_NAME = TARGET_NAME;
+}

+ 28 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/build-profile.json5

@@ -0,0 +1,28 @@
+{
+  "apiType": "stageMode",
+  "buildOption": {
+    "resOptions": {
+      "copyCodeResource": {
+        "enable": false
+      }
+    }
+  },
+  "buildOptionSet": [
+    {
+      "name": "release",
+      "arkOptions": {
+        "obfuscation": {
+          "ruleOptions": {
+            "enable": false
+          }
+        }
+      }
+    }
+  ],
+  "targets": [
+    {
+      "name": "default"
+    }
+  ]
+}
+

+ 7 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/hvigorfile.ts

@@ -0,0 +1,7 @@
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+  system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+  plugins: []       /* Custom plugin to extend the functionality of Hvigor. */
+}
+

+ 11 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/oh-package.json5

@@ -0,0 +1,11 @@
+{
+  "name": "@xdz/base-core",
+  "version": "1.0.0",
+  "description": "基础设施层 - 定义接口和基础实现",
+  "main": "src/main/ets/index.ets",
+  "dependencies": {
+  },
+  "license": "MIT",
+  "keywords": ["base", "core", "infrastructure"]
+}
+

+ 81 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/error/AppError.ets

@@ -0,0 +1,81 @@
+/**
+ * 统一异常模型(3.1)
+ * 
+ * 所有业务异常统一使用 AppError,避免直接使用 Error
+ */
+
+/**
+ * 错误类型枚举
+ */
+export enum ErrorType {
+  BIZ = 'BIZ',           // 业务错误
+  NETWORK = 'NETWORK',   // 网络错误
+  TIMEOUT = 'TIMEOUT',   // 超时错误
+  PARSE = 'PARSE',       // 解析错误
+  UNKNOWN = 'UNKNOWN'    // 未知错误
+}
+
+/**
+ * 原始错误类型(可以是 Error、字符串或其他类型)
+ */
+export type AppErrorRaw = Error | string | object;
+
+/**
+ * 统一异常类
+ */
+export class AppError extends Error {
+  readonly type: ErrorType;
+  readonly code: number;
+  readonly context: string;
+  readonly raw: AppErrorRaw | null;
+
+  constructor(
+    message: string,
+    type: ErrorType,
+    code: number = 0,
+    context: string = '',
+    raw: AppErrorRaw | null = null
+  ) {
+    super(message);
+    this.type = type;
+    this.code = code;
+    this.context = context;
+    this.raw = raw;
+    this.name = 'AppError';
+  }
+
+  /**
+   * 创建业务错误
+   */
+  static biz(message: string, code: number, context: string = ''): AppError {
+    return new AppError(message, ErrorType.BIZ, code, context);
+  }
+
+  /**
+   * 创建网络错误
+   */
+  static network(message: string, raw: AppErrorRaw | null = null): AppError {
+    return new AppError(message, ErrorType.NETWORK, 0, '', raw);
+  }
+
+  /**
+   * 创建超时错误
+   */
+  static timeout(message: string, raw: AppErrorRaw | null = null): AppError {
+    return new AppError(message, ErrorType.TIMEOUT, 0, '', raw);
+  }
+
+  /**
+   * 创建解析错误
+   */
+  static parse(message: string, context: string = ''): AppError {
+    return new AppError(message, ErrorType.PARSE, 0, context);
+  }
+
+  /**
+   * 创建未知错误
+   */
+  static unknown(message: string, raw: AppErrorRaw | null = null): AppError {
+    return new AppError(message, ErrorType.UNKNOWN, 0, '', raw);
+  }
+}

+ 117 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/FloatingLogButton.ets

@@ -0,0 +1,117 @@
+import { Context } from '@kit.AbilityKit';
+import { ILog } from './ILog';
+
+const TAG = "FloatingLogButton";
+
+/**
+ * 悬浮日志按钮
+ * 
+ * 提供悬浮窗显示日志功能,常用于开发调试
+ * 
+ * 功能:
+ * - 显示悬浮日志按钮
+ * - 点击按钮显示日志查看器
+ * - 隐藏悬浮按钮
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { FloatingLogButton } from '@xdz/base-core';
+ * 
+ * // 显示悬浮日志按钮
+ * FloatingLogButton.show(context);
+ * 
+ * // 隐藏悬浮日志按钮
+ * FloatingLogButton.hide();
+ * ```
+ */
+export class FloatingLogButton {
+  private static isShowing: boolean = false;
+  private static context: Context | null = null;
+  
+  /**
+   * 显示悬浮日志按钮
+   * 
+   * @param context 上下文
+   */
+  static show(context: Context): void {
+    try {
+      if (FloatingLogButton.isShowing) {
+        ILog.w(TAG, "悬浮日志按钮已显示");
+        return;
+      }
+      
+      FloatingLogButton.context = context;
+      FloatingLogButton.isShowing = true;
+      
+      // TODO: 使用 HarmonyOS 悬浮窗 API 实现悬浮日志按钮
+      // 注意:HarmonyOS 的悬浮窗实现方式与 Android 不同
+      // 可能需要使用 WindowStage 或其他 API
+      ILog.d(TAG, "悬浮日志按钮已显示(功能待实现)");
+    } catch (e) {
+      ILog.e(TAG, "显示悬浮日志按钮失败", e as Error);
+    }
+  }
+  
+  /**
+   * 隐藏悬浮日志按钮
+   */
+  static hide(): void {
+    try {
+      if (!FloatingLogButton.isShowing) {
+        ILog.w(TAG, "悬浮日志按钮未显示");
+        return;
+      }
+      
+      FloatingLogButton.isShowing = false;
+      FloatingLogButton.context = null;
+      
+      // TODO: 实现隐藏悬浮日志按钮功能
+      ILog.d(TAG, "悬浮日志按钮已隐藏(功能待实现)");
+    } catch (e) {
+      ILog.e(TAG, "隐藏悬浮日志按钮失败", e as Error);
+    }
+  }
+  
+  /**
+   * 检查悬浮日志按钮是否显示
+   * 
+   * @return 是否显示
+   */
+  static isVisible(): boolean {
+    return FloatingLogButton.isShowing;
+  }
+  
+  /**
+   * 切换悬浮日志按钮显示/隐藏状态
+   * 
+   * @param context 上下文(仅在显示时需要)
+   */
+  static toggle(context?: Context): void {
+    if (FloatingLogButton.isShowing) {
+      FloatingLogButton.hide();
+    } else {
+      if (context) {
+        FloatingLogButton.show(context);
+      } else if (FloatingLogButton.context) {
+        FloatingLogButton.show(FloatingLogButton.context);
+      } else {
+        ILog.w(TAG, "无法切换:缺少 context");
+      }
+    }
+  }
+}
+
+/**
+ * 使用示例:
+ * 
+ * ```typescript
+ * // 在开发模式下显示悬浮日志按钮
+ * if (__DEV__) {
+ *   FloatingLogButton.show(context);
+ * }
+ * 
+ * // 点击悬浮按钮时显示日志查看器
+ * // 注意:日志查看器功能需要在 ILog 中实现
+ * ```
+ */
+

+ 175 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/ILog.ets

@@ -0,0 +1,175 @@
+import { HilogLogger } from './impl/HilogLogger';
+import { NoOpLogger } from './impl/NoOpLogger';
+
+/**
+ * 日志级别枚举
+ */
+export enum LogLevel {
+  DEBUG,    // 调试信息
+  INFO,     // 一般信息
+  WARN,     // 警告信息
+  ERROR     // 错误信息
+}
+
+/**
+ * 日志服务接口
+ * 统一封装日志记录、日志文件管理、日志上传、崩溃收集
+ * 
+ * 实现类:HilogLogger(开发环境)、NoOpLogger(生产环境)
+ */
+export interface ILogger {
+  /**
+   * 调试日志
+   */
+  d(tag: string, message: string): void;
+  
+  /**
+   * 信息日志
+   */
+  i(tag: string, message: string): void;
+  
+  /**
+   * 警告日志
+   */
+  w(tag: string, message: string): void;
+  
+  /**
+   * 错误日志
+   */
+  e(tag: string, message: string, throwable?: Error): void;
+  
+  /**
+   * 按级别记录日志
+   * 
+   * @param level 日志级别
+   * @param tag 标签
+   * @param message 消息
+   * @param throwable 异常(可选)
+   */
+  log(level: LogLevel, tag: string, message: string, throwable?: Error): void;
+  
+  /**
+   * 上传日志文件
+   */
+  uploadLogs(): void;
+  
+  /**
+   * 收集崩溃信息
+   */
+  collectCrash(throwable: Error): void;
+}
+
+/**
+ * 日志工具类(类似 Android Log 类)
+ * 
+ * 所有模块通过静态方法进行日志记录
+ * 
+ * **实现选择**:
+ * - **开发环境**(Debug):使用 HilogLogger(输出详细日志)
+ * - **生产环境**(Release):使用 NoOpLogger(不输出日志,提升性能)
+ * 
+ * **使用示例**:
+ * ```typescript
+ * // 1. 在 Application 中初始化(推荐)
+ * // Debug 版本自动启用日志,Release 版本自动禁用
+ * ILog.init(true);
+ * 
+ * // 2. 静态方法调用(推荐,类似 Android Log.d())
+ * ILog.d("Tag", "调试信息");
+ * ILog.e("Tag", "错误信息", exception);
+ * 
+ * // 3. 手动控制(可选)
+ * ILog.init(false); // 生产环境禁用日志
+ * ILog.init(true);  // 开发环境启用日志
+ * ```
+ */
+export class ILog {
+  private static instance: ILogger | null = null;
+  
+  /**
+   * 初始化日志实现(在 Application 中调用,可选)
+   * 
+   * **自动选择实现**:
+   * - 如果 `enableLogging = true`(默认):使用 HilogLogger(开发环境)
+   * - 如果 `enableLogging = false`:使用 NoOpLogger(生产环境,不输出日志)
+   * 
+   * @param enableLogging 是否启用日志(默认 true)
+   * @param logImpl 自定义日志实现(可选,如果指定则忽略 enableLogging 参数)
+   */
+  static init(enableLogging: boolean = true, logImpl?: ILogger): void {
+    if (logImpl) {
+      ILog.instance = logImpl; // 如果指定了自定义实现,优先使用
+    } else if (enableLogging) {
+      // 启用日志(开发环境)
+      ILog.instance = HilogLogger.getInstance();
+    } else {
+      // 禁用日志(生产环境)
+      ILog.instance = NoOpLogger.getInstance();
+    }
+  }
+  
+  /**
+   * 获取日志实现实例(单例)
+   * 
+   * 如果未初始化,默认使用 HilogLogger(开发环境)
+   * 生产环境建议在 Application 中调用 init() 进行初始化
+   */
+  private static getInstance(): ILogger {
+    if (!ILog.instance) {
+      // 默认使用 HilogLogger(开发环境)
+      // 生产环境建议在 Application 中调用 init(false)
+      ILog.instance = HilogLogger.getInstance();
+    }
+    return ILog.instance;
+  }
+  
+  /**
+   * 调试日志(静态方法)
+   */
+  static d(tag: string, message: string): void {
+    ILog.getInstance().d(tag, message);
+  }
+  
+  /**
+   * 信息日志(静态方法)
+   */
+  static i(tag: string, message: string): void {
+    ILog.getInstance().i(tag, message);
+  }
+  
+  /**
+   * 警告日志(静态方法)
+   */
+  static w(tag: string, message: string): void {
+    ILog.getInstance().w(tag, message);
+  }
+  
+  /**
+   * 错误日志(静态方法)
+   */
+  static e(tag: string, message: string, throwable?: Error): void {
+    ILog.getInstance().e(tag, message, throwable);
+  }
+  
+  /**
+   * 按级别记录日志(静态方法)
+   */
+  static log(level: LogLevel, tag: string, message: string, throwable?: Error): void {
+    ILog.getInstance().log(level, tag, message, throwable);
+  }
+  
+  /**
+   * 上传日志文件(静态方法)
+   */
+  static uploadLogs(): void {
+    ILog.getInstance().uploadLogs();
+  }
+  
+  /**
+   * 收集崩溃信息(静态方法)
+   */
+  static collectCrash(throwable: Error): void {
+    ILog.getInstance().collectCrash(throwable);
+  }
+}
+

+ 68 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/HilogLogger.ets

@@ -0,0 +1,68 @@
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { ILogger, LogLevel } from '../ILog';
+
+const DOMAIN = 0x0000;
+
+/**
+ * 基于 HarmonyOS hilog 的日志实现
+ * 
+ * 开发环境使用,输出详细日志
+ */
+export class HilogLogger implements ILogger {
+  private static instance: HilogLogger | null = null;
+  
+  static getInstance(): HilogLogger {
+    if (!HilogLogger.instance) {
+      HilogLogger.instance = new HilogLogger();
+    }
+    return HilogLogger.instance;
+  }
+  
+  d(tag: string, message: string): void {
+    hilog.debug(DOMAIN, tag, '%{public}s', message);
+  }
+  
+  i(tag: string, message: string): void {
+    hilog.info(DOMAIN, tag, '%{public}s', message);
+  }
+  
+  w(tag: string, message: string): void {
+    hilog.warn(DOMAIN, tag, '%{public}s', message);
+  }
+  
+  e(tag: string, message: string, throwable?: Error): void {
+    if (throwable) {
+      hilog.error(DOMAIN, tag, '%{public}s, error: %{public}s', message, throwable.message || 'Unknown error');
+    } else {
+      hilog.error(DOMAIN, tag, '%{public}s', message);
+    }
+  }
+  
+  log(level: LogLevel, tag: string, message: string, throwable?: Error): void {
+    switch (level) {
+      case LogLevel.DEBUG:
+        this.d(tag, message);
+        break;
+      case LogLevel.INFO:
+        this.i(tag, message);
+        break;
+      case LogLevel.WARN:
+        this.w(tag, message);
+        break;
+      case LogLevel.ERROR:
+        this.e(tag, message, throwable);
+        break;
+    }
+  }
+  
+  uploadLogs(): void {
+    // TODO: 实现日志上传功能
+    hilog.info(DOMAIN, 'HilogLogger', 'uploadLogs: 日志上传功能待实现');
+  }
+  
+  collectCrash(throwable: Error): void {
+    hilog.error(DOMAIN, 'Crash', '崩溃信息: %{public}s', throwable.message || 'Unknown crash');
+    // TODO: 实现崩溃收集功能
+  }
+}
+

+ 46 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/log/impl/NoOpLogger.ets

@@ -0,0 +1,46 @@
+import { ILogger, LogLevel } from '../ILog';
+
+/**
+ * 空日志实现(生产环境使用)
+ * 
+ * 不输出任何日志,提升性能
+ */
+export class NoOpLogger implements ILogger {
+  private static instance: NoOpLogger | null = null;
+  
+  static getInstance(): NoOpLogger {
+    if (!NoOpLogger.instance) {
+      NoOpLogger.instance = new NoOpLogger();
+    }
+    return NoOpLogger.instance;
+  }
+  
+  d(tag: string, message: string): void {
+    // 空实现,不输出日志
+  }
+  
+  i(tag: string, message: string): void {
+    // 空实现,不输出日志
+  }
+  
+  w(tag: string, message: string): void {
+    // 空实现,不输出日志
+  }
+  
+  e(tag: string, message: string, throwable?: Error): void {
+    // 空实现,不输出日志
+  }
+  
+  log(level: LogLevel, tag: string, message: string, throwable?: Error): void {
+    // 空实现,不输出日志
+  }
+  
+  uploadLogs(): void {
+    // 空实现
+  }
+  
+  collectCrash(throwable: Error): void {
+    // 空实现
+  }
+}
+

+ 390 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/network/NetworkManager.ets

@@ -0,0 +1,390 @@
+import { http } from '@kit.NetworkKit';
+import { ILog } from '../log/ILog';
+
+/**
+ * HTTP 请求管理器(单例模式)
+ * 
+ * 基于 HarmonyOS @kit.NetworkKit/http 封装
+ * 提供统一的 HTTP 请求接口
+ * 
+ * 使用方式:
+ * ```typescript
+ * const response = await NetworkManager.getInstance().request<ResponseType>(
+ *   'https://api.example.com/data',
+ *   {
+ *     method: http.RequestMethod.GET,
+ *     header: { 'Content-Type': 'application/json' }
+ *   }
+ * );
+ * ```
+ */
+export class NetworkManager {
+  private static instance: NetworkManager | null = null;
+  private httpRequest: http.HttpRequest | null = null;
+  private readonly TAG = 'NetworkManager';
+  
+  /**
+   * Token 刷新提供器(可选,用于自动刷新过期的 Token)
+   * 
+   * 当请求返回 401/402 时,会自动调用此方法刷新 Token
+   * 刷新成功后会自动重试原请求
+   */
+  static refreshTokenProvider: (() => Promise<string | null>) | null = null;
+  
+  /**
+   * Token 刷新失败回调(可选,用于刷新失败时跳转登录)
+   * 
+   * 当 Token 刷新失败时,会自动调用此回调
+   * 可以在 AppInitializer 中设置,实现跳转登录界面
+   */
+  static onTokenRefreshFailed: (() => void) | null = null;
+  
+  /**
+   * Token 提供器(可选,用于自动添加 Token 到请求头)
+   */
+  static tokenProvider: (() => Promise<string | null>) | null = null;
+  
+  // Token 刷新状态(并发控制)
+  private static isRefreshing: boolean = false;
+  
+  private constructor() {
+    // 私有构造函数,单例模式
+  }
+  
+  /**
+   * 获取单例实例
+   */
+  static getInstance(): NetworkManager {
+    if (!NetworkManager.instance) {
+      NetworkManager.instance = new NetworkManager();
+      NetworkManager.instance.httpRequest = http.createHttp();
+    }
+    return NetworkManager.instance;
+  }
+  
+  /**
+   * 发送 HTTP 请求
+   * 
+   * 自动处理 Token 刷新:
+   * - 拦截 401/402 响应(Token 过期/无效)
+   * - 自动调用 refreshTokenProvider 刷新 Token
+   * - 使用新 Token 重试原请求
+   * - 并发控制:多个请求同时 401 时,只刷新一次,其他请求等待
+   * 
+   * @param url 请求 URL
+   * @param options 请求选项
+   * @returns Promise<T> 响应数据
+   */
+  async request<T>(url: string, options: http.HttpRequestOptions): Promise<T> {
+    if (!this.httpRequest) {
+      this.httpRequest = http.createHttp();
+    }
+    
+    try {
+      const response: http.HttpResponse = await this.httpRequest.request(url, options);
+      
+      // 打印响应信息
+      ILog.d(this.TAG, `========== [NetworkManager 响应] ==========`);
+      ILog.d(this.TAG, `[NetworkManager 响应] URL: ${url}`);
+      ILog.d(this.TAG, `[NetworkManager 响应] HTTP状态码: ${response.responseCode}`);
+      if (response.result) {
+        const resultStr = typeof response.result === 'string' 
+          ? response.result 
+          : JSON.stringify(response.result);
+        ILog.d(this.TAG, `[NetworkManager 响应] 响应体: ${resultStr}`);
+      } else {
+        ILog.d(this.TAG, `[NetworkManager 响应] 响应体: (空)`);
+      }
+      
+      // 检查响应状态
+      if (response.responseCode >= 200 && response.responseCode < 300) {
+        // 解析 JSON 响应
+        if (response.result) {
+          const resultStr = typeof response.result === 'string' 
+            ? response.result 
+            : JSON.stringify(response.result);
+          return JSON.parse(resultStr) as T;
+        }
+        // 返回空对象(需要类型断言)
+        // 注意:如果响应为空,返回 null,调用方需要处理
+        return null as T;
+      } else if (response.responseCode === 401 || response.responseCode === 402) {
+        // 拦截 401/402 响应(Token 过期/无效)
+        ILog.w(this.TAG, `[NetworkManager 响应] 收到 401/402,尝试刷新Token`);
+        return await this.handleTokenRefresh<T>(url, options, response);
+      } else {
+        const errorMsg = `HTTP ${response.responseCode}: ${response.result}`;
+        ILog.e(this.TAG, `[NetworkManager 响应] 请求失败: ${errorMsg}`);
+        const error = new Error(errorMsg);
+        throw error;
+      }
+    } catch (error) {
+      ILog.e(this.TAG, `Request failed: ${url}`, error as Error);
+      if (error instanceof Error) {
+        throw error;
+      } else {
+        throw new Error(String(error));
+      }
+    }
+  }
+  
+  /**
+   * 处理 Token 刷新
+   * 
+   * 当收到 401/402 响应时:
+   * 1. 检查是否有 refreshTokenProvider
+   * 2. 如果有,调用刷新 Token
+   * 3. 使用新 Token 重试原请求
+   * 4. 如果刷新失败,调用 onTokenRefreshFailed 回调
+   * 
+   * @param url 请求 URL
+   * @param options 请求选项
+   * @param originalResponse 原始响应(401/402)
+   * @returns Promise<T> 响应数据
+   */
+  private async handleTokenRefresh<T>(
+    url: string,
+    options: http.HttpRequestOptions,
+    originalResponse: http.HttpResponse
+  ): Promise<T> {
+    // 如果没有提供刷新回调,直接抛出错误
+    if (!NetworkManager.refreshTokenProvider) {
+      ILog.w(this.TAG, '收到 401/402 响应,但未设置 refreshTokenProvider,无法自动刷新');
+      const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+      throw new Error(errorMsg);
+    }
+    
+    // 并发控制:如果正在刷新,等待刷新完成
+    if (NetworkManager.isRefreshing) {
+      ILog.d(this.TAG, 'Token 正在刷新中,等待刷新完成...');
+      // 等待刷新完成,最多等待 3 秒
+      let waitCount = 0;
+      while (NetworkManager.isRefreshing && waitCount < 30) {
+        await new Promise<void>((resolve) => {
+          setTimeout(() => {
+            resolve();
+          }, 100);
+        });
+        waitCount++;
+      }
+      
+      // 刷新完成后,使用新 Token 重试
+      if (NetworkManager.tokenProvider) {
+        const newToken = await NetworkManager.tokenProvider();
+        if (newToken && newToken !== '') {
+          ILog.d(this.TAG, '使用刷新后的新 Token 重试请求');
+          // 更新请求头中的 Token
+          const newOptions = this.updateTokenInOptions(options, newToken);
+          const retryResponse: http.HttpResponse = await this.httpRequest!.request(url, newOptions);
+          
+          if (retryResponse.responseCode >= 200 && retryResponse.responseCode < 300) {
+            if (retryResponse.result) {
+              const resultStr = typeof retryResponse.result === 'string' 
+                ? retryResponse.result 
+                : JSON.stringify(retryResponse.result);
+              return JSON.parse(resultStr) as T;
+            }
+            return null as T;
+          } else {
+              const errorMsg = `HTTP ${retryResponse.responseCode}: ${retryResponse.result}`;
+              throw new Error(errorMsg);
+          }
+        } else {
+          ILog.w(this.TAG, '等待刷新完成后,Token 仍为空,返回 401 响应');
+          const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+          throw new Error(errorMsg);
+        }
+      } else {
+        const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+        throw new Error(errorMsg);
+      }
+    } else {
+      // 开始刷新
+      NetworkManager.isRefreshing = true;
+      try {
+        ILog.d(this.TAG, '检测到 401/402 响应,开始刷新 Token...');
+        const newToken = await NetworkManager.refreshTokenProvider();
+        
+        if (newToken && newToken !== '') {
+          ILog.d(this.TAG, 'Token 刷新成功,使用新 Token 重试请求');
+          
+          // 更新请求头中的 Token
+          const newOptions = this.updateTokenInOptions(options, newToken);
+          const retryResponse: http.HttpResponse = await this.httpRequest!.request(url, newOptions);
+          
+          // 如果重试后仍然是 401,说明刷新失败或 Token 无效
+          if (retryResponse.responseCode === 401 || retryResponse.responseCode === 402) {
+            ILog.w(this.TAG, '使用新 Token 重试后仍返回 401/402,Token 刷新可能失败,需要重新登录');
+            // 调用刷新失败回调
+            if (NetworkManager.onTokenRefreshFailed) {
+              NetworkManager.onTokenRefreshFailed();
+            }
+            const errorMsg = `HTTP ${retryResponse.responseCode}: ${retryResponse.result}`;
+            throw new Error(errorMsg);
+          }
+          
+          if (retryResponse.responseCode >= 200 && retryResponse.responseCode < 300) {
+            if (retryResponse.result) {
+              const resultStr = typeof retryResponse.result === 'string' 
+                ? retryResponse.result 
+                : JSON.stringify(retryResponse.result);
+              return JSON.parse(resultStr) as T;
+            }
+            return null as T;
+          } else {
+            const errorMsg = `HTTP ${retryResponse.responseCode}: ${retryResponse.result}`;
+            throw new Error(errorMsg);
+          }
+        } else {
+          ILog.w(this.TAG, 'Token 刷新失败(返回 null),返回 401 响应,需要重新登录');
+          // 调用刷新失败回调
+          if (NetworkManager.onTokenRefreshFailed) {
+            NetworkManager.onTokenRefreshFailed();
+          }
+          const errorMsg = `HTTP ${originalResponse.responseCode}: ${originalResponse.result}`;
+          throw new Error(errorMsg);
+        }
+      } catch (e) {
+        ILog.e(this.TAG, 'Token 刷新异常', e as Error);
+        // 调用刷新失败回调
+        if (NetworkManager.onTokenRefreshFailed) {
+          NetworkManager.onTokenRefreshFailed();
+        }
+        if (e instanceof Error) {
+          throw e;
+        } else {
+          throw new Error(String(e));
+        }
+      } finally {
+        NetworkManager.isRefreshing = false;
+      }
+    }
+  }
+  
+  /**
+   * 更新请求选项中的 Token
+   * 
+   * @param options 原始请求选项
+   * @param token 新的 Token
+   * @returns 更新后的请求选项
+   */
+  private updateTokenInOptions(
+    options: http.HttpRequestOptions,
+    token: string
+  ): http.HttpRequestOptions {
+    // ArkTS 不支持展开运算符,手动复制 header
+    const newHeader: Record<string, string> = {};
+    if (options.header) {
+      const keys = Object.keys(options.header);
+      for (let i = 0; i < keys.length; i++) {
+        const key = keys[i];
+        newHeader[key] = options.header[key];
+      }
+    }
+    
+    // 更新 Authorization 头
+    newHeader['Authorization'] = `Bearer ${token}`;
+    
+    const newOptions: http.HttpRequestOptions = {
+      method: options.method,
+      header: newHeader,
+      extraData: options.extraData,
+      readTimeout: options.readTimeout,
+      connectTimeout: options.connectTimeout
+    };
+    
+    return newOptions;
+  }
+  
+  /**
+   * GET 请求
+   */
+  async get<T>(url: string, headers?: Record<string, string>): Promise<T> {
+    const options: http.HttpRequestOptions = {
+      method: http.RequestMethod.GET,
+      header: headers
+    };
+    return this.request<T>(url, options);
+  }
+  
+  /**
+   * POST 请求
+   */
+  async post<T>(url: string, data?: object, headers?: Record<string, string>): Promise<T> {
+    const header: Record<string, string> = {
+      'Content-Type': 'application/json'
+    };
+    if (headers) {
+      const keys = Object.keys(headers);
+      for (let i = 0; i < keys.length; i++) {
+        const key = keys[i];
+        header[key] = headers[key];
+      }
+    }
+    
+    // 打印实际发送的请求信息
+    ILog.d(this.TAG, `========== [NetworkManager POST] ==========`);
+    ILog.d(this.TAG, `[NetworkManager POST] 完整URL: ${url}`);
+    if (data) {
+      const requestBody = JSON.stringify(data);
+      ILog.d(this.TAG, `[NetworkManager POST] 请求体: ${requestBody}`);
+    } else {
+      ILog.d(this.TAG, `[NetworkManager POST] 请求体: (无)`);
+    }
+    ILog.d(this.TAG, `[NetworkManager POST] 请求头: ${JSON.stringify(header)}`);
+    
+    const postOptions: http.HttpRequestOptions = {
+      method: http.RequestMethod.POST,
+      header: header,
+      extraData: data ? JSON.stringify(data) : undefined
+    };
+    return this.request<T>(url, postOptions);
+  }
+  
+  /**
+   * PUT 请求
+   */
+  async put<T>(url: string, data?: object, headers?: Record<string, string>): Promise<T> {
+    const header: Record<string, string> = {
+      'Content-Type': 'application/json'
+    };
+    if (headers) {
+      const keys = Object.keys(headers);
+      for (let i = 0; i < keys.length; i++) {
+        const key = keys[i];
+        header[key] = headers[key];
+      }
+    }
+    const putOptions: http.HttpRequestOptions = {
+      method: http.RequestMethod.PUT,
+      header: header,
+      extraData: data ? JSON.stringify(data) : undefined
+    };
+    return this.request<T>(url, putOptions);
+  }
+  
+  /**
+   * DELETE 请求
+   */
+  async delete<T>(url: string, headers?: Record<string, string>): Promise<T> {
+    const deleteOptions: http.HttpRequestOptions = {
+      method: http.RequestMethod.DELETE,
+      header: headers
+    };
+    return this.request<T>(url, deleteOptions);
+  }
+  
+  /**
+   * 销毁 HTTP 请求实例
+   */
+  destroy(): void {
+    if (this.httpRequest) {
+      this.httpRequest.destroy();
+      this.httpRequest = null;
+    }
+  }
+}
+
+// 导出单例实例,方便使用
+export const networkManager = NetworkManager.getInstance();
+

+ 279 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/permission/PermissionHelper.ets

@@ -0,0 +1,279 @@
+import { abilityAccessCtrl, common, Context } from '@kit.AbilityKit';
+import { ILog } from '../log/ILog';
+
+const TAG = "PermissionHelper";
+
+// HarmonyOS API 类型定义辅助
+// requestPermissionsFromUser 返回的数据结构
+interface PermissionRequestData {
+  authResults: Array<number>; // GrantStatus 数组
+}
+
+/**
+ * 权限管理封装
+ * 
+ * 统一封装 HarmonyOS 权限请求功能,提供便捷的权限管理方式
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 检查权限(异步方法)
+ * const hasPermission = await PermissionHelper.checkPermission(context, 'ohos.permission.CAMERA');
+ * 
+ * // 请求单个权限
+ * PermissionHelper.requestPermission(context, 'ohos.permission.CAMERA', (granted) => {
+ *   if (granted) {
+ *     // 权限已授予
+ *   }
+ * })
+ * 
+ * // 请求多个权限
+ * PermissionHelper.requestPermissions(context, [
+ *   'ohos.permission.CAMERA',
+ *   'ohos.permission.READ_MEDIA'
+ * ], (permissions) => {
+ *   // 处理权限结果
+ * })
+ * ```
+ */
+export class PermissionHelper {
+  /**
+   * 检查权限是否已授予(异步方法)
+   * 
+   * HarmonyOS 权限检查是异步的,必须使用此方法
+   * 
+   * @param context Context 实例
+   * @param permission 权限名称(如 'ohos.permission.CAMERA')
+   * @return Promise<boolean> true 表示已授予,false 表示未授予
+   */
+  static async checkPermission(context: Context, permission: string): Promise<boolean> {
+    try {
+      const atManager = abilityAccessCtrl.createAtManager();
+      // HarmonyOS 权限检查:使用 checkAccessToken,需要 tokenId 和 permission
+      // tokenId 通过 context 获取,permission 需要转换为正确的类型
+      const tokenId = context.applicationInfo?.accessTokenId ?? 0;
+      if (tokenId === 0) {
+        ILog.w(TAG, "无法获取 tokenId,权限检查失败");
+        return false;
+      }
+      // checkAccessToken 接受 permission 参数,需要类型转换
+      // Permissions 类型未导出,使用类型断言处理
+      // 使用函数类型断言绕过类型检查
+      const checkAccessTokenFunc = atManager.checkAccessToken as (
+        tokenId: number,
+        permission: string
+      ) => Promise<abilityAccessCtrl.GrantStatus>;
+      const grantStatus = await checkAccessTokenFunc(tokenId, permission);
+      return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
+    } catch (e) {
+      ILog.e(TAG, `检查权限失败: ${permission}`, e as Error);
+      return false;
+    }
+  }
+
+  /**
+   * 检查多个权限是否已授予(异步方法)
+   * 
+   * @param context Context 实例
+   * @param permissions 权限名称数组
+   * @return Promise<Map<权限名, 是否授予>>
+   */
+  static async checkPermissions(context: Context, permissions: string[]): Promise<Record<string, boolean>> {
+    const result: Record<string, boolean> = {};
+    for (let i = 0; i < permissions.length; i++) {
+      const permission = permissions[i];
+      result[permission] = await PermissionHelper.checkPermission(context, permission);
+    }
+    return result;
+  }
+  
+  /**
+   * 检查所有权限是否都已授予(异步方法)
+   * 
+   * @param context Context 实例
+   * @param permissions 权限名称数组
+   * @return Promise<boolean> true 表示所有权限都已授予
+   */
+  static async checkAllPermissionsGranted(context: Context, permissions: string[]): Promise<boolean> {
+    const results = await PermissionHelper.checkPermissions(context, permissions);
+    return Object.values(results).every(granted => granted);
+  }
+  
+  /**
+   * 请求单个权限
+   * 
+   * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
+   * 
+   * @param context Context 实例(必须是 UIAbilityContext)
+   * @param permission 权限名称
+   * @param onResult 权限请求结果回调(是否授予)
+   */
+  static async requestPermission(
+    context: Context,
+    permission: string,
+    onResult: (granted: boolean) => void
+  ): Promise<void> {
+    try {
+      // 先异步检查权限是否已授予
+      const hasPermission = await PermissionHelper.checkPermission(context, permission);
+      if (hasPermission) {
+        onResult(true);
+        return;
+      }
+      
+      // 请求权限(HarmonyOS 推荐方式)
+      const atManager = abilityAccessCtrl.createAtManager();
+      const permissionsArray: Array<string> = [permission];
+      
+      // HarmonyOS API 类型定义问题:requestPermissionsFromUser 要求 Permissions[] 类型
+      // 但 Permissions 类型未导出,实际运行时接受 string[]
+      // 使用类型断言处理:将 string[] 断言为方法期望的类型
+      // 注意:这是 HarmonyOS API 类型定义的问题,运行时不会有问题
+      // 使用双重类型断言绕过类型检查
+      const requestResult = await (atManager.requestPermissionsFromUser as (
+        context: Context,
+        permissions: Array<string>
+      ) => Promise<PermissionRequestData>)(context, permissionsArray);
+      
+      const grantResults = requestResult.authResults;
+      const grantStatus = grantResults[0];
+      const granted = grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
+      onResult(granted);
+    } catch (e) {
+      ILog.e(TAG, `请求权限异常: ${permission}`, e as Error);
+      onResult(false);
+    }
+  }
+  
+  /**
+   * 请求多个权限
+   * 
+   * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
+   * 
+   * @param context Context 实例(必须是 UIAbilityContext)
+   * @param permissions 权限名称数组
+   * @param onResult 权限请求结果回调(Map<权限名, 是否授予>)
+   */
+  static async requestPermissions(
+    context: Context,
+    permissions: string[],
+    onResult: (permissions: Record<string, boolean>) => void
+  ): Promise<void> {
+    try {
+      // 先异步检查已授予的权限
+      const checkedPermissions: Record<string, boolean> = {};
+      const ungrantedPermissions: string[] = [];
+      
+      for (let i = 0; i < permissions.length; i++) {
+        const permission = permissions[i];
+        const hasPermission = await PermissionHelper.checkPermission(context, permission);
+        checkedPermissions[permission] = hasPermission;
+        if (!hasPermission) {
+          ungrantedPermissions.push(permission);
+        }
+      }
+      
+      if (ungrantedPermissions.length === 0) {
+        // 所有权限都已授予
+        onResult(checkedPermissions);
+        return;
+      }
+      
+      // 请求未授予的权限(HarmonyOS 推荐方式)
+      const atManager = abilityAccessCtrl.createAtManager();
+      const permissionsArray: Array<string> = [];
+      for (let i = 0; i < ungrantedPermissions.length; i++) {
+        permissionsArray.push(ungrantedPermissions[i]);
+      }
+      
+      // HarmonyOS API 类型定义问题:requestPermissionsFromUser 要求 Permissions[] 类型
+      // 但 Permissions 类型未导出,实际运行时接受 string[]
+      // 使用函数类型断言绕过类型检查
+      const requestPermissionsFunc = atManager.requestPermissionsFromUser as (
+        context: Context,
+        permissions: Array<string>
+      ) => Promise<PermissionRequestData>;
+      const requestResult = await requestPermissionsFunc(context, permissionsArray);
+      
+      const grantResults = requestResult.authResults;
+      const result: Record<string, boolean> = {};
+      // 复制已检查的权限结果
+      const checkedKeys = Object.keys(checkedPermissions);
+      for (let i = 0; i < checkedKeys.length; i++) {
+        const key = checkedKeys[i];
+        result[key] = checkedPermissions[key];
+      }
+      
+      // 更新请求的权限结果
+      for (let i = 0; i < ungrantedPermissions.length; i++) {
+        const permission = ungrantedPermissions[i];
+        const grantStatus = grantResults[i];
+        result[permission] = grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
+      }
+      
+      onResult(result);
+    } catch (e) {
+      ILog.e(TAG, `请求多个权限异常`, e as Error);
+      // 返回已检查的结果(即使有异常也返回部分结果)
+      const checkedPermissions: Record<string, boolean> = {};
+      for (let i = 0; i < permissions.length; i++) {
+        const permission = permissions[i];
+        try {
+          checkedPermissions[permission] = await PermissionHelper.checkPermission(context, permission);
+        } catch (checkError) {
+          checkedPermissions[permission] = false;
+        }
+      }
+      onResult(checkedPermissions);
+    }
+  }
+  
+  /**
+   * 请求权限(带说明对话框)
+   * 
+   * 外部接口与 Android 保持一致,内部使用 HarmonyOS 推荐方式
+   * 
+   * @param context Context 实例
+   * @param permission 权限名称
+   * @param rationale 权限说明文本
+   * @param onResult 权限请求结果回调
+   */
+  static async requestPermissionWithRationale(
+    context: Context,
+    permission: string,
+    rationale: string,
+    onResult: (granted: boolean) => void
+  ): Promise<void> {
+    // 先异步检查权限是否已授予
+    const hasPermission = await PermissionHelper.checkPermission(context, permission);
+    if (hasPermission) {
+      onResult(true);
+      return;
+    }
+    
+    // HarmonyOS 权限系统与 Android 不同,这里简化处理
+    // 直接请求权限(不显示对话框,因为 base-core 不应该依赖 base-common 的 DialogHelper)
+    // 如果需要显示对话框,应该在业务层(base-common)中实现
+    PermissionHelper.requestPermission(context, permission, onResult);
+  }
+  
+  /**
+   * 获取权限说明文本(根据权限类型)
+   * 
+   * @param permission 权限名称
+   * @return 权限说明文本
+   */
+  static getPermissionRationale(permission: string): string {
+    const rationaleMap: Record<string, string> = {
+      'ohos.permission.CAMERA': '需要访问相机以拍摄照片',
+      'ohos.permission.READ_MEDIA': '需要访问媒体文件以选择图片',
+      'ohos.permission.WRITE_MEDIA': '需要保存文件到设备',
+      'ohos.permission.READ_CONTACTS': '需要访问通讯录',
+      'ohos.permission.WRITE_CONTACTS': '需要修改通讯录',
+      'ohos.permission.LOCATION': '需要访问位置信息',
+      'ohos.permission.MICROPHONE': '需要访问麦克风以录制音频',
+    };
+    
+    return rationaleMap[permission] || `需要${permission}权限以完成操作`;
+  }
+}
+

+ 76 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/push/IPush.ets

@@ -0,0 +1,76 @@
+import { Context } from '@kit.AbilityKit';
+
+/**
+ * 推送服务接口
+ * 
+ * 用于 base-core 与 push 模块之间的解耦
+ * push 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IPush {
+  /**
+   * 初始化推送服务
+   * 
+   * @param context Application 上下文
+   * @param appKey 极光推送 AppKey
+   * @param channel 推送渠道(可选,默认为 "developer-default")
+   * @param debugMode 是否开启调试模式
+   */
+  initialize(context: Context, appKey: string, channel?: string, debugMode?: boolean): Promise<void>;
+  
+  /**
+   * 设置别名(用于推送)
+   * 
+   * @param alias 别名(通常是用户ID)
+   */
+  setAlias(alias: string): Promise<void>;
+  
+  /**
+   * 设置标签(用于推送)
+   * 
+   * @param tags 标签列表
+   */
+  setTags(tags: string[]): Promise<void>;
+  
+  /**
+   * 设置消息监听器(自定义消息/透传消息)
+   * 
+   * @param listener 消息接收回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setMessageListener(listener: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 设置通知点击监听器(用户点击通知栏通知时触发)
+   * 
+   * @param listener 通知点击回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setNotificationClickListener(listener?: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 注册推送(开启推送)
+   */
+  register(): Promise<void>;
+  
+  /**
+   * 注销推送(关闭推送)
+   */
+  unregister(): Promise<void>;
+  
+  /**
+   * 获取注册ID(用于标识设备)
+   * 
+   * @returns 设备注册ID,如果未初始化或获取失败返回 null
+   */
+  getRegistrationId(): Promise<string | null>;
+  
+  /**
+   * 检查推送是否已开启
+   * 
+   * @returns true 表示推送已开启,false 表示推送已停止或未初始化
+   */
+  isPushEnabled(): Promise<boolean>;
+}
+

+ 76 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/push/IPushService.ets

@@ -0,0 +1,76 @@
+import { Context } from '@kit.AbilityKit';
+
+/**
+ * 推送服务接口
+ * 
+ * 用于 base-core 与 push 模块之间的解耦
+ * push 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IPushService {
+  /**
+   * 初始化推送服务
+   * 
+   * @param context Application 上下文
+   * @param appKey 极光推送 AppKey
+   * @param channel 推送渠道(可选,默认为 "developer-default")
+   * @param debugMode 是否开启调试模式
+   */
+  initialize(context: Context, appKey: string, channel?: string, debugMode?: boolean): Promise<void>;
+  
+  /**
+   * 设置别名(用于推送)
+   * 
+   * @param alias 别名(通常是用户ID)
+   */
+  setAlias(alias: string): Promise<void>;
+  
+  /**
+   * 设置标签(用于推送)
+   * 
+   * @param tags 标签列表
+   */
+  setTags(tags: string[]): Promise<void>;
+  
+  /**
+   * 设置消息监听器(自定义消息/透传消息)
+   * 
+   * @param listener 消息接收回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setMessageListener(listener: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 设置通知点击监听器(用户点击通知栏通知时触发)
+   * 
+   * @param listener 通知点击回调
+   *                 参数:title, content, extras (Record<string, string>), messageId
+   */
+  setNotificationClickListener(listener?: (title: string, content: string, extras: Record<string, string>, messageId?: string) => void): void;
+  
+  /**
+   * 注册推送(开启推送)
+   */
+  register(): Promise<void>;
+  
+  /**
+   * 注销推送(关闭推送)
+   */
+  unregister(): Promise<void>;
+  
+  /**
+   * 获取注册ID(用于标识设备)
+   * 
+   * @returns 设备注册ID,如果未初始化或获取失败返回 null
+   */
+  getRegistrationId(): Promise<string | null>;
+  
+  /**
+   * 检查推送是否已开启
+   * 
+   * @returns true 表示推送已开启,false 表示推送已停止或未初始化
+   */
+  isPushEnabled(): Promise<boolean>;
+}
+

+ 152 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/share/IShare.ets

@@ -0,0 +1,152 @@
+import { Context } from '@kit.AbilityKit';
+import { Want } from '@kit.AbilityKit';
+import { IShareCallback } from './IShareCallback';
+
+/**
+ * 分享服务接口
+ * 
+ * 用于 base-core 与 share 模块之间的解耦
+ * share 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IShare {
+  /**
+   * 初始化分享服务
+   * 
+   * @param context Application 上下文
+   * @param umengAppKey 友盟 AppKey(可选,如果为空则从资源文件读取)
+   * @param umengChannel 友盟渠道(可选,默认为 "developer-default")
+   * @param weChatAppId 微信 AppID(可选)
+   * @param weChatAppSecret 微信 AppSecret(可选)
+   * @param qqAppId QQ AppID(可选)
+   * @param qqAppKey QQ AppKey(可选)
+   * @param weiboAppKey 微博 AppKey(可选)
+   * @param weiboAppSecret 微博 AppSecret(可选)
+   * @param weiboRedirectUrl 微博回调地址(可选)
+   */
+  initialize(
+    context: Context,
+    umengAppKey?: string,
+    umengChannel?: string,
+    weChatAppId?: string,
+    weChatAppSecret?: string,
+    qqAppId?: string,
+    qqAppKey?: string,
+    weiboAppKey?: string,
+    weiboAppSecret?: string,
+    weiboRedirectUrl?: string
+  ): Promise<void>;
+  
+  /**
+   * 处理分享回调(内部使用)
+   * 
+   * @param want Want 对象(HarmonyOS 的回调方式)
+   */
+  onShareResult(want: Want): void;
+  
+  /**
+   * 统一分享方法(推荐使用)
+   * 
+   * @param context Context 上下文
+   * @param title 分享标题
+   * @param description 分享描述
+   * @param url 分享链接(可选)
+   * @param imageUrl 图片URL(可选)
+   * @param thumbImageUrl 缩略图URL(可选)
+   * @param platform 分享平台(可选,如果为 null 则显示分享弹窗)
+   * @param callback 分享结果回调
+   *                 参数:success (boolean), platform (string?), errorMessage (string?)
+   */
+  share(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    platform?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信
+   */
+  shareToWeChat(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信朋友圈
+   */
+  shareToWeChatMoments(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ
+   */
+  shareToQQ(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ空间
+   */
+  shareToQZone(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微博
+   */
+  shareToWeibo(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 系统分享(调用系统分享菜单)
+   */
+  shareToSystem(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+}
+
+// IShareCallback 接口已分离到 IShareCallback.ets 文件中
+

+ 29 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareCallback.ets

@@ -0,0 +1,29 @@
+/**
+ * 分享回调接口
+ * 
+ * 用于处理分享结果回调
+ */
+export interface IShareCallback {
+  /**
+   * 分享成功回调
+   * 
+   * @param platform 分享平台(如:wechat, qq, weibo)
+   */
+  onSuccess(platform: string): void;
+  
+  /**
+   * 分享失败回调
+   * 
+   * @param platform 分享平台(如:wechat, qq, weibo)
+   * @param errorMessage 错误信息
+   */
+  onError(platform: string, errorMessage: string): void;
+  
+  /**
+   * 分享取消回调
+   * 
+   * @param platform 分享平台(如:wechat, qq, weibo)
+   */
+  onCancel(platform: string): void;
+}
+

+ 166 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/share/IShareService.ets

@@ -0,0 +1,166 @@
+import { Context } from '@kit.AbilityKit';
+import { Want } from '@kit.AbilityKit';
+
+/**
+ * 分享服务接口
+ * 
+ * 用于 base-core 与 share 模块之间的解耦
+ * share 模块需要实现此接口
+ * 
+ * 注意:为了解耦,接口方法使用基本类型,具体类型由实现类处理
+ */
+export interface IShareService {
+  /**
+   * 初始化分享服务
+   * 
+   * @param context Application 上下文
+   * @param umengAppKey 友盟 AppKey(可选,如果为空则从资源文件读取)
+   * @param umengChannel 友盟渠道(可选,默认为 "developer-default")
+   * @param weChatAppId 微信 AppID(可选)
+   * @param weChatAppSecret 微信 AppSecret(可选)
+   * @param qqAppId QQ AppID(可选)
+   * @param qqAppKey QQ AppKey(可选)
+   * @param weiboAppKey 微博 AppKey(可选)
+   * @param weiboAppSecret 微博 AppSecret(可选)
+   * @param weiboRedirectUrl 微博回调地址(可选)
+   */
+  initialize(
+    context: Context,
+    umengAppKey?: string,
+    umengChannel?: string,
+    weChatAppId?: string,
+    weChatAppSecret?: string,
+    qqAppId?: string,
+    qqAppKey?: string,
+    weiboAppKey?: string,
+    weiboAppSecret?: string,
+    weiboRedirectUrl?: string
+  ): Promise<void>;
+  
+  /**
+   * 处理分享回调(内部使用)
+   * 
+   * @param want Want 对象(HarmonyOS 的回调方式)
+   */
+  onShareResult(want: Want): void;
+  
+  /**
+   * 统一分享方法(推荐使用)
+   * 
+   * @param context Context 上下文
+   * @param title 分享标题
+   * @param description 分享描述
+   * @param url 分享链接(可选)
+   * @param imageUrl 图片URL(可选)
+   * @param thumbImageUrl 缩略图URL(可选)
+   * @param platform 分享平台(可选,如果为 null 则显示分享弹窗)
+   * @param callback 分享结果回调
+   *                 参数:success (boolean), platform (string?), errorMessage (string?)
+   */
+  share(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    platform?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信
+   */
+  shareToWeChat(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微信朋友圈
+   */
+  shareToWeChatMoments(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ
+   */
+  shareToQQ(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到QQ空间
+   */
+  shareToQZone(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 分享到微博
+   */
+  shareToWeibo(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+  
+  /**
+   * 系统分享(调用系统分享菜单)
+   */
+  shareToSystem(
+    context: Context,
+    title: string,
+    description: string,
+    url?: string,
+    imageUrl?: string,
+    thumbImageUrl?: string,
+    callback?: (success: boolean, platform?: string, errorMessage?: string) => void
+  ): Promise<void>;
+}
+
+/**
+ * 分享回调接口
+ * 
+ * 用于 base-core 与 share 模块之间的解耦
+ * base-core 中的 WXEntryAbility 等回调 Ability 通过此接口调用 share 模块的实现
+ * 
+ * share 模块需要实现此接口
+ */
+export interface IShareCallback {
+  /**
+   * 处理微信回调
+   * 
+   * @param want Want 对象(HarmonyOS 的回调方式)
+   */
+  onWeChatCallback(want: Want): void;
+}
+

+ 30 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/storage/IStorage.ets

@@ -0,0 +1,30 @@
+/**
+ * 存储服务接口
+ * 统一封装键值存储、文件存储、数据库存储
+ * 
+ * 实现类:StorageImpl(在 base-core 中提供)
+ * 所有模块都可以直接使用 StorageImpl 进行数据存储
+ */
+export interface IStorage {
+  /**
+   * 键值存储
+   */
+  putString(key: string, value: string): Promise<void>;
+  getString(key: string, defaultValue?: string): Promise<string>;
+  putInt(key: string, value: number): Promise<void>;
+  getInt(key: string, defaultValue?: number): Promise<number>;
+  putLong(key: string, value: number): Promise<void>;
+  getLong(key: string, defaultValue?: number): Promise<number>;
+  putBoolean(key: string, value: boolean): Promise<void>;
+  getBoolean(key: string, defaultValue?: boolean): Promise<boolean>;
+  remove(key: string): Promise<void>;
+  clear(): Promise<void>;
+  
+  /**
+   * 文件存储
+   */
+  saveFile(path: string, data: Uint8Array): Promise<boolean>;
+  readFile(path: string): Promise<Uint8Array | null>;
+  deleteFile(path: string): Promise<boolean>;
+}
+

+ 346 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageImpl.ets

@@ -0,0 +1,346 @@
+import dataPreferences from '@ohos.data.preferences';
+import { Context } from '@kit.AbilityKit';
+import { IStorage } from './IStorage';
+import { fileIo } from '@kit.CoreFileKit';
+import { ILog } from '../log/ILog';
+
+/**
+ * 存储服务实现类(基于 HarmonyOS preferences)
+ * 
+ * 统一提供键值存储和文件存储功能
+ * 单例模式,需要在 Application 中初始化
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 在 Application 中初始化
+ * await StorageImpl.init(context);
+ * 
+ * // 使用存储
+ * await StorageImpl.putString("key", "value");
+ * const value = await StorageImpl.getString("key");
+ * ```
+ */
+export class StorageImpl implements IStorage {
+  private static instance: StorageImpl | null = null;
+  private static readonly PREFS_NAME = 'xdz_storage_prefs';
+  private dataPreferences: dataPreferences.Preferences | null = null;
+  private context: Context | null = null;
+  private initialized = false;
+  
+  private constructor() {
+    // 私有构造函数,单例模式
+  }
+  
+  /**
+   * 获取单例实例
+   */
+  static getInstance(): StorageImpl {
+    if (!StorageImpl.instance) {
+      StorageImpl.instance = new StorageImpl();
+    }
+    return StorageImpl.instance;
+  }
+  
+  /**
+   * 初始化存储服务
+   * 
+   * 需要在 Application.onCreate() 中调用
+   * 
+   * @param ctx 应用上下文
+   */
+  static async init(ctx: Context): Promise<void> {
+    try {
+      const instance = StorageImpl.getInstance();
+      instance.context = ctx;
+      instance.dataPreferences = await dataPreferences.getPreferences(ctx, StorageImpl.PREFS_NAME);
+      instance.initialized = true;
+    } catch (err) {
+      ILog.e('StorageImpl', '初始化失败', err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  /**
+   * 检查是否已初始化
+   */
+  static isInitialized(): boolean {
+    return StorageImpl.getInstance().initialized;
+  }
+  
+  // ========== 键值存储 ==========
+  
+  async putString(key: string, value: string): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush,确保数据立即持久化
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putString操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getString(key: string, defaultValue: string = ''): Promise<string> {
+    try {
+      if (!this.dataPreferences) {
+        ILog.w('StorageImpl', `getString: dataPreferences 未初始化,key=${key}`);
+        return defaultValue;
+      }
+      // ✅ 修复:不使用 defaultValue,让 get() 返回实际值或 undefined
+      const value = await this.dataPreferences.get(key, undefined);
+      
+      // ✅ 修复:明确处理各种情况
+      if (value === undefined || value === null) {
+        return defaultValue;
+      }
+      
+      // ✅ 修复:确保返回字符串类型
+      if (typeof value === 'string') {
+        return value;
+      }
+      
+      // ✅ 修复:如果不是字符串,转换为字符串
+      return String(value);
+    } catch (err) {
+      ILog.e('StorageImpl', `getString操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async putInt(key: string, value: number): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putInt操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getInt(key: string, defaultValue: number = 0): Promise<number> {
+    try {
+      if (!this.dataPreferences) {
+        return defaultValue;
+      }
+      const value = await this.dataPreferences.get(key, defaultValue);
+      return typeof value === 'number' ? value : defaultValue;
+    } catch (err) {
+      ILog.e('StorageImpl', 'getInt操作失败', err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async putLong(key: string, value: number): Promise<void> {
+    try {
+      // HarmonyOS preferences 使用 number 类型,可以存储 Long 值
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putLong操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getLong(key: string, defaultValue: number = 0): Promise<number> {
+    try {
+      if (!this.dataPreferences) {
+        return defaultValue;
+      }
+      const value = await this.dataPreferences.get(key, defaultValue);
+      return typeof value === 'number' ? value : defaultValue;
+    } catch (err) {
+      ILog.e('StorageImpl', 'getLong操作失败', err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async putBoolean(key: string, value: boolean): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        throw new Error('StorageImpl not initialized. Call StorageImpl.init() first.');
+      }
+      // ✅ 修复:put 后立即 flush
+      await this.dataPreferences.put(key, value);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `putBoolean操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+      if (err instanceof Error) {
+      throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
+    try {
+      if (!this.dataPreferences) {
+        return defaultValue;
+      }
+      const value = await this.dataPreferences.get(key, defaultValue);
+      return typeof value === 'boolean' ? value : defaultValue;
+    } catch (err) {
+      ILog.e('StorageImpl', 'getBoolean操作失败', err instanceof Error ? err : new Error(String(err)));
+      return defaultValue;
+    }
+  }
+  
+  async remove(key: string): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        return;
+      }
+      // ✅ 修复:delete 后立即 flush
+      await this.dataPreferences.delete(key);
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', `remove操作失败,key=${key}`, err instanceof Error ? err : new Error(String(err)));
+    }
+  }
+  
+  async clear(): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        return;
+      }
+      await this.dataPreferences.clear();
+      // clear 操作后可以调用 flush 确保立即持久化
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', 'clear操作失败', err instanceof Error ? err : new Error(String(err)));
+    }
+  }
+  
+  /**
+   * 手动刷新数据到磁盘(可选方法)
+   * 
+   * 在批量操作后可以调用此方法确保数据立即持久化
+   */
+  async flush(): Promise<void> {
+    try {
+      if (!this.dataPreferences) {
+        ILog.w('StorageImpl', 'flush: dataPreferences 未初始化');
+        return;
+      }
+      // ✅ 修复:flush 必须等待完成,如果失败要抛出错误
+      await this.dataPreferences.flush();
+    } catch (err) {
+      ILog.e('StorageImpl', 'flush操作失败', err instanceof Error ? err : new Error(String(err)));
+      // ✅ 修复:抛出错误,让调用方知道失败(ArkTS 要求必须是 Error 类型)
+      if (err instanceof Error) {
+        throw err;
+      } else {
+        throw new Error(String(err));
+      }
+    }
+  }
+  
+  // ========== 文件存储 ==========
+  
+  async saveFile(path: string, data: Uint8Array): Promise<boolean> {
+    try {
+      const ctx = this.context;
+      if (!ctx) {
+        return false;
+      }
+      
+      const filesDir = ctx.filesDir;
+      const filePath = `${filesDir}/${path}`;
+      
+      // 确保目录存在
+      const dirPath = filePath.substring(0, filePath.lastIndexOf('/'));
+      await fileIo.mkdir(dirPath, true);
+      
+      // 写入文件
+      const file = await fileIo.open(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY);
+      await fileIo.write(file.fd, data.buffer);
+      await fileIo.close(file.fd);
+      
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+  
+  async readFile(path: string): Promise<Uint8Array | null> {
+    try {
+      const ctx = this.context;
+      if (!ctx) {
+        return null;
+      }
+      
+      const filePath = `${ctx.filesDir}/${path}`;
+      
+      // 检查文件是否存在
+      const stat = await fileIo.stat(filePath);
+      if (!stat.isFile()) {
+        return null;
+      }
+      
+      // 读取文件
+      const file = await fileIo.open(filePath, fileIo.OpenMode.READ_ONLY);
+      const statInfo = await fileIo.stat(filePath);
+      const buffer = new ArrayBuffer(statInfo.size);
+      await fileIo.read(file.fd, buffer);
+      await fileIo.close(file.fd);
+      
+      return new Uint8Array(buffer);
+    } catch (e) {
+      return null;
+    }
+  }
+  
+  async deleteFile(path: string): Promise<boolean> {
+    try {
+      const ctx = this.context;
+      if (!ctx) {
+        return false;
+      }
+      
+      const filePath = `${ctx.filesDir}/${path}`;
+      
+      // 检查文件是否存在
+      const stat = await fileIo.stat(filePath);
+      if (!stat.isFile()) {
+        return false;
+      }
+      
+      // 删除文件
+      await fileIo.unlink(filePath);
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+}
+
+// 导出单例实例,方便使用
+export const storageImpl = StorageImpl.getInstance();
+

+ 16 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/storage/StorageKeys.ets

@@ -0,0 +1,16 @@
+/**
+ * 存储键常量定义
+ * 
+ * 统一管理所有存储键,避免硬编码字符串
+ */
+export class StorageKeys {
+  // Token 相关
+  static readonly TOKEN_ACCESS = 'token_access';
+  static readonly TOKEN_REFRESH = 'token_refresh';
+  static readonly TOKEN_USER_ID = 'token_user_id';
+  
+  // 应用配置相关
+  static readonly APP_SERVER_URL = 'app_server_url';
+  static readonly APP_SOCKET_URL = 'app_socket_url';
+  static readonly APP_IS_LOGIN = 'app_is_login';
+}

File diff suppressed because it is too large
+ 1170 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/util/IUtil.ets


+ 201 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/core/util/JWTUtil.ets

@@ -0,0 +1,201 @@
+/**
+ * JWT Token 工具类
+ * 
+ * 提供 JWT Token 解析和验证功能
+ * 参考 iOS 和 Android 实现
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 检查 Token 是否有效(未过期)
+ * const isValid = JWTUtil.isTokenValid(token);
+ * 
+ * // 获取 Token 过期时间
+ * const expiresAt = JWTUtil.getExpiresAt(token);
+ * ```
+ */
+
+/**
+ * JWT Payload 接口
+ * 
+ * 定义 JWT Token payload 的标准字段
+ * 注意:ArkTS 不支持索引签名和 unknown 类型,因此移除了其他字段的定义
+ */
+interface JwtPayload {
+  exp?: number;  // 过期时间(Unix时间戳,单位:秒)
+  iat?: number;  // 签发时间
+  userId?: string;  // 用户ID
+}
+
+/**
+ * JWT Token 工具类
+ * 
+ * 提供 JWT Token 解析和验证功能
+ */
+export class JWTUtil {
+  /**
+   * Base64URL 解码
+   * 
+   * JWT 使用 Base64URL 编码,需要将 URL 安全的字符转换回标准 Base64
+   * - 将 '-' 替换为 '+'
+   * - 将 '_' 替换为 '/'
+   * - 添加必要的 padding
+   * 
+   * @param base64Url Base64URL 编码的字符串
+   * @returns 解码后的 Uint8Array,如果解码失败返回 null
+   */
+  private static base64UrlDecode(base64Url: string): Uint8Array | null {
+    try {
+      // Base64URL 转 Base64
+      let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
+      
+      // 添加 padding
+      const padLength = (4 - base64.length % 4) % 4;
+      base64 = base64 + '='.repeat(padLength);
+      
+      // HarmonyOS 使用手动实现的 Base64 解码
+      return JWTUtil.base64Decode(base64);
+    } catch (e) {
+      return null;
+    }
+  }
+  
+  /**
+   * Base64 解码(手动实现)
+   * 
+   * @param base64 Base64 编码的字符串
+   * @returns 解码后的 Uint8Array
+   */
+  private static base64Decode(base64: string): Uint8Array {
+    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+    let output = '';
+    
+    base64 = base64.replace(/[^A-Za-z0-9\+\/\=]/g, '');
+    
+    for (let i = 0; i < base64.length; i += 4) {
+      const enc1 = chars.indexOf(base64.charAt(i));
+      const enc2 = chars.indexOf(base64.charAt(i + 1));
+      const enc3 = chars.indexOf(base64.charAt(i + 2));
+      const enc4 = chars.indexOf(base64.charAt(i + 3));
+      
+      const chr1 = (enc1 << 2) | (enc2 >> 4);
+      const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+      const chr3 = ((enc3 & 3) << 6) | enc4;
+      
+      output += String.fromCharCode(chr1);
+      
+      if (enc3 !== 64) {
+        output += String.fromCharCode(chr2);
+      }
+      if (enc4 !== 64) {
+        output += String.fromCharCode(chr3);
+      }
+    }
+    
+    const bytes = new Uint8Array(output.length);
+    for (let i = 0; i < output.length; i++) {
+      bytes[i] = output.charCodeAt(i);
+    }
+    return bytes;
+  }
+  
+  /**
+   * 解析 JWT Token 并检查是否过期
+   * 
+   * @param token JWT Token
+   * @returns true 如果 Token 未过期,false 如果过期或无法解析
+   */
+  static isTokenValid(token: string): boolean {
+    if (!token || token === '') {
+      return false;
+    }
+    
+    // JWT 格式:header.payload.signature
+    const parts = token.split('.');
+    if (parts.length !== 3) {
+      return false;
+    }
+    
+    // 解析 payload(第二部分)
+    const payload = parts[1];
+    
+    // Base64URL 解码
+    const payloadData = JWTUtil.base64UrlDecode(payload);
+    if (!payloadData) {
+      return false;
+    }
+    
+    // 转换为 JSON 字符串(手动实现 UTF-8 解码)
+    const payloadString = JWTUtil.uint8ArrayToString(payloadData);
+    
+    try {
+      const payloadJson: JwtPayload = JSON.parse(payloadString) as JwtPayload;
+      const exp = payloadJson.exp;
+      
+      if (typeof exp !== 'number') {
+        return false;
+      }
+      
+      // 检查是否过期(exp 是 Unix 时间戳,单位:秒)
+      const currentTime = Math.floor(Date.now() / 1000);
+      return exp > currentTime;
+    } catch (e) {
+      return false;
+    }
+  }
+  
+  /**
+   * 解析 JWT Token 并获取过期时间
+   * 
+   * @param token JWT Token
+   * @returns 过期时间(Unix 时间戳,单位:秒),如果无法解析返回 null
+   */
+  static getExpiresAt(token: string): number | null {
+    if (!token || token === '') {
+      return null;
+    }
+    
+    // JWT 格式:header.payload.signature
+    const parts = token.split('.');
+    if (parts.length !== 3) {
+      return null;
+    }
+    
+    // 解析 payload(第二部分)
+    const payload = parts[1];
+    
+    // Base64URL 解码
+    const payloadData = JWTUtil.base64UrlDecode(payload);
+    if (!payloadData) {
+      return null;
+    }
+    
+    // 转换为 JSON 字符串(手动实现 UTF-8 解码)
+    const payloadString = JWTUtil.uint8ArrayToString(payloadData);
+    
+    try {
+      const payloadJson: JwtPayload = JSON.parse(payloadString) as JwtPayload;
+      const exp = payloadJson.exp;
+      
+      if (typeof exp === 'number') {
+        return exp;
+      }
+      return null;
+    } catch (e) {
+      return null;
+    }
+  }
+  
+  /**
+   * 将 Uint8Array 转换为 UTF-8 字符串(手动实现)
+   * 
+   * @param bytes Uint8Array
+   * @returns UTF-8 字符串
+   */
+  private static uint8ArrayToString(bytes: Uint8Array): string {
+    let result = '';
+    for (let i = 0; i < bytes.length; i++) {
+      result += String.fromCharCode(bytes[i]);
+    }
+    return result;
+  }
+}

+ 36 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/ets/index.ets

@@ -0,0 +1,36 @@
+/**
+ * base-core 模块导出入口
+ * 
+ * 统一导出所有核心接口和实现
+ */
+
+// 日志模块
+export { ILog, ILogger, LogLevel } from './core/log/ILog';
+export { HilogLogger } from './core/log/impl/HilogLogger';
+export { NoOpLogger } from './core/log/impl/NoOpLogger';
+export { FloatingLogButton } from './core/log/FloatingLogButton';
+
+// 存储模块
+export { IStorage } from './core/storage/IStorage';
+export { StorageImpl, storageImpl } from './core/storage/StorageImpl';
+export { StorageKeys } from './core/storage/StorageKeys';
+
+// 网络模块
+export { NetworkManager, networkManager } from './core/network/NetworkManager';
+
+// 推送模块
+export { IPush } from './core/push/IPush';
+
+// 分享模块
+export { IShare } from './core/share/IShare';
+export { IShareCallback } from './core/share/IShareCallback';
+
+// 工具模块
+export { JWTUtil } from './core/util/JWTUtil';
+export { IUtil, UtilImpl, utilImpl } from './core/util/IUtil';
+
+// 权限模块
+export { PermissionHelper } from './core/permission/PermissionHelper';
+
+// 统一异常模型(3.1)
+export { AppError, ErrorType, AppErrorRaw } from './core/error/AppError';

+ 13 - 0
base-common/oh_modules/@xdz/capability-socketio/oh_modules/@xdz/base-core/src/main/module.json5

@@ -0,0 +1,13 @@
+{
+  "module": {
+    "name": "base_core",
+    "type": "har",
+    "description": "基础设施层 - 定义接口和基础实现",
+    "mainElement": "",
+    "deviceTypes": [
+      "phone",
+      "tablet"
+    ]
+  }
+}
+

+ 38 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/index.ets

@@ -0,0 +1,38 @@
+/**
+ * capability-socketio 模块导出入口
+ * 
+ * 统一导出所有 SocketIO 相关接口和类
+ * 支持独立打包为 SDK
+ */
+
+// 模型
+export { SocketIOEvent } from './socketio/model/SocketIOEvent';
+export { SocketIOResponse } from './socketio/model/SocketIOResponse';
+
+// API 接口
+export { SocketIOService } from './socketio/api/SocketIOService';
+
+// 实现类(通常不直接使用,通过 Factory 获取)
+export { SocketIOServiceImpl } from './socketio/impl/SocketIOServiceImpl';
+
+// 工厂类
+export { SocketIOServiceFactory } from './socketio/factory/SocketIOServiceFactory';
+export { SocketIORepositoryFactory } from './socketio/factory/SocketIORepositoryFactory';
+
+// Repository
+export { SocketIORepository } from './socketio/repository/SocketIORepository';
+
+// Manager(已迁移到 base-common 模块)
+// export { SocketIOManager } from './socketio/manager/SocketIOManager';
+
+// Protocol(内部使用,但也可以导出供外部使用)
+export { SocketIOProtocol } from './socketio/protocol/SocketIOProtocol';
+
+// Transport(内部使用,但也可以导出供外部使用)
+export { Transport } from './socketio/transport/Transport';
+export { WebSocketTransport } from './socketio/transport/WebSocketTransport';
+export { PollingTransport } from './socketio/transport/PollingTransport';
+
+// StateFlow(内部使用,但也可以导出供外部使用)
+export { StateFlow } from './socketio/repository/StateFlow';
+

+ 104 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/api/SocketIOService.ets

@@ -0,0 +1,104 @@
+import { SocketIOResponse } from '../model/SocketIOResponse';
+
+/**
+ * SocketIO服务接口
+ * 
+ * 提供SocketIO实时通信能力(WebSocket长连接 + HTTP长轮询降级)
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 获取实例
+ * const socketService = SocketIOServiceFactory.getInstance();
+ * 
+ * // 连接服务器(默认命名空间)
+ * await socketService.connect("http://server:9090", "token");
+ * 
+ * // 连接命名空间
+ * await socketService.connect("http://server:9090", "token", "/namespace");
+ * 
+ * // 订阅事件
+ * socketService.on("event", (response) => { ... });
+ * 
+ * // 发送事件
+ * socketService.emit("event", data);
+ * 
+ * // 加入房间
+ * socketService.joinRoom("room_name");
+ * 
+ * // 离开房间
+ * socketService.leaveRoom("room_name");
+ * ```
+ */
+export interface SocketIOService {
+  /**
+   * 连接服务器
+   * 
+   * @param serverUrl 服务器地址(如 "http://localhost:9090")
+   * @param token JWT Token(用于身份验证)
+   * @param namespace 命名空间(可选,默认为 "/")
+   */
+  connect(serverUrl: string, token: string, namespace?: string): Promise<void>;
+  
+  /**
+   * 断开连接
+   */
+  disconnect(): Promise<void>;
+  
+  /**
+   * 是否已连接
+   */
+  isConnected(): boolean;
+  
+  /**
+   * 订阅事件
+   * 
+   * @param event 事件名称
+   * @param callback 回调函数,接收SocketIOResponse
+   */
+  on(event: string, callback: (response: SocketIOResponse) => void): void;
+  
+  /**
+   * 取消订阅事件
+   * 
+   * @param event 事件名称
+   */
+  off(event: string): void;
+  
+  /**
+   * 发送事件到服务器
+   * 
+   * @param event 事件名称
+   * @param data 数据(会被转换为JSON)
+   * @param ackCallback ACK 回调(可选)
+   */
+  emit(event: string, data: object, ackCallback?: (response: object) => void): void;
+  
+  /**
+   * 发送二进制事件到服务器
+   * 
+   * @param event 事件名称
+   * @param data 二进制数据(ArrayBuffer 或 Uint8Array)
+   * @param ackCallback ACK 回调(可选)
+   */
+  emitBinary(event: string, data: ArrayBuffer | Uint8Array, ackCallback?: (response: object) => void): void;
+  
+  /**
+   * 加入房间
+   * 
+   * @param room 房间名称
+   */
+  joinRoom(room: string): void;
+  
+  /**
+   * 离开房间
+   * 
+   * @param room 房间名称
+   */
+  leaveRoom(room: string): void;
+  
+  /**
+   * 获取当前命名空间
+   */
+  getNamespace(): string;
+}
+

+ 45 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/factory/SocketIORepositoryFactory.ets

@@ -0,0 +1,45 @@
+import { SocketIORepository } from '../repository/SocketIORepository';
+
+/**
+ * SocketIO Repository 工厂类
+ * 
+ * 提供统一的获取 SocketIORepository 实例的方式
+ * Repository 是全局单例,多个界面共享同一个实例
+ * 
+ * 使用示例:
+ * ```typescript
+ * // 获取 Repository 实例(单例)
+ * const repository = SocketIORepositoryFactory.getInstance();
+ * 
+ * // 连接服务器(需要传入 serverUrl 和 token)
+ * await repository.connect(serverUrl, token);
+ * 
+ * // 观察连接状态
+ * repository.connectionState.observe((isConnected) => {
+ *   // 处理连接状态变化
+ * });
+ * ```
+ */
+export class SocketIORepositoryFactory {
+  private static instance: SocketIORepository | null = null;
+  
+  /**
+   * 获取 SocketIORepository 实例(单例)
+   * 
+   * @return SocketIORepository 实例(单例)
+   */
+  static getInstance(): SocketIORepository {
+    if (!SocketIORepositoryFactory.instance) {
+      SocketIORepositoryFactory.instance = new SocketIORepository();
+    }
+    return SocketIORepositoryFactory.instance;
+  }
+  
+  /**
+   * 销毁单例(用于测试或需要重新初始化时)
+   */
+  static destroyInstance(): void {
+    SocketIORepositoryFactory.instance = null;
+  }
+}
+

+ 37 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/factory/SocketIOServiceFactory.ets

@@ -0,0 +1,37 @@
+import { SocketIOService } from '../api/SocketIOService';
+import { SocketIOServiceImpl } from '../impl/SocketIOServiceImpl';
+
+/**
+ * SocketIO服务工厂类
+ * 
+ * 提供统一的获取SocketIO服务实例的方式
+ * SocketIO连接是全局单例,多个界面共享同一个连接
+ * 
+ * 使用示例:
+ * ```typescript
+ * // 获取服务实例(单例)
+ * const socketService = SocketIOServiceFactory.getInstance();
+ * 
+ * // 连接服务器
+ * await socketService.connect("http://server:9090", "your_token");
+ * 
+ * // 订阅事件
+ * socketService.on("vehicle_status", (response) => {
+ *   // 处理接收到的数据
+ * });
+ * 
+ * // 发送事件
+ * socketService.emit("vehicle_control", controlData);
+ * ```
+ */
+export class SocketIOServiceFactory {
+  /**
+   * 获取SocketIO服务实例(单例)
+   * 
+   * @return SocketIOService实例(单例)
+   */
+  static getInstance(): SocketIOService {
+    return SocketIOServiceImpl.getInstance();
+  }
+}
+

+ 588 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/impl/SocketIOServiceImpl.ets

@@ -0,0 +1,588 @@
+import { ILog } from '@xdz/base-core';
+import { SocketIOService } from '../api/SocketIOService';
+import { SocketIOResponse } from '../model/SocketIOResponse';
+import { SocketIOEvent } from '../model/SocketIOEvent';
+import { SocketIOProtocol, ParsedMessage } from '../protocol/SocketIOProtocol';
+import { Transport } from '../transport/Transport';
+import { WebSocketTransport } from '../transport/WebSocketTransport';
+import { PollingTransport } from '../transport/PollingTransport';
+
+const TAG = "SocketIOService";
+
+/**
+ * 空对象接口
+ */
+interface EmptyObject {
+}
+
+/**
+ * SocketIO服务实现类(单例模式)
+ * 
+ * 基于 HarmonyOS WebSocket API 和 HTTP API 实现完整的 Socket.IO 协议
+ * 支持自动降级连接(WebSocket -> HTTP 长轮询)
+ * Socket.IO连接是全局唯一的,多个界面需要共享同一个连接
+ * 
+ * 注意:请通过 SocketIOServiceFactory.getInstance() 获取实例,不要直接调用此类的 getInstance()
+ */
+export class SocketIOServiceImpl implements SocketIOService {
+  private static instance: SocketIOServiceImpl | null = null;
+  private transport: Transport | null = null;
+  private serverUrl: string = '';
+  private token: string = '';
+  private namespace: string = '/'; // 默认命名空间
+  // 存储事件监听器
+  private eventListeners: Map<string, Array<(response: SocketIOResponse) => void>> = new Map();
+  private connected: boolean = false;
+  private pingInterval: number = 25000; // 默认 25 秒
+  private pingTimeout: number = 20000; // 默认 20 秒
+  private pingTimer: number | null = null;
+  private pongTimer: number | null = null;
+  private sid: string | null = null; // Session ID
+  private currentTransport: 'websocket' | 'polling' = 'websocket';
+  private rooms: Set<string> = new Set(); // 已加入的房间
+  private ackCallbacks: Map<number, (response: object) => void> = new Map(); // ACK 回调
+  private nextAckId: number = 0; // 下一个 ACK ID
+  private binaryDataQueue: Map<number, ArrayBuffer | Uint8Array> = new Map(); // 二进制数据队列
+
+  private constructor() {
+    // 私有构造函数,单例模式
+  }
+
+  /**
+   * 获取SocketIO服务单例(内部方法)
+   * 
+   * 注意:请通过 SocketIOServiceFactory.getInstance() 获取,保持API一致性
+   */
+  static getInstance(): SocketIOServiceImpl {
+    if (!SocketIOServiceImpl.instance) {
+      SocketIOServiceImpl.instance = new SocketIOServiceImpl();
+    }
+    return SocketIOServiceImpl.instance;
+  }
+
+  /**
+   * 销毁单例(用于测试或需要重新初始化时)
+   */
+  static destroyInstance(): void {
+    if (SocketIOServiceImpl.instance) {
+      SocketIOServiceImpl.instance.stopPingPong();
+      SocketIOServiceImpl.instance.disconnect();
+      SocketIOServiceImpl.instance = null;
+    }
+  }
+
+  async connect(serverUrl: string, token: string, namespace: string = '/'): Promise<void> {
+    try {
+      ILog.d(TAG, "=== SocketIO连接开始 ===");
+      ILog.d(TAG, `服务器地址: ${serverUrl}`);
+      ILog.d(TAG, `命名空间: ${namespace}`);
+      ILog.d(TAG, `Token长度: ${token.length}`);
+
+      // 如果已连接,先断开
+      if (this.connected && this.transport) {
+        ILog.d(TAG, "检测到已有连接,先断开");
+        await this.disconnect();
+      }
+
+      this.serverUrl = serverUrl;
+      this.token = token;
+      this.namespace = namespace;
+
+      // 尝试连接:先 WebSocket,失败则降级到 HTTP 长轮询
+      await this.connectWithFallback();
+    } catch (e) {
+      ILog.e(TAG, "❌ SocketIO连接异常", e as Error);
+      this.connected = false;
+      if (e instanceof Error) {
+        throw e;
+      } else {
+        throw new Error(String(e));
+      }
+    }
+  }
+
+  /**
+   * 连接并自动降级
+   * 
+   * 1. 先尝试 WebSocket 连接
+   * 2. 如果失败,降级到 HTTP 长轮询
+   */
+  private async connectWithFallback(): Promise<void> {
+      // 1. 先尝试 WebSocket
+      try {
+        ILog.d(TAG, "尝试 WebSocket 连接...");
+        this.transport = new WebSocketTransport();
+        this.setupTransportCallbacks();
+        const wsUrl = SocketIOProtocol.buildHandshakeUrl(this.serverUrl, this.token, 'websocket', this.namespace);
+        await this.transport.connect(wsUrl, this.token, this.namespace);
+        this.currentTransport = 'websocket';
+        ILog.d(TAG, "✅ WebSocket 连接成功");
+        return;
+      } catch (e) {
+        ILog.w(TAG, `WebSocket 连接失败,降级到 HTTP 长轮询: ${(e as Error).message}`);
+      }
+
+      // 2. 降级到 HTTP 长轮询
+      try {
+        ILog.d(TAG, "尝试 HTTP 长轮询连接...");
+        const pollingTransport = new PollingTransport();
+        this.transport = pollingTransport;
+        this.setupTransportCallbacks();
+        await pollingTransport.connect(this.serverUrl, this.token, this.namespace);
+        this.currentTransport = 'polling';
+        ILog.d(TAG, "✅ HTTP 长轮询连接成功");
+      } catch (e) {
+        ILog.e(TAG, "HTTP 长轮询连接也失败", e as Error);
+        if (e instanceof Error) {
+          throw e;
+        } else {
+          throw new Error(String(e));
+        }
+      }
+  }
+
+  /**
+   * 设置传输层回调
+   */
+  private setupTransportCallbacks(): void {
+    if (!this.transport) {
+      return;
+    }
+
+    this.transport.onOpen(() => {
+      ILog.d(TAG, "传输层连接成功,等待 Socket.IO 握手");
+    });
+
+    this.transport.onMessage((message: string) => {
+      try {
+        ILog.d(TAG, `收到消息: ${message}`);
+        
+        // 解析 Socket.IO 协议消息
+        const parsed = SocketIOProtocol.parseMessage(message);
+        if (!parsed) {
+          ILog.w(TAG, `无法解析消息: ${message}`);
+          return;
+        }
+
+        this.handleProtocolMessage(parsed);
+      } catch (e) {
+        ILog.e(TAG, `Error handling message: ${JSON.stringify(e)}`, e as Error);
+      }
+    });
+
+    this.transport.onClose(() => {
+      ILog.d(TAG, "传输层连接断开");
+      this.stopPingPong();
+      this.connected = false;
+      this.sid = null;
+      this.triggerEvent(SocketIOEvent.DISCONNECT, "{}");
+    });
+
+    this.transport.onError((err: Error) => {
+      ILog.e(TAG, `传输层错误: ${err.message}`, err);
+      this.stopPingPong();
+      this.connected = false;
+      this.triggerEvent(SocketIOEvent.CONNECT_ERROR, err.message);
+    });
+  }
+
+  /**
+   * 处理 Socket.IO 协议消息
+   */
+  private handleProtocolMessage(parsed: ParsedMessage): void {
+    // 确保 type 是 number 类型,避免字面量类型推断
+    const packetTypeValue: number = parsed.type;
+    const type: number = packetTypeValue;
+    const data = parsed.data;
+    const event = parsed.event;
+    const id = parsed.id;
+
+    // 处理连接消息(握手响应)
+    // 使用 Number() 确保常量也是 number 类型
+    if (type === Number(SocketIOProtocol.PACKET_CONNECT)) {
+      if (data) {
+        const connectData = data as Record<string, object>;
+        if (connectData.sid) {
+          this.sid = String(connectData.sid);
+          const pingIntervalValue = connectData.pingInterval;
+          const pingTimeoutValue = connectData.pingTimeout;
+          this.pingInterval = pingIntervalValue ? Number(pingIntervalValue) : 25000;
+          this.pingTimeout = pingTimeoutValue ? Number(pingTimeoutValue) : 20000;
+          ILog.d(TAG, `Socket.IO 握手成功,SID: ${this.sid}, pingInterval: ${this.pingInterval}, pingTimeout: ${this.pingTimeout}`);
+          
+          this.connected = true;
+          this.startPingPong();
+          
+          // 触发已注册的 "connect" 事件回调
+          this.triggerEvent(SocketIOEvent.CONNECT, JSON.stringify(data));
+        }
+      }
+      return;
+    }
+
+    // 处理断开连接消息
+    if (type === Number(SocketIOProtocol.PACKET_DISCONNECT)) {
+      this.stopPingPong();
+      this.connected = false;
+      this.triggerEvent(SocketIOEvent.DISCONNECT, "{}");
+      return;
+    }
+
+    // 处理错误消息
+    if (type === Number(SocketIOProtocol.PACKET_ERROR)) {
+      let errorMsg: string;
+      if (data) {
+        const errorData = data as Record<string, object>;
+        const messageValue = errorData.message;
+        errorMsg = messageValue ? String(messageValue) : JSON.stringify(data);
+      } else {
+        errorMsg = "Unknown error";
+      }
+      ILog.e(TAG, `Socket.IO 错误: ${errorMsg}`);
+      this.triggerEvent(SocketIOEvent.CONNECT_ERROR, errorMsg);
+      return;
+    }
+
+    // 处理 ping 消息
+    if (type === Number(SocketIOProtocol.PACKET_PING)) {
+      ILog.d(TAG, "收到 ping,发送 pong");
+      this.sendPong();
+      return;
+    }
+
+    // 处理 pong 消息
+    if (type === Number(SocketIOProtocol.PACKET_PONG)) {
+      ILog.d(TAG, "收到 pong");
+      // 清除 pong 超时定时器
+      if (this.pongTimer !== null) {
+        clearTimeout(this.pongTimer);
+        this.pongTimer = null;
+      }
+      return;
+    }
+
+    // 处理 ACK 消息
+    if (type === Number(SocketIOProtocol.PACKET_ACK) && id !== undefined) {
+      const callback = this.ackCallbacks.get(id);
+      if (callback) {
+        // 使用空对象作为默认值
+        const emptyObj: EmptyObject = {} as EmptyObject;
+        const ackData: object = data || (emptyObj as object);
+        callback(ackData);
+        this.ackCallbacks.delete(id);
+      }
+      return;
+    }
+
+    // 处理二进制事件
+    if (type === Number(SocketIOProtocol.PACKET_BINARY_EVENT) && event) {
+      // 二进制事件需要先接收占位符消息,然后接收二进制数据
+      // 这里简化处理,假设二进制数据已经包含在消息中
+      const eventData = typeof data === 'string' ? data : JSON.stringify(data || {});
+      this.triggerEvent(event, eventData);
+      return;
+    }
+
+    // 处理事件消息
+    if (type === Number(SocketIOProtocol.PACKET_EVENT) && event) {
+      const eventData = typeof data === 'string' ? data : JSON.stringify(data || {});
+      this.triggerEvent(event, eventData);
+      return;
+    }
+  }
+
+  /**
+   * 触发事件回调
+   */
+  private triggerEvent(event: string, data: string): void {
+    const callbacks = this.eventListeners.get(event) || [];
+    const response = new SocketIOResponse(event, data, Date.now());
+    callbacks.forEach(callback => {
+      try {
+        callback(response);
+      } catch (e) {
+        ILog.e(TAG, `Error in event callback for ${event}: ${JSON.stringify(e)}`, e as Error);
+      }
+    });
+  }
+
+  /**
+   * 启动 ping/pong 机制
+   */
+  private startPingPong(): void {
+    this.stopPingPong();
+    
+    // 定期发送 ping(仅 WebSocket 需要,HTTP 长轮询不需要)
+    if (this.currentTransport === 'websocket') {
+      this.pingTimer = setInterval(() => {
+        if (this.connected && this.transport) {
+          this.sendPing();
+        }
+      }, this.pingInterval) as number;
+      
+      ILog.d(TAG, `Ping/Pong 机制已启动,间隔: ${this.pingInterval}ms`);
+    }
+  }
+
+  /**
+   * 停止 ping/pong 机制
+   */
+  private stopPingPong(): void {
+    if (this.pingTimer !== null) {
+      clearInterval(this.pingTimer);
+      this.pingTimer = null;
+    }
+    if (this.pongTimer !== null) {
+      clearTimeout(this.pongTimer);
+      this.pongTimer = null;
+    }
+  }
+
+  /**
+   * 发送 ping 消息
+   */
+  private sendPing(): void {
+    if (!this.transport || !this.connected) {
+      return;
+    }
+
+    try {
+      const pingMessage = SocketIOProtocol.buildMessage(SocketIOProtocol.PACKET_PING);
+      this.transport.send(pingMessage);
+      ILog.d(TAG, "发送 ping");
+
+      // 设置 pong 超时定时器
+      this.pongTimer = setTimeout(() => {
+        ILog.w(TAG, "Pong 超时,连接可能已断开");
+        this.connected = false;
+        this.triggerEvent(SocketIOEvent.CONNECT_ERROR, "Pong timeout");
+      }, this.pingTimeout) as number;
+    } catch (e) {
+      ILog.e(TAG, "发送 ping 失败", e as Error);
+    }
+  }
+
+  /**
+   * 发送 pong 消息
+   */
+  private sendPong(): void {
+    if (!this.transport || !this.connected) {
+      return;
+    }
+
+    try {
+      const pongMessage = SocketIOProtocol.buildMessage(SocketIOProtocol.PACKET_PONG);
+      this.transport.send(pongMessage);
+      ILog.d(TAG, "发送 pong");
+    } catch (e) {
+      ILog.e(TAG, "发送 pong 失败", e as Error);
+    }
+  }
+
+  async disconnect(): Promise<void> {
+    this.stopPingPong();
+    
+    if (this.transport) {
+      try {
+        // 发送断开连接消息
+        const disconnectMessage = SocketIOProtocol.buildMessage(SocketIOProtocol.PACKET_DISCONNECT);
+        this.transport.send(disconnectMessage);
+        
+        await this.transport.disconnect();
+      } catch (e) {
+        ILog.e(TAG, `Error disconnecting transport: ${JSON.stringify(e)}`, e as Error);
+      }
+      this.transport = null;
+    }
+    this.connected = false;
+    this.sid = null;
+    this.rooms.clear();
+    this.ackCallbacks.clear();
+    this.binaryDataQueue.clear();
+    ILog.d(TAG, "Disconnected from SocketIO server");
+  }
+
+  isConnected(): boolean {
+    return this.connected && this.transport !== null && this.transport.isConnected();
+  }
+
+  on(event: string, callback: (response: SocketIOResponse) => void): void {
+    // 保存事件监听器
+    if (!this.eventListeners.has(event)) {
+      this.eventListeners.set(event, []);
+    }
+    this.eventListeners.get(event)!.push(callback);
+    ILog.d(TAG, `Event listener registered for: ${event}`);
+  }
+
+  off(event: string): void {
+    this.eventListeners.delete(event);
+    ILog.d(TAG, `Event listener removed for: ${event}`);
+  }
+
+  emit(event: string, data: object, ackCallback?: (response: object) => void): void {
+    if (!this.isConnected() || !this.transport) {
+      ILog.w(TAG, `Cannot emit event ${event}: not connected`);
+      return;
+    }
+
+    try {
+      let ackId: number | undefined = undefined;
+      if (ackCallback) {
+        ackId = this.nextAckId++;
+        this.ackCallbacks.set(ackId, ackCallback);
+      }
+
+      // 构建 Socket.IO 事件消息:42["event", data] 或 42/namespace["event", data]
+      const message = SocketIOProtocol.buildMessage(
+        SocketIOProtocol.PACKET_EVENT,
+        event,
+        data,
+        ackId,
+        this.namespace !== '/' ? this.namespace : undefined
+      );
+      ILog.d(TAG, `Emitting event: ${event}, message: ${message}`);
+      
+      // 发送消息
+      this.transport.send(message);
+    } catch (e) {
+      ILog.e(TAG, `Error emitting event: ${event}`, e as Error);
+    }
+  }
+
+  emitBinary(event: string, data: ArrayBuffer | Uint8Array, ackCallback?: (response: object) => void): void {
+    if (!this.isConnected() || !this.transport) {
+      ILog.w(TAG, `Cannot emit binary event ${event}: not connected`);
+      return;
+    }
+
+    try {
+      // 生成占位符索引
+      const placeholderIndex = this.binaryDataQueue.size;
+      this.binaryDataQueue.set(placeholderIndex, data);
+
+      let ackId: number | undefined = undefined;
+      if (ackCallback) {
+        ackId = this.nextAckId++;
+        this.ackCallbacks.set(ackId, ackCallback);
+      }
+
+      // 构建二进制事件消息:51-["event", {"_placeholder":true,"num":0}]
+      const message = SocketIOProtocol.buildBinaryMessage(event, placeholderIndex);
+      ILog.d(TAG, `Emitting binary event: ${event}, placeholderIndex: ${placeholderIndex}`);
+      
+      // 发送占位符消息
+      this.transport.send(message);
+      
+      // 发送二进制数据(WebSocket 支持,HTTP 长轮询需要 base64 编码)
+      if (this.currentTransport === 'websocket') {
+        // WebSocket 可以直接发送二进制数据
+        if (this.transport instanceof WebSocketTransport) {
+          // 注意:这里需要扩展 Transport 接口支持二进制数据
+          // 暂时使用 JSON 编码的方式
+          const base64Data = this.arrayBufferToBase64(data);
+          this.transport.send(base64Data);
+        }
+      } else {
+        // HTTP 长轮询需要 base64 编码
+        const base64Data = this.arrayBufferToBase64(data);
+        this.transport.send(base64Data);
+      }
+    } catch (e) {
+      ILog.e(TAG, `Error emitting binary event: ${event}`, e as Error);
+    }
+  }
+
+  joinRoom(room: string): void {
+    if (!this.isConnected()) {
+      ILog.w(TAG, `Cannot join room ${room}: not connected`);
+      return;
+    }
+
+    if (this.rooms.has(room)) {
+      ILog.d(TAG, `Already in room: ${room}`);
+      return;
+    }
+
+    // 发送加入房间事件(Socket.IO 约定的事件名)
+    interface JoinRoomData {
+      room: string;
+    }
+    const joinData: JoinRoomData = { room: room };
+    this.emit('join', joinData as object);
+    this.rooms.add(room);
+    ILog.d(TAG, `Joined room: ${room}`);
+  }
+
+  leaveRoom(room: string): void {
+    if (!this.rooms.has(room)) {
+      ILog.d(TAG, `Not in room: ${room}`);
+      return;
+    }
+
+    // 发送离开房间事件(Socket.IO 约定的事件名)
+    interface LeaveRoomData {
+      room: string;
+    }
+    const leaveData: LeaveRoomData = { room: room };
+    this.emit('leave', leaveData as object);
+    this.rooms.delete(room);
+    ILog.d(TAG, `Left room: ${room}`);
+  }
+
+  getNamespace(): string {
+    return this.namespace;
+  }
+
+  /**
+   * ArrayBuffer/Uint8Array 转 Base64
+   * 
+   * 使用手动实现的 Base64 编码算法
+   */
+  private arrayBufferToBase64(buffer: ArrayBuffer | Uint8Array): string {
+    try {
+      // 转换为 Uint8Array
+      let bytes: Uint8Array;
+      if (buffer instanceof Uint8Array) {
+        bytes = buffer;
+      } else {
+        bytes = new Uint8Array(buffer);
+      }
+      
+      // 使用 Base64 编码
+      return this.base64Encode(bytes);
+    } catch (e) {
+      ILog.e(TAG, "arrayBufferToBase64 编码失败", e as Error);
+      return '';
+    }
+  }
+  
+  /**
+   * Base64 编码(手动实现)
+   * 
+   * @param bytes Uint8Array 数据
+   * @return Base64 编码后的字符串
+   */
+  private base64Encode(bytes: Uint8Array): string {
+    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+    let result = '';
+    
+    for (let i = 0; i < bytes.length; i += 3) {
+      const byte1 = bytes[i];
+      const byte2 = i + 1 < bytes.length ? bytes[i + 1] : 0;
+      const byte3 = i + 2 < bytes.length ? bytes[i + 2] : 0;
+      
+      const enc1 = byte1 >> 2;
+      const enc2 = ((byte1 & 3) << 4) | (byte2 >> 4);
+      const enc3 = ((byte2 & 15) << 2) | (byte3 >> 6);
+      const enc4 = byte3 & 63;
+      
+      result += chars.charAt(enc1);
+      result += chars.charAt(enc2);
+      result += (i + 1 < bytes.length) ? chars.charAt(enc3) : '=';
+      result += (i + 2 < bytes.length) ? chars.charAt(enc4) : '=';
+    }
+    
+    return result;
+  }
+}

+ 32 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/model/SocketIOEvent.ets

@@ -0,0 +1,32 @@
+/**
+ * SocketIO事件类型常量
+ * 
+ * 定义SocketIO通信中使用的事件名称
+ * 建议使用这些常量而不是硬编码字符串
+ */
+export class SocketIOEvent {
+  // ========== 连接事件(SocketIO内置事件) ==========
+  /** 连接成功 */
+  static readonly CONNECT = "connect";
+  /** 断开连接 */
+  static readonly DISCONNECT = "disconnect";
+  /** 连接错误 */
+  static readonly CONNECT_ERROR = "connect_error";
+  
+  // ========== 车辆相关事件(业务事件) ==========
+  /** 车辆状态更新 */
+  static readonly VEHICLE_STATUS = "vehicle_status";
+  /** 车辆控制指令 */
+  static readonly VEHICLE_CONTROL = "vehicle_control";
+  /** 车辆报警 */
+  static readonly VEHICLE_ALARM = "vehicle_alarm";
+  /** 车辆位置更新 */
+  static readonly VEHICLE_LOCATION = "vehicle_location";
+  
+  // ========== 消息相关事件(业务事件) ==========
+  /** 普通消息 */
+  static readonly MESSAGE = "message";
+  /** 站内信 */
+  static readonly INBOX_MESSAGE = "inbox_message";
+}
+

+ 21 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/model/SocketIOResponse.ets

@@ -0,0 +1,21 @@
+/**
+ * SocketIO响应模型
+ * 
+ * 用于封装SocketIO服务器推送的实时数据
+ * 
+ * @param event 事件名称(如 "vehicle_status", "vehicle_control" 等)
+ * @param data 数据内容(JSON字符串格式)
+ * @param timestamp 时间戳(接收时间)
+ */
+export class SocketIOResponse {
+  event: string;
+  data: string;
+  timestamp: number;
+
+  constructor(event: string, data: string, timestamp: number = Date.now()) {
+    this.event = event;
+    this.data = data;
+    this.timestamp = timestamp;
+  }
+}
+

+ 280 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/protocol/SocketIOProtocol.ets

@@ -0,0 +1,280 @@
+import { ILog } from '@xdz/base-core';
+
+const TAG = "SocketIOProtocol";
+
+/**
+ * Socket.IO 消息解析结果接口
+ */
+export interface ParsedMessage {
+  type: number;
+  data?: object;
+  event?: string;
+  id?: number;
+}
+
+/**
+ * 命名空间解析结果接口
+ */
+export interface NamespaceParseResult {
+  namespace?: string;
+  message: string;
+}
+
+/**
+ * 占位符接口
+ */
+interface Placeholder {
+  "_placeholder": boolean;
+  "num": number;
+}
+
+/**
+ * Socket.IO 协议实现
+ * 
+ * Socket.IO 协议规范:
+ * - 消息类型:0=CONNECT, 1=DISCONNECT, 2=EVENT, 3=ACK, 4=ERROR, 5=BINARY_EVENT, 6=BINARY_ACK
+ * - 消息格式:<packet type>[<data>]
+ * - 握手:HTTP 轮询或 WebSocket 升级
+ * - 心跳:ping/pong 机制
+ */
+export class SocketIOProtocol {
+  // Engine.IO 协议版本(与服务器保持一致,当前服务器使用 v1)
+  // 如果需要支持不同版本的服务器,只需修改此常量即可
+  static readonly ENGINE_IO_VERSION = "1";
+  
+  // Socket.IO 消息类型
+  static readonly PACKET_CONNECT = 0;
+  static readonly PACKET_DISCONNECT = 1;
+  static readonly PACKET_EVENT = 2;
+  static readonly PACKET_ACK = 3;
+  static readonly PACKET_ERROR = 4;
+  static readonly PACKET_BINARY_EVENT = 5;
+  static readonly PACKET_BINARY_ACK = 6;
+  static readonly PACKET_PING = 2; // ping 使用 EVENT 类型,但 event 名称为 "ping"
+  static readonly PACKET_PONG = 3; // pong 使用 ACK 类型
+
+  /**
+   * 解析 Socket.IO 消息
+   * 
+   * Socket.IO 消息格式:
+   * - 文本消息:<packet type>[<data>]
+   * - 例如:42["event", data] 表示 EVENT 类型,事件名为 "event",数据为 data
+   */
+  static parseMessage(message: string): ParsedMessage | null {
+    try {
+      if (!message || message.length === 0) {
+        return null;
+      }
+
+      const packetType = parseInt(message[0]);
+      
+      // 处理 ping/pong
+      if (packetType === SocketIOProtocol.PACKET_EVENT && message.startsWith('2')) {
+        const content = message.substring(1);
+        try {
+          const parsed = JSON.parse(content) as Array<object>;
+          if (Array.isArray(parsed) && parsed.length > 0) {
+            const firstElement = String(parsed[0]);
+            if (firstElement === 'ping') {
+              const pingResult: ParsedMessage = { type: SocketIOProtocol.PACKET_PING };
+              return pingResult;
+            }
+          }
+        } catch (e) {
+          // 忽略解析错误
+        }
+      }
+
+      // 处理普通事件消息:42["event", data]
+      if (packetType === SocketIOProtocol.PACKET_EVENT) {
+        const content = message.substring(1);
+        try {
+          const parsed = JSON.parse(content) as Array<object>;
+          if (Array.isArray(parsed) && parsed.length >= 1) {
+            const eventResult: ParsedMessage = {
+              type: packetType,
+              event: String(parsed[0]),
+              data: parsed.length > 1 ? (parsed[1] as object) : undefined
+            };
+            return eventResult;
+          }
+        } catch (e) {
+          ILog.e(TAG, `Failed to parse event message: ${content}`, e as Error);
+        }
+      }
+
+      // 处理连接消息:0{"sid":"...","upgrades":[],"pingInterval":25000,"pingTimeout":20000}
+      if (packetType === SocketIOProtocol.PACKET_CONNECT) {
+        const content = message.substring(1);
+        try {
+          const parsed = JSON.parse(content) as object;
+          const connectResult: ParsedMessage = {
+            type: packetType,
+            data: parsed
+          };
+          return connectResult;
+        } catch (e) {
+          ILog.e(TAG, `Failed to parse connect message: ${content}`, e as Error);
+        }
+      }
+
+      // 处理断开连接消息:1
+      if (packetType === SocketIOProtocol.PACKET_DISCONNECT) {
+        const disconnectResult: ParsedMessage = { type: packetType };
+        return disconnectResult;
+      }
+
+      // 处理错误消息:4{"message":"..."}
+      if (packetType === SocketIOProtocol.PACKET_ERROR) {
+        const content = message.substring(1);
+        try {
+          const parsed = JSON.parse(content) as object;
+          const errorResult: ParsedMessage = {
+            type: packetType,
+            data: parsed
+          };
+          return errorResult;
+        } catch (e) {
+          ILog.e(TAG, `Failed to parse error message: ${content}`, e as Error);
+        }
+      }
+
+      const defaultResult: ParsedMessage = { type: packetType };
+      return defaultResult;
+    } catch (e) {
+      ILog.e(TAG, `Failed to parse Socket.IO message: ${message}`, e as Error);
+      return null;
+    }
+  }
+
+  /**
+   * 构建 Socket.IO 消息
+   * 
+   * @param type 消息类型
+   * @param event 事件名称(可选)
+   * @param data 数据(可选)
+   * @param id ACK ID(可选)
+   * @param namespace 命名空间(可选)
+   */
+  static buildMessage(type: number, event?: string, data?: object, id?: number, namespace?: string): string {
+    try {
+      // 连接消息:0
+      if (type === SocketIOProtocol.PACKET_CONNECT) {
+        return '0';
+      }
+
+      // 断开连接消息:1
+      if (type === SocketIOProtocol.PACKET_DISCONNECT) {
+        return '1';
+      }
+
+      // 事件消息:42["event", data] 或 42/namespace["event", data](带命名空间)
+      if (type === SocketIOProtocol.PACKET_EVENT) {
+        if (event) {
+          const payload = data !== undefined ? [event, data] : [event];
+          let message = `${type}${JSON.stringify(payload)}`;
+          // 如果有命名空间,添加到消息前面
+          if (namespace) {
+            message = `${type}/${namespace}${JSON.stringify(payload)}`;
+          }
+          return message;
+        }
+        return `${type}[]`;
+      }
+
+      // ACK 消息:43[data]
+      if (type === SocketIOProtocol.PACKET_ACK) {
+        const payload = data !== undefined ? [data] : [];
+        return `${type}${JSON.stringify(payload)}`;
+      }
+
+      // Ping 消息:2["ping"]
+      if (type === SocketIOProtocol.PACKET_PING) {
+        return `${SocketIOProtocol.PACKET_EVENT}["ping"]`;
+      }
+
+      // Pong 消息:3["pong"]
+      if (type === SocketIOProtocol.PACKET_PONG) {
+        return `${SocketIOProtocol.PACKET_ACK}["pong"]`;
+      }
+
+      return `${type}`;
+    } catch (e) {
+      ILog.e(TAG, `Failed to build Socket.IO message`, e as Error);
+      return '';
+    }
+  }
+
+  /**
+   * 构建握手 URL
+   * 
+   * Socket.IO 握手使用 HTTP 轮询或 WebSocket 升级
+   * URL 格式:/socket.io/?EIO=1&transport=websocket&token=xxx
+   * 
+   * @param serverUrl 服务器地址
+   * @param token Token
+   * @param transport 传输方式(websocket 或 polling)
+   * @param namespace 命名空间(可选)
+   */
+  static buildHandshakeUrl(serverUrl: string, token: string, transport: string = 'websocket', namespace?: string): string {
+    let url = serverUrl;
+    
+    // WebSocket 需要转换协议
+    if (transport === 'websocket') {
+      url = url.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:');
+    }
+    
+    // 确保 URL 以 / 结尾
+    if (!url.endsWith('/')) {
+      url += '/';
+    }
+    
+    // 添加 Socket.IO 路径和参数
+    // 使用 ENGINE_IO_VERSION 常量,与服务器保持一致(当前服务器使用 v1)
+    let path = `socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=${transport}&token=${encodeURIComponent(token)}`;
+    
+    // 如果有命名空间,添加到路径
+    if (namespace) {
+      path = `${namespace}/socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=${transport}&token=${encodeURIComponent(token)}`;
+    }
+    
+    url += path;
+    
+    return url;
+  }
+
+  /**
+   * 构建二进制消息(带占位符)
+   * 
+   * Socket.IO 二进制消息格式:51-["event", {"_placeholder":true,"num":0}]
+   * 二进制数据会作为单独的消息发送
+   */
+  static buildBinaryMessage(event: string, placeholderIndex: number): string {
+    const placeholder: Placeholder = {
+      "_placeholder": true,
+      "num": placeholderIndex
+    };
+    // 构建数组,第一个元素是事件名(字符串),第二个元素是占位符对象
+    const payload: Array<object | string> = [event, placeholder as object];
+    return `${SocketIOProtocol.PACKET_BINARY_EVENT}${JSON.stringify(payload)}`;
+  }
+
+  /**
+   * 解析命名空间
+   * 
+   * 从消息中提取命名空间,例如:42/namespace["event", data]
+   */
+  static parseNamespace(message: string): NamespaceParseResult {
+    const match: RegExpMatchArray | null = message.match(/^(\d+)\/([^[]+)(.*)$/);
+    if (match && match.length >= 4) {
+      const result: NamespaceParseResult = {
+        namespace: match[2],
+        message: match[1] + match[3]
+      };
+      return result;
+    }
+    const defaultResult: NamespaceParseResult = { message: message };
+    return defaultResult;
+  }
+}
+

+ 192 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/repository/SocketIORepository.ets

@@ -0,0 +1,192 @@
+import { ILog, StorageImpl, StorageKeys } from '@xdz/base-core';
+import { SocketIOService } from '../api/SocketIOService';
+import { SocketIOServiceFactory } from '../factory/SocketIOServiceFactory';
+import { SocketIOEvent } from '../model/SocketIOEvent';
+import { SocketIOResponse } from '../model/SocketIOResponse';
+import { StateFlow } from './StateFlow';
+
+const TAG = "SocketIORepository";
+
+/**
+ * SocketIO 数据仓库
+ * 
+ * 负责统一管理 SocketIO 连接和数据获取
+ * 完全封装在 capability-socketio 模块内部,app 模块通过 Factory 获取实例
+ */
+export class SocketIORepository {
+  private socketService: SocketIOService;
+  
+  // 使用 StateFlow 管理状态
+  private _connectionState = new StateFlow<boolean>(false);
+  connectionState: StateFlow<boolean> = this._connectionState;
+  
+  private _logMessage = new StateFlow<string>('');
+  logMessage: StateFlow<string> = this._logMessage;
+  
+  private _vehicleControlResponse = new StateFlow<SocketIOResponse | null>(null);
+  vehicleControlResponse: StateFlow<SocketIOResponse | null> = this._vehicleControlResponse;
+  
+  private _vehicleAlarm = new StateFlow<SocketIOResponse | null>(null);
+  vehicleAlarm: StateFlow<SocketIOResponse | null> = this._vehicleAlarm;
+  
+  constructor(socketService?: SocketIOService) {
+    this.socketService = socketService || SocketIOServiceFactory.getInstance();
+    this.subscribeEvents();
+  }
+  
+  /**
+   * 连接 SocketIO
+   * 
+   * @param serverUrl SocketIO 服务器地址(如果为 null,则从存储中获取)
+   * @param token JWT Token(如果为 null,则从存储中获取)
+   * @param namespace 命名空间(可选,默认为 "/")
+   */
+  async connect(serverUrl: string | null = null, token: string | null = null, namespace: string = '/'): Promise<void> {
+    try {
+      const finalServerUrl = serverUrl || await StorageImpl.getInstance().getString(StorageKeys.APP_SOCKET_URL);
+      const finalToken = token || await StorageImpl.getInstance().getString(StorageKeys.TOKEN_ACCESS);
+      
+      if (!finalServerUrl || finalServerUrl === '' || !finalToken || finalToken === '') {
+        throw new Error("未登录或服务器地址未配置,无法连接");
+      }
+      
+      ILog.d(TAG, `connect: 正在连接 ${finalServerUrl}, namespace: ${namespace}`);
+      await this.socketService.connect(finalServerUrl, finalToken, namespace);
+    } catch (e) {
+      ILog.e(TAG, "connect: 连接失败", e as Error);
+      if (e instanceof Error) {
+        throw e;
+      } else {
+        throw new Error(String(e));
+      }
+    }
+  }
+  
+  /**
+   * 断开 SocketIO 连接
+   */
+  async disconnect(): Promise<void> {
+    try {
+      await this.socketService.disconnect();
+      ILog.d(TAG, "disconnect: 已断开连接");
+    } catch (e) {
+      ILog.e(TAG, "disconnect: 断开连接失败", e as Error);
+      if (e instanceof Error) {
+        throw e;
+      } else {
+        throw new Error(String(e));
+      }
+    }
+  }
+  
+  /**
+   * 检查连接状态
+   */
+  isConnected(): boolean {
+    return this.socketService.isConnected();
+  }
+  
+  /**
+   * 检查连接状态,如果断开则自动重连
+   * 
+   * 用于 App 进入前台时自动重连的场景
+   * 如果未传入 serverUrl 或 token,则从存储中自动获取
+   * 
+   * @param serverUrl SocketIO 服务器地址(如果为 null,则从存储中获取)
+   * @param token JWT Token(如果为 null,则从存储中获取)
+   * @param namespace 命名空间(可选,默认为 "/")
+   * @return 如果已连接返回 true,如果需要重连则返回 false(重连是异步的)
+   */
+  async checkAndReconnect(serverUrl: string | null = null, token: string | null = null, namespace: string = '/'): Promise<boolean> {
+    if (this.socketService.isConnected()) {
+      // 已连接,无需重连
+      ILog.d(TAG, "checkAndReconnect: 已连接,无需重连");
+      return true;
+    } else {
+      // 未连接,尝试重连
+      ILog.d(TAG, "checkAndReconnect: 未连接,开始重连...");
+      try {
+        await this.connect(serverUrl, token, namespace);
+        ILog.d(TAG, "checkAndReconnect: 重连成功");
+        return true;
+      } catch (e) {
+        ILog.e(TAG, "checkAndReconnect: 重连失败", e as Error);
+        return false;
+      }
+    }
+  }
+  
+  /**
+   * 发送车辆控制指令
+   */
+  async sendVehicleControl(command: string, vehicleId: number): Promise<void> {
+    try {
+      if (!this.socketService.isConnected()) {
+        throw new Error("未连接,无法发送消息");
+      }
+      
+      interface VehicleControlData {
+        command: string;
+        vehicleId: number;
+        timestamp: number;
+      }
+      const data: VehicleControlData = {
+        command: command,
+        vehicleId: vehicleId,
+        timestamp: Date.now()
+      };
+      this.socketService.emit(SocketIOEvent.VEHICLE_CONTROL, data as object);
+      ILog.d(TAG, `sendVehicleControl: 发送指令 ${command}`);
+    } catch (e) {
+      ILog.e(TAG, "sendVehicleControl: 发送失败", e as Error);
+      if (e instanceof Error) {
+        throw e;
+      } else {
+        throw new Error(String(e));
+      }
+    }
+  }
+  
+  /**
+   * 订阅 SocketIO 事件
+   */
+  private subscribeEvents(): void {
+    // 订阅连接成功事件
+    this.socketService.on(SocketIOEvent.CONNECT, (response: SocketIOResponse) => {
+      ILog.d(TAG, "onConnect - 触发连接状态更新");
+      this._connectionState.value = true;
+      this._logMessage.value = "✅ 连接成功";
+    });
+    
+    // 订阅断开连接事件
+    this.socketService.on(SocketIOEvent.DISCONNECT, (response: SocketIOResponse) => {
+      ILog.d(TAG, "onDisconnect");
+      this._connectionState.value = false;
+      this._logMessage.value = "❌ 断开连接";
+    });
+    
+    // 订阅连接错误事件
+    this.socketService.on(SocketIOEvent.CONNECT_ERROR, (response: SocketIOResponse) => {
+      ILog.e(TAG, `onConnectError: ${response.data}`);
+      this._connectionState.value = false;
+      this._logMessage.value = `❌ 连接错误:${response.data}`;
+    });
+    
+    // 订阅车辆控制响应事件
+    this.socketService.on("vehicle_control_response", (response: SocketIOResponse) => {
+      ILog.d(TAG, `onVehicleControlResponse: ${response.data}`);
+      this._logMessage.value = `📩 收到车辆控制响应:${response.data}`;
+      this._vehicleControlResponse.value = response;
+    });
+    
+    // 订阅车辆报警事件
+    this.socketService.on(SocketIOEvent.VEHICLE_ALARM, (response: SocketIOResponse) => {
+      ILog.d(TAG, `onVehicleAlarm: ${response.data}`);
+      this._logMessage.value = "🚨 收到车辆报警推送";
+      this._logMessage.value = `   事件: ${response.event}`;
+      this._logMessage.value = `   数据: ${response.data}`;
+      this._vehicleAlarm.value = response;
+    });
+  }
+}
+

+ 75 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/repository/StateFlow.ets

@@ -0,0 +1,75 @@
+/**
+ * StateFlow 的 HarmonyOS 实现(capability-socketio 内部使用)
+ * 
+ * 提供类似 Android StateFlow 的功能,用于响应式状态管理
+ * 
+ * 注意:这个类在 capability-socketio 模块内部,避免依赖 base-common
+ */
+export class StateFlow<T> {
+  private _value: T;
+  private listeners: Set<(value: T) => void> = new Set();
+  
+  constructor(initialValue: T) {
+    this._value = initialValue;
+  }
+  
+  /**
+   * 获取当前值
+   */
+  get value(): T {
+    return this._value;
+  }
+  
+  /**
+   * 设置新值(并通知所有监听者)
+   */
+  set value(newValue: T) {
+    if (this._value !== newValue) {
+      this._value = newValue;
+      this.notifyListeners();
+    }
+  }
+  
+  /**
+   * 添加监听者
+   */
+  observe(listener: (value: T) => void): () => void {
+    this.listeners.add(listener);
+    // 立即通知当前值
+    listener(this._value);
+    
+    // 返回取消监听的函数
+    return () => {
+      this.listeners.delete(listener);
+    };
+  }
+  
+  /**
+   * 移除监听者
+   */
+  removeObserver(listener: (value: T) => void): void {
+    this.listeners.delete(listener);
+  }
+  
+  /**
+   * 通知所有监听者
+   */
+  private notifyListeners(): void {
+    this.listeners.forEach(listener => {
+      try {
+        listener(this._value);
+      } catch (error) {
+        // 监听器错误已静默处理,避免影响其他监听器
+        // 如需记录日志,可在此处添加 LogHelper.e('StateFlow', 'listener error', error);
+      }
+    });
+  }
+  
+  /**
+   * 获取监听者数量(用于调试)
+   */
+  get observerCount(): number {
+    return this.listeners.size;
+  }
+}
+

+ 299 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/transport/PollingTransport.ets

@@ -0,0 +1,299 @@
+import { http } from '@kit.NetworkKit';
+import { ILog } from '@xdz/base-core';
+import { Transport } from './Transport';
+import { SocketIOProtocol } from '../protocol/SocketIOProtocol';
+
+const TAG = "PollingTransport";
+
+/**
+ * HTTP 长轮询传输实现
+ * 
+ * Socket.IO 的降级传输方式,当 WebSocket 不可用时使用
+ * 通过 HTTP GET 轮询接收消息,POST 发送消息
+ */
+export class PollingTransport implements Transport {
+  private serverUrl: string = '';
+  private token: string = '';
+  private namespace: string = '/';
+  private sid: string | null = null;
+  private connected: boolean = false;
+  private pollingTimer: number | null = null;
+  private messageCallback: ((message: string) => void) | null = null;
+  private openCallback: (() => void) | null = null;
+  private closeCallback: (() => void) | null = null;
+  private errorCallback: ((error: Error) => void) | null = null;
+  private httpRequest: http.HttpRequest | null = null;
+  private polling: boolean = false;
+
+  constructor() {
+    this.httpRequest = http.createHttp();
+  }
+
+  async connect(url: string, token: string, namespace: string = '/'): Promise<void> {
+    try {
+      ILog.d(TAG, "=== HTTP 长轮询连接开始 ===");
+      ILog.d(TAG, `服务器地址: ${url}`);
+      ILog.d(TAG, `命名空间: ${namespace}`);
+      
+      this.serverUrl = url;
+      this.token = token;
+      this.namespace = namespace;
+
+      // 1. 先进行握手(GET 请求)
+      await this.handshake();
+      
+      // 2. 开始轮询接收消息
+      this.startPolling();
+      
+      this.connected = true;
+      this.openCallback?.();
+      ILog.d(TAG, "✅ HTTP 长轮询连接成功");
+    } catch (e) {
+      ILog.e(TAG, "❌ HTTP 长轮询连接失败", e as Error);
+      this.errorCallback?.(e as Error);
+      if (e instanceof Error) {
+        throw e;
+      } else {
+        throw new Error(String(e));
+      }
+    }
+  }
+
+  /**
+   * Socket.IO 握手(HTTP GET)
+   * 
+   * 获取 session ID (sid) 和连接参数
+   */
+  private async handshake(): Promise<void> {
+    const handshakeUrl = this.buildHandshakeUrl(this.namespace);
+    ILog.d(TAG, `握手 URL: ${handshakeUrl}`);
+
+    try {
+      const response = await this.httpRequest!.request(handshakeUrl, {
+        method: http.RequestMethod.GET,
+        header: {
+          'Authorization': `Bearer ${this.token}`
+        },
+        connectTimeout: 10000,
+        readTimeout: 10000
+      });
+
+      if (response.responseCode === 200) {
+        const data = JSON.parse(response.result.toString()) as Record<string, object>;
+        this.sid = String(data.sid);
+        ILog.d(TAG, `握手成功,SID: ${this.sid}`);
+      } else {
+        throw new Error(`握手失败,状态码: ${response.responseCode}`);
+      }
+    } catch (e) {
+      ILog.e(TAG, "握手失败", e as Error);
+      if (e instanceof Error) {
+        throw e;
+      } else {
+        throw new Error(String(e));
+      }
+    }
+  }
+
+  /**
+   * 开始轮询接收消息
+   */
+  private startPolling(): void {
+    if (this.polling) {
+      return;
+    }
+    
+    this.polling = true;
+    this.poll();
+  }
+
+  /**
+   * 轮询接收消息(HTTP GET)
+   */
+  private async poll(): Promise<void> {
+    if (!this.polling || !this.connected) {
+      return;
+    }
+
+    try {
+      const pollUrl = this.buildPollUrl();
+      const response = await this.httpRequest!.request(pollUrl, {
+        method: http.RequestMethod.GET,
+        header: {
+          'Authorization': `Bearer ${this.token}`
+        },
+        connectTimeout: 60000, // 60 秒超时(长轮询)
+        readTimeout: 60000
+      });
+
+      if (response.responseCode === 200) {
+        const messages = response.result.toString();
+        if (messages && messages.length > 0) {
+          // Socket.IO 可能返回多个消息,用换行符分隔
+          const messageArray = messages.split('\n').filter(msg => msg.trim().length > 0);
+          for (const message of messageArray) {
+            this.messageCallback?.(message);
+          }
+        }
+        
+        // 继续轮询
+        if (this.polling && this.connected) {
+          this.poll();
+        }
+      } else if (response.responseCode === 400) {
+        // 400 表示连接已关闭
+        ILog.d(TAG, "轮询返回 400,连接已关闭");
+        this.polling = false;
+        this.connected = false;
+        this.closeCallback?.();
+      } else {
+        ILog.w(TAG, `轮询返回状态码: ${response.responseCode}`);
+        // 继续轮询
+        if (this.polling && this.connected) {
+          setTimeout(() => this.poll(), 1000);
+        }
+      }
+    } catch (e) {
+      ILog.e(TAG, "轮询错误", e as Error);
+      // 继续轮询
+      if (this.polling && this.connected) {
+        setTimeout(() => this.poll(), 1000);
+      }
+    }
+  }
+
+  /**
+   * 发送消息(HTTP POST)
+   */
+  send(message: string): void {
+    if (!this.connected || !this.sid) {
+      ILog.w(TAG, "未连接,无法发送消息");
+      return;
+    }
+
+    this.sendMessage(message).catch((e: Error) => {
+      ILog.e(TAG, "发送消息失败", e);
+      this.errorCallback?.(e);
+    });
+  }
+
+  /**
+   * HTTP POST 发送消息
+   */
+  private async sendMessage(message: string): Promise<void> {
+    const sendUrl = this.buildSendUrl();
+    
+    try {
+      const response = await this.httpRequest!.request(sendUrl, {
+        method: http.RequestMethod.POST,
+        header: {
+          'Content-Type': 'text/plain;charset=UTF-8',
+          'Authorization': `Bearer ${this.token}`
+        },
+        extraData: message,
+        connectTimeout: 10000,
+        readTimeout: 10000
+      });
+
+      if (response.responseCode !== 200) {
+        throw new Error(`发送消息失败,状态码: ${response.responseCode}`);
+      }
+    } catch (e) {
+      ILog.e(TAG, "发送消息失败", e as Error);
+      if (e instanceof Error) {
+        throw e;
+      } else {
+        throw new Error(String(e));
+      }
+    }
+  }
+
+  async disconnect(): Promise<void> {
+    this.polling = false;
+    this.connected = false;
+    
+    if (this.pollingTimer !== null) {
+      clearTimeout(this.pollingTimer);
+      this.pollingTimer = null;
+    }
+
+    if (this.httpRequest) {
+      this.httpRequest.destroy();
+      this.httpRequest = null;
+    }
+
+    ILog.d(TAG, "HTTP 长轮询连接已断开");
+  }
+
+  isConnected(): boolean {
+    return this.connected && this.sid !== null;
+  }
+
+  onMessage(callback: (message: string) => void): void {
+    this.messageCallback = callback;
+  }
+
+  onOpen(callback: () => void): void {
+    this.openCallback = callback;
+  }
+
+  onClose(callback: () => void): void {
+    this.closeCallback = callback;
+  }
+
+  onError(callback: (error: Error) => void): void {
+    this.errorCallback = callback;
+  }
+
+  /**
+   * 构建握手 URL
+   * 
+   * 注意:PollingTransport 的 connect 方法需要接收 namespace 参数
+   * 这里暂时不支持命名空间,后续可以扩展
+   */
+  private buildHandshakeUrl(namespace?: string): string {
+    let url = this.serverUrl;
+    if (!url.endsWith('/')) {
+      url += '/';
+    }
+    let path = `socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=polling&token=${encodeURIComponent(this.token)}`;
+    if (namespace && namespace !== '/') {
+      path = `${namespace}/socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=polling&token=${encodeURIComponent(this.token)}`;
+    }
+    url += path;
+    return url;
+  }
+
+  /**
+   * 构建轮询 URL
+   */
+  private buildPollUrl(): string {
+    let url = this.serverUrl;
+    if (!url.endsWith('/')) {
+      url += '/';
+    }
+    let path = `socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=polling&sid=${this.sid}&token=${encodeURIComponent(this.token)}`;
+    if (this.namespace && this.namespace !== '/') {
+      path = `${this.namespace}/socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=polling&sid=${this.sid}&token=${encodeURIComponent(this.token)}`;
+    }
+    url += path;
+    return url;
+  }
+
+  /**
+   * 构建发送消息 URL
+   */
+  private buildSendUrl(): string {
+    let url = this.serverUrl;
+    if (!url.endsWith('/')) {
+      url += '/';
+    }
+    let path = `socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=polling&sid=${this.sid}&token=${encodeURIComponent(this.token)}`;
+    if (this.namespace && this.namespace !== '/') {
+      path = `${this.namespace}/socket.io/?EIO=${SocketIOProtocol.ENGINE_IO_VERSION}&transport=polling&sid=${this.sid}&token=${encodeURIComponent(this.token)}`;
+    }
+    url += path;
+    return url;
+  }
+}
+

+ 58 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/transport/Transport.ets

@@ -0,0 +1,58 @@
+import { SocketIOResponse } from '../model/SocketIOResponse';
+import { ILog } from '@xdz/base-core';
+
+const TAG = "Transport";
+
+/**
+ * Socket.IO 传输层接口
+ * 
+ * 支持两种传输方式:
+ * - WebSocket:实时双向通信
+ * - HTTP 长轮询:降级方案,兼容性更好
+ */
+export interface Transport {
+  /**
+   * 连接服务器
+   * 
+   * @param url 服务器地址或完整的 WebSocket URL
+   * @param token Token(用于 HTTP 长轮询)
+   * @param namespace 命名空间(可选,用于 HTTP 长轮询)
+   */
+  connect(url: string, token: string, namespace?: string): Promise<void>;
+  
+  /**
+   * 断开连接
+   */
+  disconnect(): Promise<void>;
+  
+  /**
+   * 是否已连接
+   */
+  isConnected(): boolean;
+  
+  /**
+   * 发送消息
+   */
+  send(message: string): void;
+  
+  /**
+   * 设置消息接收回调
+   */
+  onMessage(callback: (message: string) => void): void;
+  
+  /**
+   * 设置连接成功回调
+   */
+  onOpen(callback: () => void): void;
+  
+  /**
+   * 设置连接关闭回调
+   */
+  onClose(callback: () => void): void;
+  
+  /**
+   * 设置错误回调
+   */
+  onError(callback: (error: Error) => void): void;
+}
+

+ 160 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/ets/socketio/transport/WebSocketTransport.ets

@@ -0,0 +1,160 @@
+import { webSocket } from '@kit.NetworkKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { ILog } from '@xdz/base-core';
+import { Transport } from './Transport';
+
+const TAG = "WebSocketTransport";
+
+/**
+ * WebSocket 传输实现
+ * 
+ * Socket.IO 的首选传输方式,实时双向通信
+ */
+export class WebSocketTransport implements Transport {
+  private ws: webSocket.WebSocket | null = null;
+  private connected: boolean = false;
+  private messageCallback: ((message: string) => void) | null = null;
+  private openCallback: (() => void) | null = null;
+  private closeCallback: (() => void) | null = null;
+  private errorCallback: ((error: Error) => void) | null = null;
+
+  async connect(url: string, token: string, namespace?: string): Promise<void> {
+    return new Promise<void>((resolve, reject) => {
+      try {
+        ILog.d(TAG, "=== WebSocket 连接开始 ===");
+        // url 已经是完整的 WebSocket URL(包含 token 和命名空间)
+        const wsUrl = url;
+        ILog.d(TAG, `WebSocket URL: ${wsUrl}`);
+
+        // 创建 WebSocket 连接
+        this.ws = webSocket.createWebSocket();
+        
+        // 设置回调
+        this.ws.on('open', (err: BusinessError, value: Object) => {
+          if (err != undefined) {
+            ILog.e(TAG, `WebSocket 连接打开失败: ${JSON.stringify(err)}`);
+            this.connected = false;
+            const error = new Error(JSON.stringify(err));
+            this.errorCallback?.(error);
+            reject(error);
+            return;
+          }
+          ILog.d(TAG, "✅ WebSocket 连接成功");
+          this.connected = true;
+          this.openCallback?.();
+          resolve(); // 连接成功,resolve Promise
+        });
+
+        this.ws.on('message', (error: BusinessError, value: string | ArrayBuffer) => {
+          if (error != undefined) {
+            ILog.e(TAG, `接收消息错误: ${JSON.stringify(error)}`);
+            this.errorCallback?.(new Error(JSON.stringify(error)));
+            return;
+          }
+          try {
+            let message: string;
+            if (typeof value === 'string') {
+              message = value;
+            } else {
+              // HarmonyOS 需要使用 util.TextDecoder 或直接处理 ArrayBuffer
+              // 这里简化处理,假设是字符串
+              ILog.w(TAG, "ArrayBuffer 消息需要特殊处理");
+              message = String(value);
+            }
+            this.messageCallback?.(message);
+          } catch (e) {
+            ILog.e(TAG, "处理消息失败", e as Error);
+          }
+        });
+
+        this.ws.on('close', (err: BusinessError, value: webSocket.CloseResult) => {
+          if (err != undefined) {
+            ILog.e(TAG, `WebSocket 关闭错误: ${JSON.stringify(err)}`);
+          } else {
+            ILog.d(TAG, `❌ WebSocket 连接断开, code: ${value.code}, reason: ${value.reason}`);
+          }
+          this.connected = false;
+          this.closeCallback?.();
+        });
+
+        this.ws.on('error', (err: BusinessError) => {
+          ILog.e(TAG, `❌ WebSocket 连接错误: ${JSON.stringify(err)}`);
+          this.connected = false;
+          const error = new Error(JSON.stringify(err));
+          this.errorCallback?.(error);
+          reject(error);
+        });
+
+        // 连接 WebSocket(使用回调方式)
+        this.ws.connect(wsUrl, {}, (err: BusinessError, value: boolean) => {
+          if (err != undefined) {
+            ILog.e(TAG, `WebSocket 连接失败: ${JSON.stringify(err)}`);
+            this.connected = false;
+            const error = new Error(JSON.stringify(err));
+            this.errorCallback?.(error);
+            reject(error);
+          } else {
+            ILog.d(TAG, "WebSocket 连接请求已发送,等待 'open' 事件");
+            // 注意:这里不 resolve,真正的连接成功会在 'open' 事件中处理
+          }
+        });
+      } catch (e) {
+        ILog.e(TAG, "❌ WebSocket 连接异常", e as Error);
+        this.connected = false;
+        const error = e instanceof Error ? e : new Error(String(e));
+        reject(error);
+      }
+    });
+  }
+
+  async disconnect(): Promise<void> {
+    if (this.ws) {
+      this.ws.close((err: BusinessError, value: boolean) => {
+        if (err != undefined) {
+          ILog.e(TAG, `关闭 WebSocket 失败: ${JSON.stringify(err)}`);
+        } else {
+          ILog.d(TAG, "WebSocket 连接已断开");
+        }
+      });
+      this.ws = null;
+    }
+    this.connected = false;
+  }
+
+  isConnected(): boolean {
+    return this.connected && this.ws !== null;
+  }
+
+  send(message: string): void {
+    if (!this.isConnected() || !this.ws) {
+      ILog.w(TAG, "未连接,无法发送消息");
+      return;
+    }
+
+    this.ws.send(message, (err: BusinessError, value: boolean) => {
+      if (err != undefined) {
+        ILog.e(TAG, `发送消息失败: ${JSON.stringify(err)}`);
+        this.errorCallback?.(new Error(JSON.stringify(err)));
+      } else {
+        ILog.d(TAG, "发送消息成功");
+      }
+    });
+  }
+
+  onMessage(callback: (message: string) => void): void {
+    this.messageCallback = callback;
+  }
+
+  onOpen(callback: () => void): void {
+    this.openCallback = callback;
+  }
+
+  onClose(callback: () => void): void {
+    this.closeCallback = callback;
+  }
+
+  onError(callback: (error: Error) => void): void {
+    this.errorCallback = callback;
+  }
+}
+

+ 14 - 0
base-common/oh_modules/@xdz/capability-socketio/src/main/module.json5

@@ -0,0 +1,14 @@
+{
+  "module": {
+    "name": "capability_socketio",
+    "type": "har",
+    "description": "SocketIO 能力层模块",
+    "mainElement": "",
+    "deviceTypes": [
+      "phone",
+      "tablet",
+      "2in1"
+    ]
+  }
+}
+

+ 17 - 0
base-common/src/main/ets/common/auth/AuthGuardHolder.ets

@@ -0,0 +1,17 @@
+import type { IAuthGuard } from './IAuthGuard';
+
+/**
+ * 认证守卫持有者(3.3.2)
+ * 由 entry 注入 IAuthGuard 实现,ARouter/RouterManager 通过此处获取,避免循环依赖
+ */
+export class AuthGuardHolder {
+  private static guard: IAuthGuard | null = null;
+
+  static setGuard(guard: IAuthGuard | null): void {
+    AuthGuardHolder.guard = guard;
+  }
+
+  static getGuard(): IAuthGuard | null {
+    return AuthGuardHolder.guard;
+  }
+}

+ 15 - 0
base-common/src/main/ets/common/auth/IAuthGuard.ets

@@ -0,0 +1,15 @@
+/**
+ * 认证守卫接口(3.3.1)
+ * 由 entry 注入实现,base-common 不直接依赖 AuthManager/TokenStore
+ */
+export interface IAuthGuard {
+  /**
+   * 是否已登录
+   */
+  isLoggedIn(): Promise<boolean>;
+
+  /**
+   * 登出(清除本地登录态)
+   */
+  logout(): Promise<void>;
+}

+ 1 - 1
base-common/src/main/ets/common/camera/CameraHelper.ets

@@ -1,6 +1,6 @@
 import { Context, common } from '@kit.AbilityKit';
 import { LogHelper } from '../log/LogHelper';
-import { PermissionHelper } from '../permission/PermissionHelper';
+import { PermissionHelper } from '@xdz/base-core';
 
 const TAG = "CameraHelper";
 

+ 58 - 21
base-common/src/main/ets/common/config/ServerConfigManager.ets

@@ -5,17 +5,15 @@ import { StorageImpl, ILog } from '@xdz/base-core';
  * 服务器配置管理器
  * 用于管理开发测试时的服务器地址配置
  * 
- * 统一配置服务器IP,然后根据不同服务类型连接不同端口
- * - HTTP API服务:18080(用户服务)、18082(消息服务)
- * - SocketIO服务:9090
+ * 统一配置服务器地址和端口(IP:端口格式),然后根据不同服务类型拼接路径
+ * - HTTP API服务:从 IP:端口 拼接 http:// 和 /api/v1/app/
+ * - SocketIO服务:从 IP:端口 提取 IP,拼接 http:// 和 :9090
  */
 export class ServerConfigManager {
   private static readonly KEY_SERVER_IP = 'server_ip';
-  private static readonly DEFAULT_SERVER_IP = '192.168.1.107';
+  private static readonly DEFAULT_SERVER_ADDRESS = '192.168.1.107:8080';
   
-  // 服务端口配置
-  private static readonly PORT_HTTP_USER = 18080;
-  private static readonly PORT_HTTP_MESSAGE = 18082;
+  // 服务端口配置(SocketIO 单独配置)
   private static readonly PORT_SOCKETIO = 9090;
   
   /**
@@ -26,38 +24,77 @@ export class ServerConfigManager {
     if (!StorageImpl.isInitialized()) {
       await StorageImpl.init(context);
     }
-    const ip = await ServerConfigManager.getServerIp();
-    ILog.d('ServerConfigManager', `初始化完成,当前IP: ${ip}`);
+    const address = await ServerConfigManager.getServerAddress();
+    ILog.d('ServerConfigManager', `初始化完成,当前地址: ${address}`);
+  }
+  
+  /**
+   * 获取服务器地址(IP:端口格式)
+   * 公开方法,供 ServerConfigDialog 使用
+   */
+  static async getServerAddress(): Promise<string> {
+    const address = await StorageImpl.getInstance().getString(ServerConfigManager.KEY_SERVER_IP);
+    return address === '' ? ServerConfigManager.DEFAULT_SERVER_ADDRESS : address;
   }
   
   /**
-   * 获取服务器IP地址
+   * 设置服务器地址(IP:端口格式,如:192.168.1.107:8080)
+   */
+  static async setServerAddress(address: string): Promise<void> {
+    await StorageImpl.getInstance().putString(ServerConfigManager.KEY_SERVER_IP, address);
+    // ✅ 关键修复:显式调用 flush() 确保数据立即持久化到磁盘
+    // 虽然 HarmonyOS preferences 会自动持久化,但在应用重启前显式 flush 更可靠
+    await StorageImpl.getInstance().flush();
+    ILog.d('ServerConfigManager', `服务器地址已更新为: ${address}`);
+  }
+  
+  /**
+   * 获取服务器IP地址(从 IP:端口 中提取)
+   * 如果格式不正确(没有冒号),返回整个字符串(降级处理)
    */
   static async getServerIp(): Promise<string> {
-    const ip = await StorageImpl.getInstance().getString(ServerConfigManager.KEY_SERVER_IP);
-    return ip === '' ? ServerConfigManager.DEFAULT_SERVER_IP : ip;
+    const address = await ServerConfigManager.getServerAddress();
+    const colonIndex = address.indexOf(':');
+    return colonIndex >= 0 ? address.substring(0, colonIndex) : address;
   }
   
   /**
-   * 设置服务器IP地址
+   * 设置服务器IP地址(兼容旧接口,自动添加默认端口8080)
    */
   static async setServerIp(ip: string): Promise<void> {
-    await StorageImpl.getInstance().putString(ServerConfigManager.KEY_SERVER_IP, ip);
-    ILog.d('ServerConfigManager', `服务器IP已更新为: ${ip}`);
+    // 如果已经包含端口,直接使用;否则添加默认端口8080
+    if (ip.indexOf(':') >= 0) {
+      await ServerConfigManager.setServerAddress(ip);
+    } else {
+      await ServerConfigManager.setServerAddress(`${ip}:8080`);
+    }
   }
   
   /**
-   * 获取HTTP API服务器地址(用户服务)
+   * 获取HTTP API服务器地址(通过网关)
+   * 
+   * 从存储的 IP:端口 拼接完整URL:http://IP:端口/api/v1/app/
+   * 
+   * 网关路由配置:/api/v1/app/xxx -> StripPrefix=2 -> 转发到业务服务 /app/xxx
+   * API 路径:community/post/create
+   * 最终请求:http://ip:8080/api/v1/app/community/post/create
+   * 网关会去掉 /api/v1,转发 /app/community/post/create 到业务服务
+   * 业务服务 Controller 路径:/app/community/post
+   * 最终匹配:/app/community/post/create
    */
   static async getHttpServerUrl(): Promise<string> {
-    const ip = await ServerConfigManager.getServerIp();
-    const url = `http://${ip}:${ServerConfigManager.PORT_HTTP_USER}/app-api/`;
-    ILog.d('ServerConfigManager', `HTTP服务器地址: ${url}`);
+    const address = await ServerConfigManager.getServerAddress();
+    const url = `http://${address}/api/v1/app/`;
+    ILog.d('ServerConfigManager', `========== [HTTP服务器地址] ==========`);
+    ILog.d('ServerConfigManager', `[HTTP服务器地址] 存储的地址: ${address}`);
+    ILog.d('ServerConfigManager', `[HTTP服务器地址] 完整baseURL: ${url}`);
+    ILog.d('ServerConfigManager', `[HTTP服务器地址] 说明: 这是Gateway地址,端口应该是8080`);
     return url;
   }
   
   /**
    * 获取SocketIO服务器地址
+   * 从 IP:端口 中提取 IP,拼接 SocketIO 端口
    */
   static async getSocketIOUrl(): Promise<string> {
     const ip = await ServerConfigManager.getServerIp();
@@ -67,10 +104,10 @@ export class ServerConfigManager {
   }
   
   /**
-   * 重置为默认IP
+   * 重置为默认地址
    */
   static async resetToDefault(): Promise<void> {
-    await ServerConfigManager.setServerIp(ServerConfigManager.DEFAULT_SERVER_IP);
+    await ServerConfigManager.setServerAddress(ServerConfigManager.DEFAULT_SERVER_ADDRESS);
   }
 }
 

+ 134 - 0
base-common/src/main/ets/common/dialog/CascadePickerDialog.ets

@@ -0,0 +1,134 @@
+import { Context } from '@kit.AbilityKit';
+import { ILog } from '@xdz/base-core';
+
+const TAG = "CascadePickerDialog";
+
+/**
+ * 级联选择器数据项
+ */
+export interface CascadeData {
+  label: string;
+  value: string;
+  children?: CascadeData[];
+}
+
+/**
+ * 级联选择器对话框
+ * 
+ * 提供多级联动选择功能,常用于地址选择、分类选择等场景
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { CascadePickerDialog } from '@xdz/base-common';
+ * 
+ * const data: CascadeData[] = [
+ *   {
+ *     label: '北京',
+ *     value: 'beijing',
+ *     children: [
+ *       { label: '朝阳区', value: 'chaoyang' },
+ *       { label: '海淀区', value: 'haidian' }
+ *     ]
+ *   }
+ * ];
+ * 
+ * CascadePickerDialog.show(context, data, (result) => {
+ *   // 处理选择结果
+ * });
+ * ```
+ */
+export class CascadePickerDialog {
+  
+  /**
+   * 显示级联选择器对话框
+   * 
+   * @param context 上下文
+   * @param data 级联数据
+   * @param onSelected 选择回调
+   */
+  static show(
+    context: Context,
+    data: CascadeData[],
+    onSelected: (result: string[]) => void
+  ): void {
+    try {
+      // TODO: 使用 HarmonyOS CustomDialog 实现级联选择器
+      // 当前使用简化实现,直接返回第一级数据
+      ILog.w(TAG, "级联选择器对话框功能待实现,当前返回简化结果");
+      
+      // 简化实现:直接返回第一级数据
+      if (data.length > 0) {
+        onSelected([data[0].value]);
+      } else {
+        onSelected([]);
+      }
+    } catch (e) {
+      ILog.e(TAG, "显示级联选择器对话框失败", e as Error);
+    }
+  }
+  
+  /**
+   * 关闭级联选择器对话框
+   */
+  static dismiss(): void {
+    try {
+      // TODO: 实现关闭对话框功能
+      ILog.d(TAG, "关闭级联选择器对话框");
+    } catch (e) {
+      ILog.e(TAG, "关闭级联选择器对话框失败", e as Error);
+    }
+  }
+}
+
+/**
+ * 使用示例:
+ * 
+ * ```typescript
+ * // 准备数据
+ * const addressData: CascadeData[] = [
+ *   {
+ *     label: '北京市',
+ *     value: 'beijing',
+ *     children: [
+ *       {
+ *         label: '朝阳区',
+ *         value: 'chaoyang',
+ *         children: [
+ *           { label: '三里屯', value: 'sanlitun' },
+ *           { label: '国贸', value: 'guomao' }
+ *         ]
+ *       },
+ *       {
+ *         label: '海淀区',
+ *         value: 'haidian',
+ *         children: [
+ *           { label: '中关村', value: 'zhongguancun' },
+ *           { label: '五道口', value: 'wudaokou' }
+ *         ]
+ *       }
+ *     ]
+ *   },
+ *   {
+ *     label: '上海市',
+ *     value: 'shanghai',
+ *     children: [
+ *       {
+ *         label: '黄浦区',
+ *         value: 'huangpu',
+ *         children: [
+ *           { label: '外滩', value: 'waitan' },
+ *           { label: '南京路', value: 'nanjinglu' }
+ *         ]
+ *       }
+ *     ]
+ *   }
+ * ];
+ * 
+ * // 显示对话框
+ * CascadePickerDialog.show(context, addressData, (result) => {
+ *   // result 为选择的结果数组,如:['beijing', 'chaoyang', 'sanlitun']
+ *   // 处理选择结果
+ * });
+ * ```
+ */
+

+ 90 - 0
base-common/src/main/ets/common/dialog/ServerConfigDialog.ets

@@ -0,0 +1,90 @@
+import { Context } from '@kit.AbilityKit';
+import { ILog } from '@xdz/base-core';
+import { ServerConfigManager } from '../config/ServerConfigManager';
+
+const TAG = "ServerConfigDialog";
+
+/**
+ * 服务器配置数据
+ */
+export interface ServerConfig {
+  baseUrl: string;
+  socketUrl?: string;
+  apiVersion?: string;
+}
+
+/**
+ * 服务器配置对话框
+ * 
+ * 提供服务器配置的输入和修改功能,常用于开发环境切换服务器地址
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { ServerConfigDialog } from '@xdz/base-common';
+ * 
+ * ServerConfigDialog.show(context, (config) => {
+ *   // 保存配置
+ *   ServerConfigManager.setBaseUrl(config.baseUrl);
+ * });
+ * ```
+ */
+export class ServerConfigDialog {
+  
+  /**
+   * 显示服务器配置对话框
+   * 
+   * @param context 上下文
+   * @param onConfirm 确认回调
+   */
+  static async show(
+    context: Context,
+    onConfirm: (config: ServerConfig) => void
+  ): Promise<void> {
+    try {
+      // TODO: 使用 HarmonyOS 对话框 API 实现服务器配置对话框
+      // 当前使用简化实现,直接使用当前配置
+      ILog.w(TAG, "服务器配置对话框功能待实现,当前返回当前配置");
+      
+      // 简化实现:直接返回当前配置
+      const currentBaseUrl = await ServerConfigManager.getHttpServerUrl();
+      const currentSocketUrl = await ServerConfigManager.getSocketIOUrl();
+      const config: ServerConfig = {
+        baseUrl: currentBaseUrl || '',
+        socketUrl: currentSocketUrl || '',
+        apiVersion: 'v1'
+      };
+      
+      onConfirm(config);
+    } catch (e) {
+      ILog.e(TAG, "显示服务器配置对话框失败", e as Error);
+    }
+  }
+  
+  /**
+   * 关闭服务器配置对话框
+   */
+  static dismiss(): void {
+    try {
+      // TODO: 实现关闭对话框功能
+      ILog.d(TAG, "关闭服务器配置对话框");
+    } catch (e) {
+      ILog.e(TAG, "关闭服务器配置对话框失败", e as Error);
+    }
+  }
+}
+
+/**
+ * 使用示例:
+ * 
+ * ```typescript
+ * // 显示服务器配置对话框
+ * ServerConfigDialog.show(context, async (config) => {
+ *   // 保存配置
+ *   // TODO: 实现保存配置功能
+ *   // 注意:ServerConfigManager 使用 IP 地址,需要从 baseUrl 中提取 IP
+ *   // 重新初始化网络模块
+ *   // NetworkHelper.reinitialize();
+ * });
+ * ```
+ */
+

+ 147 - 0
base-common/src/main/ets/common/media/MediaPickerHelper.ets

@@ -0,0 +1,147 @@
+import { picker } from '@kit.CoreFileKit';
+import { Context } from '@kit.AbilityKit';
+import { LogHelper } from '../log/LogHelper';
+
+const TAG = "FilePickerHelper";
+
+/**
+ * 文件选择器助手
+ * 
+ * 统一封装文件选择功能,提供便捷的文件选择方式
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 选择单个文件
+ * MediaPickerHelper.pickFile(context, (fileUri) => {
+ *   // 处理选择的文件
+ * })
+ * 
+ * // 选择多个文件
+ * MediaPickerHelper.pickFiles(context, (fileUris) => {
+ *   // 处理选择的文件列表
+ * })
+ * 
+ * // 选择图片
+ * MediaPickerHelper.pickImage(context, (imageUri) => {
+ *   // 处理选择的图片
+ * })
+ * ```
+ */
+export class MediaPickerHelper {
+  /**
+   * 选择单个文件
+   * 
+   * @param context Context 实例
+   * @param onResult 选择结果回调,参数为文件 URI
+   * @param fileTypes 文件类型过滤(可选,如 ['image/*', 'application/pdf'])
+   */
+  static async pickFile(
+    context: Context,
+    onResult: (fileUri: string) => void,
+    fileTypes?: string[]
+  ): Promise<void> {
+    try {
+      const photoSelectOptions = new picker.PhotoSelectOptions();
+      photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
+      photoSelectOptions.maxSelectNumber = 1;
+      
+      const photoPicker = new picker.PhotoViewPicker();
+      const photoSelectResult = await photoPicker.select(photoSelectOptions);
+      
+      if (photoSelectResult && photoSelectResult.photoUris.length > 0) {
+        onResult(photoSelectResult.photoUris[0]);
+      }
+    } catch (e) {
+      LogHelper.e(TAG, `选择文件失败`, e as Error);
+    }
+  }
+  
+  /**
+   * 选择多个文件
+   * 
+   * @param context Context 实例
+   * @param onResult 选择结果回调,参数为文件 URI 数组
+   * @param maxCount 最大选择数量(默认 9)
+   * @param fileTypes 文件类型过滤(可选)
+   */
+  static async pickFiles(
+    context: Context,
+    onResult: (fileUris: string[]) => void,
+    maxCount: number = 9,
+    fileTypes?: string[]
+  ): Promise<void> {
+    try {
+      const photoSelectOptions = new picker.PhotoSelectOptions();
+      photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
+      photoSelectOptions.maxSelectNumber = maxCount;
+      
+      const photoPicker = new picker.PhotoViewPicker();
+      const photoSelectResult = await photoPicker.select(photoSelectOptions);
+      
+      if (photoSelectResult && photoSelectResult.photoUris.length > 0) {
+        onResult(photoSelectResult.photoUris);
+      }
+    } catch (e) {
+      LogHelper.e(TAG, `选择多个文件失败`, e as Error);
+    }
+  }
+  
+  /**
+   * 选择图片
+   * 
+   * @param context Context 实例
+   * @param onResult 选择结果回调,参数为图片 URI
+   */
+  static async pickImage(
+    context: Context,
+    onResult: (imageUri: string) => void
+  ): Promise<void> {
+    await MediaPickerHelper.pickFile(context, onResult, ['image/*']);
+  }
+  
+  /**
+   * 选择多个图片
+   * 
+   * @param context Context 实例
+   * @param onResult 选择结果回调,参数为图片 URI 数组
+   * @param maxCount 最大选择数量(默认 9)
+   */
+  static async pickImages(
+    context: Context,
+    onResult: (imageUris: string[]) => void,
+    maxCount: number = 9
+  ): Promise<void> {
+    await MediaPickerHelper.pickFiles(context, onResult, maxCount, ['image/*']);
+  }
+  
+  /**
+   * 选择视频
+   * 
+   * @param context Context 实例
+   * @param onResult 选择结果回调,参数为视频 URI
+   */
+  static async pickVideo(
+    context: Context,
+    onResult: (videoUri: string) => void
+  ): Promise<void> {
+    await MediaPickerHelper.pickFile(context, onResult, ['video/*']);
+  }
+  
+  /**
+   * 选择文档
+   * 
+   * @param context Context 实例
+   * @param onResult 选择结果回调,参数为文档 URI
+   */
+  static async pickDocument(
+    context: Context,
+    onResult: (documentUri: string) => void
+  ): Promise<void> {
+    await MediaPickerHelper.pickFile(context, onResult, [
+      'application/pdf',
+      'application/msword',
+      'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+    ]);
+  }
+}
+

+ 45 - 3
base-common/src/main/ets/common/network/ApiBaseRemoteDataSource.ets

@@ -2,6 +2,7 @@ import { NetworkManager, ILog } from '@xdz/base-core';
 import { NetworkHelper } from './NetworkHelper';
 import { LogHelper } from '../log/LogHelper';
 import { Result } from './ApiBaseRepository';
+import { ApiResponseParser, ApiCommonResult } from './ApiResponseParser';
 
 // 重新导出 Result 类型,方便其他模块使用
 export { Result };
@@ -42,7 +43,7 @@ export abstract class ApiBaseRemoteDataSource {
    * 
    * 自动处理:
    * - HTTP 错误码
-   * - 业务错误码
+   * - 业务错误码(401/402 会触发 Token 刷新)
    * - 网络异常
    * - 超时异常
    * - 日志记录
@@ -61,17 +62,42 @@ export abstract class ApiBaseRemoteDataSource {
       
       const response = await request();
       
+      // 检查响应是否是 ApiCommonResult 格式,如果是则检查业务错误码
+      if (this.isApiCommonResult(response)) {
+        const apiResponse = response as ApiCommonResult<T>;
+        // 检查业务错误码 401/402,调用 Token 刷新失败回调
+        if (apiResponse.code === 401 || apiResponse.code === 402) {
+          LogHelper.w(tag, `检测到业务错误码 ${apiResponse.code},调用 Token 刷新失败回调`);
+          if (NetworkHelper.getOnTokenRefreshFailed()) {
+            NetworkHelper.getOnTokenRefreshFailed()!();
+          }
+        }
+      }
+      
       LogHelper.d(tag, '请求成功');
       return Result.success(response);
     } catch (error) {
       const tag = this.getTag();
       let errorMsg = errorMessage;
       
+      // 直接使用 instanceof Error,ArkTS 禁止使用 in 运算符
       if (error instanceof Error) {
-        if (error.message.includes('timeout') || error.message.includes('超时')) {
+        const err = error;
+        // 检查是否是 401/402 错误
+        if (err.message.includes('401') || err.message.includes('402')) {
+          LogHelper.w(tag, '检测到 HTTP 401/402 错误,Token 刷新机制已在 NetworkManager 中处理');
+          // Token 刷新机制已在 NetworkManager 中处理,这里只需要记录日志
+        } else if (err.message.includes('timeout') || err.message.includes('超时')) {
           errorMsg = '请求超时,请检查网络连接';
-        } else if (error.message.includes('network') || error.message.includes('网络')) {
+        } else if (err.message.includes('network') || err.message.includes('网络') || 
+                   err.message.includes('ECONNREFUSED') || err.message.includes('ENOTFOUND') ||
+                   err.message.includes('timeout') || err.message.includes('ETIMEDOUT')) {
           errorMsg = '网络连接失败,请检查网络设置';
+          // 网络连接失败时,也调用 Token 刷新失败回调(参考 Android 版本)
+          if (NetworkHelper.getOnTokenRefreshFailed()) {
+            LogHelper.w(tag, '检测到网络连接失败,调用 Token 刷新失败回调');
+            NetworkHelper.getOnTokenRefreshFailed()!();
+          }
         } else {
           errorMsg = error.message || errorMessage;
         }
@@ -86,6 +112,22 @@ export abstract class ApiBaseRemoteDataSource {
   }
   
   /**
+   * 检查响应是否是 ApiCommonResult 格式
+   * 
+   * @param response 响应对象
+   * @returns true 如果是 ApiCommonResult 格式
+   */
+  private isApiCommonResult<T>(response: T): boolean {
+    if (response && typeof response === 'object') {
+      const obj = response as Record<string, Object>;
+      // ArkTS 不支持 'in' 操作符和 hasOwnProperty,使用 Object.keys() 检查
+      const keys = Object.keys(obj);
+      return keys.includes('code') && keys.includes('data') && keys.includes('msg');
+    }
+    return false;
+  }
+  
+  /**
    * 发送 HTTP 请求(封装 NetworkManager)
    * 
    * @param url 请求 URL(完整路径或相对路径)

+ 126 - 26
base-common/src/main/ets/common/network/ApiBaseService.ets

@@ -5,6 +5,20 @@ import { Result } from './ApiBaseRepository';
 import { LogHelper } from '../log/LogHelper';
 
 /**
+ * 查询参数基类(要求实现 toQueryString 方法,避免使用 JSON.parse + 动态key)
+ */
+export abstract class QueryParamsBase {
+  abstract toQueryString(): string;
+}
+
+/**
+ * 错误对象接口(用于类型安全地访问错误对象的 message 属性)
+ */
+interface ErrorLike {
+  message?: string;
+}
+
+/**
  * API 服务基类
  * 
  * 提供统一的 API 调用封装,减少重复代码
@@ -39,6 +53,19 @@ export abstract class ApiBaseService {
   }
   
   /**
+   * 将查询参数转换为 query string(避免使用 JSON.parse + 动态key)
+   */
+  private objToQueryString(params: QueryParamsBase | string | undefined): string {
+    if (!params) {
+      return '';
+    }
+    if (typeof params === 'string') {
+      return params;
+    }
+    return params.toQueryString();
+  }
+  
+  /**
    * GET 请求
    * 
    * @param path API 路径(相对路径)
@@ -48,16 +75,16 @@ export abstract class ApiBaseService {
    */
   protected async get<T>(
     path: string,
-    params?: Record<string, string>,
+    params?: QueryParamsBase | string,
     errorMessage: string = '请求失败'
   ): Promise<Result<T>> {
     try {
       let url = this.buildUrl(path);
       if (params) {
-        const queryString = Object.keys(params)
-          .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
-          .join('&');
-        url = `${url}?${queryString}`;
+        const qs = this.objToQueryString(params);
+        if (qs.length > 0) {
+          url = `${url}?${qs}`;
+        }
       }
       
       const headers = await NetworkHelper.getHeaders();
@@ -65,8 +92,20 @@ export abstract class ApiBaseService {
       
       return ApiResponseParser.handleResponse(response, errorMessage, this.constructor.name);
     } catch (error) {
-      LogHelper.e(this.constructor.name, `${errorMessage}: ${(error as Error).message}`, error as Error);
-      return Result.failure(error as Error);
+      // ✅ 修复:正确转换错误对象,保留原始错误信息
+      let err: Error;
+      if (error instanceof Error) {
+        err = error;
+      } else if (error && typeof error === 'object') {
+        // 如果是对象,尝试提取 message 属性或转换为字符串
+        const errorLike = error as ErrorLike;
+        const errorMsg = errorLike.message || String(error) || errorMessage;
+        err = new Error(errorMsg);
+      } else {
+        err = new Error(String(error) || errorMessage);
+      }
+      LogHelper.e(this.constructor.name, `${errorMessage}: ${err.message}`, err);
+      return Result.failure(err);
     }
   }
   
@@ -86,12 +125,38 @@ export abstract class ApiBaseService {
     try {
       const url = this.buildUrl(path);
       const headers = await NetworkHelper.getHeaders();
+      
+      // 打印完整的请求信息
+      LogHelper.d(this.constructor.name, `========== [POST请求] ==========`);
+      LogHelper.d(this.constructor.name, `[POST请求] baseURL: ${this.baseUrl}`);
+      LogHelper.d(this.constructor.name, `[POST请求] 相对路径: ${path}`);
+      LogHelper.d(this.constructor.name, `[POST请求] 完整URL: ${url}`);
+      if (data) {
+        const requestBody = JSON.stringify(data);
+        LogHelper.d(this.constructor.name, `[POST请求] 请求体: ${requestBody}`);
+      } else {
+        LogHelper.d(this.constructor.name, `[POST请求] 请求体: (无)`);
+      }
+      LogHelper.d(this.constructor.name, `[POST请求] 请求头: ${JSON.stringify(headers)}`);
+      
       const response = await this.networkManager.post<ApiCommonResult<T>>(url, data, headers);
       
       return ApiResponseParser.handleResponse(response, errorMessage, this.constructor.name);
     } catch (error) {
-      LogHelper.e(this.constructor.name, `${errorMessage}: ${(error as Error).message}`, error as Error);
-      return Result.failure(error as Error);
+      // ✅ 修复:正确转换错误对象,保留原始错误信息
+      let err: Error;
+      if (error instanceof Error) {
+        err = error;
+      } else if (error && typeof error === 'object') {
+        // 如果是对象,尝试提取 message 属性或转换为字符串
+        const errorLike = error as ErrorLike;
+        const errorMsg = errorLike.message || String(error) || errorMessage;
+        err = new Error(errorMsg);
+      } else {
+        err = new Error(String(error) || errorMessage);
+      }
+      LogHelper.e(this.constructor.name, `${errorMessage}: ${err.message}`, err);
+      return Result.failure(err);
     }
   }
   
@@ -110,8 +175,20 @@ export abstract class ApiBaseService {
       
       return ApiResponseParser.handleResponse(response, errorMessage, this.constructor.name);
     } catch (error) {
-      LogHelper.e(this.constructor.name, `${errorMessage}: ${(error as Error).message}`, error as Error);
-      return Result.failure(error as Error);
+      // ✅ 修复:正确转换错误对象,保留原始错误信息
+      let err: Error;
+      if (error instanceof Error) {
+        err = error;
+      } else if (error && typeof error === 'object') {
+        // 如果是对象,尝试提取 message 属性或转换为字符串
+        const errorLike = error as ErrorLike;
+        const errorMsg = errorLike.message || String(error) || errorMessage;
+        err = new Error(errorMsg);
+      } else {
+        err = new Error(String(error) || errorMessage);
+      }
+      LogHelper.e(this.constructor.name, `${errorMessage}: ${err.message}`, err);
+      return Result.failure(err);
     }
   }
   
@@ -120,16 +197,16 @@ export abstract class ApiBaseService {
    */
   protected async delete<T>(
     path: string,
-    params?: Record<string, string>,
+    params?: QueryParamsBase | string,
     errorMessage: string = '请求失败'
   ): Promise<Result<T>> {
     try {
       let url = this.buildUrl(path);
       if (params) {
-        const queryString = Object.keys(params)
-          .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
-          .join('&');
-        url = `${url}?${queryString}`;
+        const qs = this.objToQueryString(params);
+        if (qs.length > 0) {
+          url = `${url}?${qs}`;
+        }
       }
       
       const headers = await NetworkHelper.getHeaders();
@@ -137,8 +214,20 @@ export abstract class ApiBaseService {
       
       return ApiResponseParser.handleResponse(response, errorMessage, this.constructor.name);
     } catch (error) {
-      LogHelper.e(this.constructor.name, `${errorMessage}: ${(error as Error).message}`, error as Error);
-      return Result.failure(error as Error);
+      // ✅ 修复:正确转换错误对象,保留原始错误信息
+      let err: Error;
+      if (error instanceof Error) {
+        err = error;
+      } else if (error && typeof error === 'object') {
+        // 如果是对象,尝试提取 message 属性或转换为字符串
+        const errorLike = error as ErrorLike;
+        const errorMsg = errorLike.message || String(error) || errorMessage;
+        err = new Error(errorMsg);
+      } else {
+        err = new Error(String(error) || errorMessage);
+      }
+      LogHelper.e(this.constructor.name, `${errorMessage}: ${err.message}`, err);
+      return Result.failure(err);
     }
   }
   
@@ -150,16 +239,16 @@ export abstract class ApiBaseService {
   protected async postWithQuery<T>(
     path: string,
     data?: object,
-    queryParams?: Record<string, string>,
+    queryParams?: QueryParamsBase | string,
     errorMessage: string = '请求失败'
   ): Promise<Result<T>> {
     try {
       let url = this.buildUrl(path);
       if (queryParams) {
-        const queryString = Object.keys(queryParams)
-          .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(queryParams[key])}`)
-          .join('&');
-        url = `${url}?${queryString}`;
+        const qs = this.objToQueryString(queryParams);
+        if (qs.length > 0) {
+          url = `${url}?${qs}`;
+        }
       }
       
       const headers = await NetworkHelper.getHeaders();
@@ -167,9 +256,20 @@ export abstract class ApiBaseService {
       
       return ApiResponseParser.handleResponse(response, errorMessage, this.constructor.name);
     } catch (error) {
-      LogHelper.e(this.constructor.name, `${errorMessage}: ${(error as Error).message}`, error as Error);
-      return Result.failure(error as Error);
+      // ✅ 修复:正确转换错误对象,保留原始错误信息
+      let err: Error;
+      if (error instanceof Error) {
+        err = error;
+      } else if (error && typeof error === 'object') {
+        // 如果是对象,尝试提取 message 属性或转换为字符串
+        const errorLike = error as ErrorLike;
+        const errorMsg = errorLike.message || String(error) || errorMessage;
+        err = new Error(errorMsg);
+      } else {
+        err = new Error(String(error) || errorMessage);
+      }
+      LogHelper.e(this.constructor.name, `${errorMessage}: ${err.message}`, err);
+      return Result.failure(err);
     }
   }
 }
-

+ 40 - 8
base-common/src/main/ets/common/network/ApiResponseParser.ets

@@ -1,13 +1,20 @@
 import { LogHelper } from '../log/LogHelper';
 import { Result } from './ApiBaseRepository';
+import { AppError, AppErrorRaw } from '@xdz/base-core';
 
 /**
- * API 通用响应结构
+ * API 通用响应结构(使用 class 避免 ArkTS 结构化类型限制)
  */
-export interface ApiCommonResult<T> {
+export class ApiCommonResult<T> {
   code: number;
   data: T;
   msg: string;
+
+  constructor(code: number, data: T, msg: string) {
+    this.code = code;
+    this.data = data;
+    this.msg = msg;
+  }
 }
 
 /**
@@ -49,15 +56,17 @@ export class ApiResponseParser {
         LogHelper.d(tag, '请求成功');
         return Result.success(response.data);
       } else {
-        const error = new Error('响应数据为空');
+        const errorContext = `code:${response.code},msg:${response.msg || ''}`;
+        const appError: AppError = AppError.parse('响应数据为空', errorContext);
         LogHelper.e(tag, `${errorMessage}: 响应数据为空`);
-        return Result.failure(error);
+        return Result.failure(appError as Error);
       }
     } else {
       const errorMsg = response.msg || errorMessage;
-      const error = new Error(errorMsg);
+      const errorContext = `code:${response.code},msg:${errorMsg}`;
+      const appError: AppError = AppError.biz(errorMsg, response.code, errorContext);
       LogHelper.e(tag, `${errorMessage}: ${errorMsg} (code: ${response.code})`);
-      return Result.failure(error);
+      return Result.failure(appError as Error);
     }
   }
   
@@ -81,9 +90,10 @@ export class ApiResponseParser {
       return Result.success(response.data ?? null);
     } else {
       const errorMsg = response.msg || errorMessage;
-      const error = new Error(errorMsg);
+      const errorContext = `code:${response.code},msg:${errorMsg}`;
+      const appError: AppError = AppError.biz(errorMsg, response.code, errorContext);
       LogHelper.e(tag, `${errorMessage}: ${errorMsg} (code: ${response.code})`);
-      return Result.failure(error);
+      return Result.failure(appError as Error);
     }
   }
   
@@ -100,5 +110,27 @@ export class ApiResponseParser {
   static getErrorMessage<T>(response: ApiCommonResult<T>, defaultMessage: string = '请求失败'): string {
     return response.msg || defaultMessage;
   }
+  /**
+   * 将请求过程中的异常归一为 AppError(3.1.2 网络层)
+   * 用于 ApiBaseService catch:超时/网络/解析统一输出 AppError
+   */
+  static toAppError(raw: AppErrorRaw, fallbackMessage: string = '请求失败'): AppError {
+    // 已经是 AppError 的情况
+    if (raw instanceof AppError) {
+      return raw;
+    }
+
+    // 将原始错误统一包装为 Error,再基于 message 判断类型
+    const err = raw instanceof Error ? raw : new Error(String(raw));
+    const msg = err.message || fallbackMessage;
+
+    if (/timeout|timed out|ETIMEDOUT/i.test(msg)) {
+      return AppError.timeout(msg, raw);
+    }
+    if (/network|fetch|ECONNREFUSED|ENOTFOUND/i.test(msg)) {
+      return AppError.network(msg, raw);
+    }
+    return AppError.network(msg, raw);
+  }
 }
 

+ 52 - 1
base-common/src/main/ets/common/network/NetworkHelper.ets

@@ -1,5 +1,7 @@
 import { NetworkManager } from '@xdz/base-core';
-import { TokenStore } from '../auth/storage/TokenStore';
+// TokenStore 已迁移到 entry 模块
+// TODO: 后续改为依赖注入方式,避免 base-common 直接依赖 entry 模块
+// 临时方案:通过 tokenProvider 回调获取 Token,不直接导入 TokenStore
 import { LogHelper } from '../log/LogHelper';
 
 /**
@@ -24,6 +26,8 @@ import { LogHelper } from '../log/LogHelper';
  */
 export class NetworkHelper {
   private static tokenProvider: (() => Promise<string | null>) | null = null;
+  private static refreshTokenProvider: (() => Promise<string | null>) | null = null;
+  private static onTokenRefreshFailed: (() => void) | null = null;
   private static baseUrl: string = '';
   private static isDebug: boolean = false;
   
@@ -53,6 +57,9 @@ export class NetworkHelper {
    */
   static setTokenProvider(tokenProvider: () => Promise<string | null>): void {
     NetworkHelper.tokenProvider = tokenProvider;
+    // 同时设置到 NetworkManager(用于 Token 刷新后重试请求)
+    NetworkManager.tokenProvider = tokenProvider;
+    LogHelper.d('NetworkHelper', 'Token 提供器已设置');
   }
   
   /**
@@ -86,5 +93,49 @@ export class NetworkHelper {
     
     return headers;
   }
+  
+  /**
+   * 设置 Token 刷新提供器
+   * 
+   * 用于自动刷新过期的 Token
+   * 当请求返回 401/402 时,会自动调用此方法刷新 Token
+   * 
+   * @param refreshTokenProvider Token 刷新提供器,返回新的 accessToken
+   */
+  static setRefreshTokenProvider(refreshTokenProvider: () => Promise<string | null>): void {
+    NetworkHelper.refreshTokenProvider = refreshTokenProvider;
+    // 同时设置到 NetworkManager
+    NetworkManager.refreshTokenProvider = refreshTokenProvider;
+    LogHelper.d('NetworkHelper', 'Token 刷新提供器已设置');
+  }
+  
+  /**
+   * 设置 Token 刷新失败回调
+   * 
+   * 当 Token 刷新失败时,会自动调用此回调
+   * 可以在 AppInitializer 中设置,实现跳转登录界面
+   * 
+   * @param onTokenRefreshFailed Token 刷新失败回调
+   */
+  static setOnTokenRefreshFailed(onTokenRefreshFailed: () => void): void {
+    NetworkHelper.onTokenRefreshFailed = onTokenRefreshFailed;
+    // 同时设置到 NetworkManager
+    NetworkManager.onTokenRefreshFailed = onTokenRefreshFailed;
+    LogHelper.d('NetworkHelper', 'Token 刷新失败回调已设置');
+  }
+  
+  /**
+   * 获取 Token 刷新提供器
+   */
+  static getRefreshTokenProvider(): (() => Promise<string | null>) | null {
+    return NetworkHelper.refreshTokenProvider;
+  }
+  
+  /**
+   * 获取 Token 刷新失败回调
+   */
+  static getOnTokenRefreshFailed(): (() => void) | null {
+    return NetworkHelper.onTokenRefreshFailed;
+  }
 }
 

+ 357 - 0
base-common/src/main/ets/common/router/ARouter.ets

@@ -0,0 +1,357 @@
+import { HMRouterMgr } from '@hadss/hmrouter';
+import { LogHelper } from '../log/LogHelper';
+import { StorageManager } from '../storage/StorageManager';
+import { StorageKeys } from '@xdz/base-core';
+import { RouteConfig } from './RouteConfig';
+import { AuthGuardHolder } from '../auth/AuthGuardHolder';
+
+/**
+ * HarmonyOS ARouter - 简化版路由框架
+ *
+ * 模仿 Android ARouter 的使用方式
+ *
+ * 使用方式:
+ * ```typescript
+ * // 1. 配置路由路径(在页面上)
+ * @Route("/app/main")
+ * export struct MainPage {
+ *   @Inject("title") title: string = "";
+ *
+ *   aboutToAppear() {
+ *     ARouter.inject(this); // 自动注入参数
+ *   }
+ * }
+ *
+ * // 2. 跳转
+ * ARouter.build("/app/main").navigation();
+ * ARouter.build("/app/main").withString("title", "首页").navigation();
+ * ```
+ */
+
+// ========== 注解定义 ==========
+
+/**
+ * 路由注解(装饰器)
+ * 在页面类上使用
+ * 
+ * 使用配置键而不是路径字符串:
+ * @Route("AUTH_LOGIN")
+ */
+export function Route(routeKey: string) {
+  return (target: ESObject) => {
+    // 从配置中心获取逻辑路径和文件路径
+    const path = RouteConfig.getPath(routeKey);
+    const filePath = RouteConfig.getFilePath(routeKey);
+    
+    if (!path || !filePath) {
+      LogHelper.e('Route', `路由配置未找到: ${routeKey}`);
+      return;
+    }
+    
+    // 注册路由(使用逻辑路径作为键)
+    ARouter.register(path, target);
+    
+    // 保存文件路径映射(用于跳转)
+    ARouter.registerFilePath(path, filePath);
+    
+    LogHelper.d('Route', `注册路由: ${routeKey} -> ${path} -> ${filePath}`);
+  };
+}
+
+/**
+ * 参数注入注解(装饰器)
+ * 在页面属性上使用
+ */
+export function Inject(key: string, defaultValue?: ESObject) {
+  return (target: ESObject, propertyKey: string) => {
+    // 注册注入信息
+    const injectInfo = ARouter.getInjectInfo(target.constructor as ESObject) || [];
+    injectInfo.push({ propertyKey, key, defaultValue });
+    ARouter.setInjectInfo(target.constructor as ESObject, injectInfo);
+  };
+}
+
+// ========== 核心类 ==========
+
+/**
+ * 路由构建器(类似 Android ARouter 的 build() 返回的对象)
+ */
+export class Postcard {
+  private readonly filePath: string;  // 文件路径(已废弃,保留用于兼容)
+  private readonly routeKey: string;  // 配置键(用于拦截器)
+  private params: Record<string, ESObject> = {};
+  private skipInterceptors: boolean = false;
+
+  constructor(filePath: string, routeKey: string) {
+    this.filePath = filePath;
+    this.routeKey = routeKey;
+  }
+
+  /**
+   * 统一参数传递(2.2.1):根据 value 类型写入,推荐业务使用
+   */
+  withParam(key: string, value: string | number | boolean | ESObject): Postcard {
+    this.params[key] = value as ESObject;
+    return this;
+  }
+
+  /**
+   * 传递字符串参数
+   */
+  withString(key: string, value: string): Postcard {
+    this.params[key] = value;
+    return this;
+  }
+
+  /**
+   * 传递数字参数
+   */
+  withInt(key: string, value: number): Postcard {
+    this.params[key] = value;
+    return this;
+  }
+
+  /**
+   * 传递布尔参数
+   */
+  withBoolean(key: string, value: boolean): Postcard {
+    this.params[key] = value;
+    return this;
+  }
+
+  /**
+   * 传递对象参数
+   */
+  withObject(key: string, value: ESObject): Postcard {
+    this.params[key] = value;
+    return this;
+  }
+
+  /**
+   * 跳过拦截器
+   */
+  skipInterceptor(): Postcard {
+    this.skipInterceptors = true;
+    return this;
+  }
+
+  /**
+   * 执行跳转
+   */
+  async navigation(): Promise<void> {
+    // 检查拦截器(使用配置键)
+    if (!this.skipInterceptors) {
+      const canNavigate = await ARouter.checkInterceptors(this.routeKey, this.params);
+      if (!canNavigate) {
+        return;
+      }
+    }
+
+    // ✅ 使用 HMRouterMgr.push() 显式指定 navigationId
+    // MainView 内部使用 HMNavigation,所有页面都在 mainNavigation 上下文中
+    try {
+      await HMRouterMgr.push({
+        navigationId: 'mainNavigation',
+        pageUrl: this.routeKey,
+        param: Object.keys(this.params).length > 0 ? this.params as ESObject : undefined
+      });
+      LogHelper.d('ARouter', `跳转成功: ${this.routeKey}`);
+    } catch (error) {
+      LogHelper.e('ARouter', `跳转失败: ${this.routeKey}`, error as Error);
+      // ✅ 修复:重新抛出错误,让调用方知道跳转失败(ArkTS 要求必须是 Error 类型)
+      if (error instanceof Error) {
+        throw error;
+      } else {
+        throw new Error(String(error));
+      }
+    }
+  }
+}
+
+/**
+ * ARouter 核心类
+ */
+/**
+ * 注入信息接口
+ */
+interface InjectInfo {
+  propertyKey: string;
+  key: string;
+  defaultValue?: ESObject;
+}
+
+/**
+ * 拦截器函数类型
+ */
+type InterceptorFunction = (routeKey: string, params: Record<string, ESObject>) => boolean | Promise<boolean>;
+
+export class ARouter {
+  private static readonly TAG = 'ARouter';
+  private static routes: Map<string, ESObject> = new Map();
+  private static pathMap: Map<string, string> = new Map(); // 逻辑路径 -> 文件路径映射
+  private static injectInfos: Map<ESObject, Array<InjectInfo>> = new Map();
+  private static interceptors: Array<InterceptorFunction> = [];
+
+  /**
+   * 初始化 ARouter
+   */
+  static init(): void {
+    // 注册默认拦截器(使用配置键)
+    ARouter.addInterceptor(async (routeKey: string, params: Record<string, ESObject>) => {
+      if (RouteConfig.needLogin(routeKey)) {
+        const guard = AuthGuardHolder.getGuard();
+        const isLogin = guard ? await guard.isLoggedIn() : await StorageManager.getBoolean(StorageKeys.APP_IS_LOGIN, false);
+        if (!isLogin) {
+          // 未登录,跳转到登录页
+          await ARouter.build("AUTH_LOGIN")
+            .withString("targetRoute", routeKey)
+            .skipInterceptor()
+            .navigation();
+          return false;
+        }
+      }
+      return true;
+    });
+
+    LogHelper.d(ARouter.TAG, 'ARouter 初始化完成');
+  }
+
+  /**
+   * 注册文件路径映射
+   */
+  static registerFilePath(logicPath: string, filePath: string): void {
+    ARouter.pathMap.set(logicPath, filePath);
+  }
+
+  /**
+   * 构建路由(使用配置键)
+   * 
+   * @param routeKey 路由配置键(如 "AUTH_LOGIN")
+   * @returns Postcard 实例
+   */
+  static build(routeKey: string): Postcard {
+    // 先从配置中心获取文件路径
+    let filePath = RouteConfig.getFilePath(routeKey);
+    
+    // 如果配置中心没有,尝试从路径映射表获取(向后兼容)
+    if (!filePath) {
+      const logicPath = RouteConfig.getPath(routeKey);
+      if (logicPath) {
+        filePath = ARouter.pathMap.get(logicPath) || logicPath;
+      } else {
+        // 如果都没有,可能是直接传入的路径字符串(向后兼容)
+        filePath = routeKey;
+        LogHelper.w(ARouter.TAG, `使用路径字符串作为文件路径: ${routeKey}`);
+      }
+    }
+    
+    if (!filePath) {
+      LogHelper.e(ARouter.TAG, `路由未找到: ${routeKey}`);
+      throw new Error(`Route not found: ${routeKey}`);
+    }
+    
+    return new Postcard(filePath, routeKey);
+  }
+
+  /**
+   * 注册路由
+   */
+  static register(path: string, target: ESObject): void {
+    ARouter.routes.set(path, target);
+    LogHelper.d(ARouter.TAG, `注册路由: ${path}`);
+  }
+
+  /**
+   * 添加拦截器
+   */
+  static addInterceptor(interceptor: InterceptorFunction): void {
+    ARouter.interceptors.push(interceptor);
+  }
+
+  /**
+   * 检查拦截器
+   */
+  static async checkInterceptors(routeKey: string, params: Record<string, ESObject>): Promise<boolean> {
+    for (const interceptor of ARouter.interceptors) {
+      try {
+        const result = await interceptor(routeKey, params);
+        if (!result) {
+          return false;
+        }
+      } catch (error) {
+        LogHelper.e(ARouter.TAG, '拦截器执行出错', error as Error);
+      }
+    }
+    return true;
+  }
+
+  /**
+   * 参数注入
+   */
+  static inject(target: ESObject): void {
+    const params = HMRouterMgr.getCurrentParam() as Record<string, ESObject> | undefined;
+    if (!params) {
+      return;
+    }
+
+    const injectInfo = ARouter.getInjectInfo(target.constructor as ESObject);
+    if (!injectInfo) {
+      return;
+    }
+
+    for (const info of injectInfo) {
+      const value: ESObject | undefined = params[info.key];
+      if (value !== undefined) {
+        (target as Record<string, ESObject>)[info.propertyKey] = value;
+      } else if (info.defaultValue !== undefined) {
+        (target as Record<string, ESObject>)[info.propertyKey] = info.defaultValue;
+      }
+    }
+
+    LogHelper.d(ARouter.TAG, `参数注入完成`);
+  }
+
+  /**
+   * 获取注入信息
+   */
+  static getInjectInfo(target: ESObject): Array<InjectInfo> | undefined {
+    return ARouter.injectInfos.get(target);
+  }
+
+  /**
+   * 设置注入信息
+   */
+  static setInjectInfo(target: ESObject, info: Array<InjectInfo>): void {
+    ARouter.injectInfos.set(target, info);
+  }
+
+  // ========== 常用路由方法 ==========
+
+  /**
+   * 跳转到登录页
+   */
+  static toLogin(): Postcard {
+    return ARouter.build("AUTH_LOGIN");
+  }
+
+  /**
+   * 跳转到主界面
+   */
+  static toMain(): Postcard {
+    return ARouter.build("APP_MAIN");
+  }
+
+  /**
+   * 跳转到帖子详情
+   */
+  static toPostDetail(postId: number): Postcard {
+    return ARouter.build("COMMUNITY_POST_DETAIL").withInt("postId", postId);
+  }
+
+  /**
+   * 跳转到个人资料页
+   */
+  static toProfile(): Postcard {
+    return ARouter.build("USER_PERSONAL_INFO");
+  }
+}

+ 150 - 0
base-common/src/main/ets/common/router/ARouterExample.ets

@@ -0,0 +1,150 @@
+/**
+ * ARouter 使用示例
+ *
+ * 展示如何像 Android ARouter 一样使用 HarmonyOS ARouter
+ */
+
+import { ARouter, Route, Inject, Postcard } from './ARouter';
+import { RouteConstants } from './RouteConstants';
+
+/**
+ * 示例页面 1:主界面
+ */
+@Route(RouteConstants.APP_MAIN)
+@Component
+export struct MainPage {
+  @Inject("title") @State title: string = "首页";
+  @Inject("userId") @State userId: number = 0;
+
+  aboutToAppear() {
+    // 自动注入参数,就像 Android ARouter 的 @Autowired
+    ARouter.inject(this);
+  }
+
+  build() {
+    Column() {
+      Text(this.title)
+        .fontSize(24)
+        .margin({ top: 50 })
+
+      Text(`用户ID: ${this.userId}`)
+        .fontSize(16)
+        .margin({ top: 20 })
+
+      Button("跳转到帖子详情")
+        .margin({ top: 30 })
+        .onClick(() => {
+          // 像 Android ARouter 一样跳转
+          ARouter.build(RouteConstants.COMMUNITY_POST_DETAIL)
+            .withInt("postId", 123)
+            .withString("from", "main")
+            .navigation();
+        })
+
+      Button("跳转到个人资料")
+        .margin({ top: 20 })
+        .onClick(() => {
+          // 简化调用
+          ARouter.toProfile().navigation();
+        })
+
+      Button("跳转到占位页面")
+        .margin({ top: 20 })
+        .onClick(() => {
+          ARouter.build(RouteConstants.USER_SIMPLE_PLACEHOLDER)
+            .withString("title", "测试页面")
+            .navigation();
+        })
+    }
+    .width('100%')
+    .height('100%')
+  }
+}
+
+/**
+ * 示例页面 2:帖子详情页
+ */
+@Route(RouteConstants.COMMUNITY_POST_DETAIL)
+@Entry
+@Component
+export struct PostDetailPage {
+  @Inject("postId") @State postId: number = 0;
+  @Inject("from") @State from: string = "";
+
+  aboutToAppear() {
+    ARouter.inject(this);
+  }
+
+  build() {
+    Column() {
+      Text("帖子详情")
+        .fontSize(24)
+        .margin({ top: 50 })
+
+      Text(`帖子ID: ${this.postId}`)
+        .fontSize(16)
+        .margin({ top: 20 })
+
+      Text(`来源: ${this.from}`)
+        .fontSize(16)
+        .margin({ top: 10 })
+
+      Button("返回")
+        .margin({ top: 30 })
+        .onClick(() => {
+          HMRouterMgr.popAsync();
+        })
+    }
+    .width('100%')
+    .height('100%')
+  }
+}
+
+/**
+ * 使用示例类
+ */
+export class ARouterUsageExample {
+
+  /**
+   * 基本跳转
+   */
+  static basicNavigation() {
+    // 跳转到主界面
+    ARouter.build("/app/main").navigation();
+
+    // 跳转到主界面并传参数
+    ARouter.build("/app/main")
+      .withString("title", "我的首页")
+      .withInt("userId", 12345)
+      .navigation();
+  }
+
+  /**
+   * 使用便捷方法
+   */
+  static convenientNavigation() {
+    // 使用便捷方法跳转
+    ARouter.toLogin().navigation();
+    ARouter.toMain().navigation();
+    ARouter.toProfile().navigation();
+    ARouter.toPostDetail(123).navigation();
+  }
+
+  /**
+   * 跳过拦截器
+   */
+  static skipInterceptors() {
+    // 跳过拦截器直接跳转(用于登录页等特殊页面)
+    ARouter.build("/auth/login")
+      .skipInterceptors()
+      .navigation();
+  }
+
+  /**
+   * 页面中的参数注入
+   */
+  static pageInjection() {
+    // 在页面的 aboutToAppear 中调用
+    // ARouter.inject(this);
+  }
+}

+ 44 - 72
base-common/src/main/ets/common/router/NavigationHelper.ets

@@ -1,69 +1,52 @@
-import { router } from '@kit.ArkUI';
+import { HMRouterMgr } from '@hadss/hmrouter';
+import { RouterManager, getRouteKeyFromPath } from './RouterManager';
+import { LogHelper } from '../log/LogHelper';
 
 /**
- * ⚠️ 警告:此文件使用了已弃用的API
+ * ⚠️ 警告:此文件已废弃,请使用 RouterManager
  * 
- * 已弃用的API:
- * - router.pushUrl (已弃用,建议使用新API)
- * - router.back (已弃用,建议使用新API)
- * - router.replaceUrl (已弃用,建议使用新API)
- * - router.clear (已弃用,建议使用新API)
+ * 此文件保留了向后兼容性,但所有新代码应该使用 RouterManager
  * 
- * TODO: 需要迁移到HarmonyOS新版本的Router API
- * 建议参考HarmonyOS官方文档了解新API的替代方案
+ * @deprecated 请使用 RouterManager 代替
  * 
- * 风险:
- * - 这些API可能在未来的HarmonyOS版本中被移除
- * - 建议尽快迁移到新API以确保兼容性
- */
-
-/**
- * 路由导航管理器
- * 
- * 统一封装路由跳转,提供便捷的路由调用方式
- * 
- * ⚠️ 注意:此工具类使用了已弃用的API,建议迁移到新API
- * 
- * 使用方式:
+ * 迁移指南:
  * ```typescript
- * // 基础跳转
- * NavigationHelper.navigate("pages/UserProfile");
+ * // 旧代码(不推荐)
+ * NavigationHelper.navigate("pages/LoginPage");
  * 
- * // 带参数跳转
- * NavigationHelper.navigate("pages/UserProfile", {
- *   userId: "123",
- *   userName: "张三"
- * });
- * 
- * // 带结果回调跳转
- * const result = await NavigationHelper.navigateForResult("pages/UserSelect", {
- *   type: "user"
- * });
+ * // 新代码(推荐)
+ * RouterManager.navigateToLogin();
  * ```
  */
 export class NavigationHelper {
   /**
    * 基础跳转
    * 
-   * ⚠️ 注意:使用了已弃用的 router.pushUrl API
-   * TODO: 需要迁移到HarmonyOS新版本的Router API
+   * ⚠️ 已废弃:请使用 RouterManager 代替
+   * 
+   * @deprecated 请使用 RouterManager.navigateToXXX() 方法代替
    * 
    * @param path 路由路径
    * @param params 参数(可选)
    */
   static navigate(path: string, params?: Record<string, Object>): void {
-    const routerOptions: router.RouterOptions = {
-      url: path,
-      params: params
-    };
-    router.pushUrl(routerOptions).catch((error: Error) => {
-      console.error('NavigationHelper', `跳转失败: ${path}`, error);
+    const pageUrl = getRouteKeyFromPath(path);
+    const builder = HMRouterMgr.to(pageUrl);
+    if (params) {
+      builder.withParam(params as ESObject);
+    }
+    builder.pushAsync().catch((error: Error) => {
+      LogHelper.e('NavigationHelper', `跳转失败: ${path}`, error);
     });
   }
   
   /**
    * 带结果回调跳转
    * 
+   * ⚠️ 已废弃:请使用 RouterManager 代替
+   * 
+   * @deprecated 请使用 RouterManager.navigateToXXX() 方法代替
+   * 
    * @param path 路由路径
    * @param params 参数(可选)
    * @returns Promise<Object> 返回结果
@@ -73,19 +56,18 @@ export class NavigationHelper {
     params?: Record<string, Object>
   ): Promise<Object> {
     return new Promise((resolve, reject) => {
-      const routerOptions: router.RouterOptions = {
-        url: path,
-        params: params
-      };
-      // 使用已弃用的API,待迁移
-      router.pushUrl(routerOptions).then(() => {
-        // HarmonyOS 路由暂不支持结果回调,返回空对象
+      const pageUrl = getRouteKeyFromPath(path);
+      const builder = HMRouterMgr.to(pageUrl);
+      if (params) {
+        builder.withParam(params as ESObject);
+      }
+      builder.pushAsync().then(() => {
         interface EmptyResult {
         }
         const emptyResult: EmptyResult = {};
         resolve(emptyResult as Object);
       }).catch((error: Error) => {
-        console.error('NavigationHelper', `跳转失败: ${path}`, error);
+        LogHelper.e('NavigationHelper', `跳转失败: ${path}`, error);
         reject(error);
       });
     });
@@ -94,52 +76,42 @@ export class NavigationHelper {
   /**
    * 返回上一页
    * 
-   * ⚠️ 注意:使用了已弃用的 router.back API
-   * TODO: 需要迁移到HarmonyOS新版本的Router API
+   * ⚠️ 已废弃:请使用 RouterManager.back() 代替
+   * 
+   * @deprecated 请使用 RouterManager.back() 方法代替
    * 
    * @param result 返回结果(可选,HarmonyOS 暂不支持)
    */
   static back(result?: Object): void {
-    router.back();
+    RouterManager.back();
   }
   
   /**
    * 替换当前页面
    * 
-   * ⚠️ 注意:使用了已弃用的 router.replaceUrl API
-   * TODO: 需要迁移到HarmonyOS新版本的Router API
+   * ⚠️ 已废弃:请使用 RouterManager.replace() 代替
+   * 
+   * @deprecated 请使用 RouterManager.replace() 方法代替
    * 
    * @param path 路由路径
    * @param params 参数(可选)
    */
   static replace(path: string, params?: Record<string, Object>): void {
-    const routerOptions: router.RouterOptions = {
-      url: path,
-      params: params
-    };
-    router.replaceUrl(routerOptions).catch((error: Error) => {
-      console.error('NavigationHelper', `替换页面失败: ${path}`, error);
-    });
+    RouterManager.replace(path, params);
   }
   
   /**
    * 清空路由栈并跳转
    * 
-   * ⚠️ 注意:使用了已弃用的 router.clear 和 router.pushUrl API
-   * TODO: 需要迁移到HarmonyOS新版本的Router API
+   * ⚠️ 已废弃:请使用 RouterManager.clearStack() 代替
+   * 
+   * @deprecated 请使用 RouterManager.clearStack() 方法代替
    * 
    * @param path 路由路径
    * @param params 参数(可选)
    */
   static clearStack(path: string, params?: Record<string, Object>): void {
-    router.clear();
-    const routerOptions: router.RouterOptions = {
-      url: path,
-      params: params
-    };
-    router.pushUrl(routerOptions).catch((error: Error) => {
-      console.error('NavigationHelper', `清空栈并跳转失败: ${path}`, error);
-    });
+    RouterManager.clearStack(path, params);
   }
 }
 

+ 207 - 0
base-common/src/main/ets/common/router/RouteConfig.ets

@@ -0,0 +1,207 @@
+import { LogHelper } from '../log/LogHelper';
+
+/**
+ * 路由配置项类
+ */
+export class RouteConfigItem {
+  /** 逻辑路径(用于注解和路由标识) */
+  path: string;
+  
+  /** 文件路径(用于 HMRouterMgr.to() 的 pageUrl) */
+  filePath: string;
+  
+  /** 是否需要登录 */
+  needLogin: boolean;
+  
+  /** 路由描述(可选) */
+  description?: string;
+  
+  constructor(path: string, filePath: string, needLogin: boolean, description?: string) {
+    this.path = path;
+    this.filePath = filePath;
+    this.needLogin = needLogin;
+    this.description = description;
+  }
+}
+
+/**
+ * 路由配置中心
+ * 
+ * 统一管理所有路由配置,避免硬编码路径
+ * 
+ * 使用方式:
+ * ```typescript
+ * // 获取文件路径
+ * const filePath = RouteConfig.getFilePath("AUTH_LOGIN");
+ * 
+ * // 获取逻辑路径
+ * const path = RouteConfig.getPath("AUTH_LOGIN");
+ * 
+ * // 检查是否需要登录
+ * const needLogin = RouteConfig.needLogin("USER_PROFILE");
+ * ```
+ */
+export class RouteConfig {
+  private static readonly TAG = 'RouteConfig';
+  
+  /**
+   * 路由配置字典
+   * 
+   * 所有路由路径在这里统一配置
+   */
+  private static _routes: Record<string, RouteConfigItem> | null = null;
+  
+  /**
+   * 初始化路由配置
+   */
+  private static initRoutes(): void {
+    RouteConfig._routes = {} as Record<string, RouteConfigItem>;
+    const routes = RouteConfig._routes;
+    
+    // ========== 应用主界面 ==========
+    // 注意:这里指向的是路由页 MainPage(内部再渲染 MainView)
+    routes['APP_MAIN'] = new RouteConfigItem("/app/main", "pages/MainPage", false, "主界面");
+    
+    // ========== 认证模块 ==========
+    routes['AUTH_LOGIN'] = new RouteConfigItem("/auth/login", "modules/auth/pages/LoginPage", false, "登录界面");
+    routes['AUTH_REGISTER'] = new RouteConfigItem("/auth/register", "modules/auth/pages/RegisterPage", false, "注册界面");
+    routes['AUTH_VERIFY_CODE_LOGIN'] = new RouteConfigItem("/auth/verify-code-login", "modules/auth/pages/VerifyCodeLoginPage", false, "验证码登录界面");
+    routes['AUTH_PASSWORD_LOGIN'] = new RouteConfigItem("/auth/password-login", "modules/auth/pages/PasswordLoginPage", false, "密码登录界面");
+    routes['AUTH_FORGOT_PASSWORD'] = new RouteConfigItem("/auth/forgot-password", "modules/auth/pages/ForgotPasswordPage", false, "忘记密码界面");
+    routes['AUTH_THIRD_PARTY_BINDING'] = new RouteConfigItem("/auth/third-party-binding", "modules/auth/pages/ThirdPartyBindingPage", false, "第三方登录绑定手机号页面");
+    routes['AUTH_RESET_PASSWORD'] = new RouteConfigItem("/auth/reset-password", "modules/auth/pages/ResetPasswordPage", true, "重置密码");
+    
+    // ========== 社区模块 ==========
+    routes['COMMUNITY_POST_DETAIL'] = new RouteConfigItem("/community/post-detail", "modules/community/pages/PostDetailPage", false, "帖子详情页");
+    routes['COMMUNITY_CREATE_POST'] = new RouteConfigItem("/community/create-post", "modules/community/pages/CreatePostPage", true, "发帖页");
+    
+    // ========== 用户模块 ==========
+    routes['USER_PERSONAL_INFO'] = new RouteConfigItem("/user/personal-info", "modules/user/pages/PersonalInfoPage", true, "个人资料页");
+    routes['USER_SETTINGS'] = new RouteConfigItem("/user/settings", "modules/user/pages/SettingsPage", true, "设置页");
+    routes['USER_ACCOUNT_MANAGE'] = new RouteConfigItem("/user/account-manage", "modules/user/pages/AccountManagePage", true, "账号管理页");
+    routes['USER_MESSAGE_LIST'] = new RouteConfigItem("/user/message-list", "modules/user/pages/MessageListPage", true, "我的消息页");
+    routes['USER_COLLECT_LIST'] = new RouteConfigItem("/user/collect-list", "modules/user/pages/CollectListPage", true, "我的收藏页");
+    routes['USER_VEHICLE_LIST'] = new RouteConfigItem("/user/vehicle-list", "modules/user/pages/VehicleListPage", true, "我的车辆页");
+    routes['USER_ORDER_LIST'] = new RouteConfigItem("/user/order-list", "modules/user/pages/OrderListPage", true, "我的订单页");
+    routes['USER_ACTIVITY_LIST'] = new RouteConfigItem("/user/activity-list", "modules/user/pages/ActivityListPage", true, "我的活动页");
+    routes['USER_INVITE'] = new RouteConfigItem("/user/invite", "modules/user/pages/InvitePage", true, "邀友购车页");
+    routes['USER_RIDING_STATISTICS'] = new RouteConfigItem("/user/riding-statistics", "modules/user/pages/RidingStatisticsPage", true, "骑行统计页");
+    routes['USER_FEEDBACK'] = new RouteConfigItem("/user/feedback", "modules/user/pages/FeedbackPage", true, "意见反馈页");
+    routes['USER_CONTACT'] = new RouteConfigItem("/user/contact", "modules/user/pages/ContactPage", true, "联系我们页");
+    routes['USER_BLACKLIST'] = new RouteConfigItem("/user/blacklist", "modules/user/pages/BlacklistPage", true, "黑名单页");
+    routes['USER_SIMPLE_PLACEHOLDER'] = new RouteConfigItem("/common/placeholder", "modules/user/pages/SimplePlaceholderPage", false, "简单占位页");
+    
+    // ========== 车辆模块 ==========
+    routes['VEHICLE_BIND'] = new RouteConfigItem("/vehicle/bind", "modules/vehicle/pages/VehicleBindPage", true, "车辆绑定页");
+    routes['QRCODE_SCAN'] = new RouteConfigItem("/vehicle/scan", "modules/vehicle/pages/VehicleQRScanPage", true, "车辆扫码页");
+    routes['VEHICLE_BIND_CONFIRM'] = new RouteConfigItem("/vehicle/bind-confirm", "modules/vehicle/pages/VehicleBindConfirmPage", true, "绑定确认页");
+    routes['VEHICLE_MANAGE'] = new RouteConfigItem("/vehicle/manage", "modules/vehicle/pages/VehicleManagePage", true, "车辆管理页");
+    routes['RIDING_RECORD_LIST'] = new RouteConfigItem("/vehicle/riding-record-list", "modules/vehicle/pages/RidingRecordListPage", true, "骑行记录列表");
+    routes['RIDING_RECORD_DETAIL'] = new RouteConfigItem("/vehicle/riding-record-detail", "modules/vehicle/pages/RidingRecordDetailPage", true, "骑行记录详情");
+    routes['FIRMWARE_UPGRADE'] = new RouteConfigItem("/vehicle/firmware-upgrade", "modules/vehicle/pages/FirmwareUpgradePage", true, "固件升级列表");
+    routes['FIRMWARE_UPGRADE_DETAIL'] = new RouteConfigItem("/vehicle/firmware-upgrade-detail", "modules/vehicle/pages/FirmwareUpgradeDetailPage", true, "固件升级详情");
+    routes['MAP'] = new RouteConfigItem("/vehicle/map", "modules/vehicle/pages/MapPage", true, "地图");
+    routes['KEY_SHARE'] = new RouteConfigItem("/vehicle/key-share", "modules/vehicle/pages/KeySharePage", true, "钥匙共享");
+    routes['BATTERY_DETAILS'] = new RouteConfigItem("/vehicle/battery-details", "modules/vehicle/pages/BatteryDetailsPage", true, "电池详情");
+    routes['VEHICLE_BLE_SEARCH'] = new RouteConfigItem("/vehicle/ble-search", "modules/vehicle/pages/BluetoothDeviceSearchPage", true, "蓝牙设备搜索");
+    routes['TIRE_PRESSURE'] = new RouteConfigItem("/vehicle/tire-pressure", "modules/vehicle/pages/TirePressurePage", true, "胎压");
+    routes['AMBIENT_LIGHT_SETTINGS'] = new RouteConfigItem("/vehicle/ambient-light", "modules/vehicle/pages/AmbientLightSettingsPage", true, "氛围灯设置");
+    routes['RGB_COLOR_PICKER'] = new RouteConfigItem("/vehicle/rgb-picker", "modules/vehicle/pages/RGBColorPickerPage", true, "RGB颜色选择");
+    routes['SET_STARTUP_PASSWORD'] = new RouteConfigItem("/vehicle/startup-password", "modules/vehicle/pages/SetStartupPasswordPage", true, "开机密码设置");
+    routes['CREATE_SHARE'] = new RouteConfigItem("/vehicle/create-share", "modules/vehicle/pages/CreateSharePage", true, "创建分享");
+    routes['DRIVING_RECORDER'] = new RouteConfigItem("/vehicle/driving-recorder", "modules/vehicle/pages/DrivingRecorderPage", true, "行车记录仪");
+    routes['SMART_ACCESSORIES'] = new RouteConfigItem("/vehicle/smart-accessories", "modules/vehicle/pages/SmartAccessoriesPage", true, "智能周边");
+    
+    // ========== 车辆设置相关页面 ==========
+    routes['SECURITY_SETTINGS'] = new RouteConfigItem("/vehicle/security-settings", "modules/vehicle/pages/SecuritySettingsPage", true, "安防设置");
+    routes['LOST_VEHICLE_MODE'] = new RouteConfigItem("/vehicle/lost-vehicle-mode", "modules/vehicle/pages/LostVehicleModePage", true, "丢车模式");
+    routes['SOS_EMERGENCY'] = new RouteConfigItem("/vehicle/sos-emergency", "modules/vehicle/pages/SosEmergencyPage", true, "SOS紧急通知");
+    routes['NFC_SETTINGS'] = new RouteConfigItem("/vehicle/nfc-settings", "modules/vehicle/pages/NfcSettingsPage", true, "NFC设置");
+    routes['INDUCTIVE_UNLOCK'] = new RouteConfigItem("/vehicle/inductive-unlock", "modules/vehicle/pages/InductiveUnlockPage", true, "感应解锁");
+    routes['NFC_PASSWORD_SETUP'] = new RouteConfigItem("/vehicle/nfc-password-setup", "modules/vehicle/pages/NfcPasswordSetupPage", true, "NFC密码");
+    routes['VEHICLE_CUSTOMIZATION'] = new RouteConfigItem("/vehicle/customization", "modules/vehicle/pages/VehicleCustomizationPage", true, "车辆自定义功能");
+    routes['LIGHTING_SETTINGS'] = new RouteConfigItem("/vehicle/lighting-settings", "modules/vehicle/pages/LightingSettingsPage", true, "灯光设置");
+    routes['AMBIENT_LIGHT_DETAIL'] = new RouteConfigItem("/vehicle/ambient-light-detail", "modules/vehicle/pages/AmbientLightDetailPage", true, "氛围灯详情");
+    routes['VEHICLE_SETTINGS'] = new RouteConfigItem("/vehicle/settings", "modules/vehicle/pages/VehicleSettingsPage", true, "车辆设置");
+    routes['NOVICE_ESCORT'] = new RouteConfigItem("/vehicle/novice-escort", "modules/vehicle/pages/NoviceEscortPage", true, "新手护航");
+    routes['CHASSIS_CONTROL'] = new RouteConfigItem("/vehicle/chassis-control", "modules/vehicle/pages/ChassisControlPage", true, "驾控设置");
+    routes['USER_CUSTOM_MODE'] = new RouteConfigItem("/vehicle/user-custom-mode", "modules/vehicle/pages/UserCustomModePage", true, "自定义模式");
+    routes['DEVICE_INFO'] = new RouteConfigItem("/vehicle/device-info", "modules/vehicle/pages/DeviceInfoPage", true, "设备信息");
+    routes['RECORDER_REMOTE_LIST'] = new RouteConfigItem("/vehicle/recorder-remote-list", "modules/vehicle/pages/RecorderRemoteListPage", true, "行车记录仪(云端列表)");
+    routes['RECORDER_LOCAL_LIST'] = new RouteConfigItem("/vehicle/recorder-local-list", "modules/vehicle/pages/RecorderLocalListPage", true, "行车记录仪(本地列表)");
+    routes['RECORDER_DETAIL'] = new RouteConfigItem("/vehicle/recorder-detail", "modules/vehicle/pages/RecorderDetailPage", true, "行车记录仪(详情)");
+    routes['RECORDER_DOWNLOAD_TASK'] = new RouteConfigItem("/vehicle/recorder-download-task", "modules/vehicle/pages/RecorderDownloadTaskPage", true, "行车记录仪(下载任务)");
+  }
+  
+  /**
+   * 获取路由配置字典
+   */
+  static get routes(): Record<string, RouteConfigItem> {
+    if (RouteConfig._routes === null) {
+      RouteConfig.initRoutes();
+    }
+    return RouteConfig._routes!;
+  }
+  
+  /**
+   * 获取文件路径(用于 HMRouterMgr.to() 的 pageUrl)
+   * 
+   * @param routeKey 路由配置键
+   * @returns 文件路径,如果未找到返回空字符串
+   */
+  static getFilePath(routeKey: string): string {
+    const config = RouteConfig.routes[routeKey];
+    if (!config) {
+      LogHelper.e(RouteConfig.TAG, `路由配置未找到: ${routeKey}`);
+      return "";
+    }
+    return config.filePath;
+  }
+  
+  /**
+   * 获取逻辑路径(用于注解)
+   * 
+   * @param routeKey 路由配置键
+   * @returns 逻辑路径,如果未找到返回空字符串
+   */
+  static getPath(routeKey: string): string {
+    const config = RouteConfig.routes[routeKey];
+    if (!config) {
+      LogHelper.e(RouteConfig.TAG, `路由配置未找到: ${routeKey}`);
+      return "";
+    }
+    return config.path;
+  }
+  
+  /**
+   * 检查是否需要登录
+   * 
+   * @param routeKey 路由配置键
+   * @returns 是否需要登录
+   */
+  static needLogin(routeKey: string): boolean {
+    const config = RouteConfig.routes[routeKey];
+    return config?.needLogin || false;
+  }
+  
+  /**
+   * 获取路由配置
+   * 
+   * @param routeKey 路由配置键
+   * @returns 路由配置项,如果未找到返回 undefined
+   */
+  static getConfig(routeKey: string): RouteConfigItem | undefined {
+    return RouteConfig.routes[routeKey];
+  }
+  
+  /**
+   * 检查路由是否存在
+   * 
+   * @param routeKey 路由配置键
+   * @returns 是否存在
+   */
+  static hasRoute(routeKey: string): boolean {
+    return RouteConfig.routes[routeKey] !== undefined;
+  }
+}
+

+ 41 - 0
base-common/src/main/ets/common/router/RouteConstants.ets

@@ -0,0 +1,41 @@
+/**
+ * ARouter 路由常量(类似 Android ARouter 的路由路径)
+ *
+ * 使用方式:
+ * ```typescript
+ * ARouter.build(RouteConstants.APP_MAIN).navigation();
+ * ```
+ */
+export class RouteConstants {
+  // ========== 应用主界面 ==========
+  static readonly APP_MAIN = "/app/main";
+
+  // ========== 认证相关 ==========
+  static readonly AUTH_LOGIN = "/auth/login";
+  static readonly AUTH_REGISTER = "/auth/register";
+  static readonly AUTH_VERIFY_CODE_LOGIN = "/auth/verify-code-login";
+  static readonly AUTH_PASSWORD_LOGIN = "/auth/password-login";
+  static readonly AUTH_FORGOT_PASSWORD = "/auth/forgot-password";
+  static readonly AUTH_THIRD_PARTY_BINDING = "/auth/third-party-binding";
+
+  // ========== 主界面 ==========
+  static readonly MAIN_INDEX = "/main/index";
+
+  // ========== 社区相关 ==========
+  static readonly COMMUNITY_POST_DETAIL = "/community/post-detail";
+  static readonly COMMUNITY_CREATE_POST = "/community/create-post";
+
+  // ========== 用户相关 ==========
+  static readonly USER_PERSONAL_INFO = "/user/personal-info";
+  static readonly USER_SETTINGS = "/user/settings";
+  static readonly USER_ACCOUNT_MANAGE = "/user/account-manage";
+  static readonly USER_ACTIVITY_LIST = "/user/activity-list";
+  static readonly USER_BLACKLIST = "/user/blacklist";
+  static readonly USER_COLLECT_LIST = "/user/collect-list";
+  static readonly USER_CONTACT = "/user/contact";
+  static readonly USER_FEEDBACK = "/user/feedback";
+  static readonly USER_INVITE = "/user/invite";
+  static readonly USER_MESSAGE_LIST = "/user/message-list";
+  static readonly USER_ORDER_LIST = "/user/order-list";
+  static readonly USER_SIMPLE_PLACEHOLDER = "/common/placeholder";
+}

+ 202 - 0
base-common/src/main/ets/common/router/RouteInterceptor.ets

@@ -0,0 +1,202 @@
+import { HMRouterMgr } from '@hadss/hmrouter';
+import { RoutePath } from './RoutePath';
+import { LogHelper } from '../log/LogHelper';
+import { StorageManager } from '../storage/StorageManager';
+import { StorageKeys } from '@xdz/base-core';
+import { getRouteKeyFromPath } from './RouterManager';
+
+/**
+ * 路由拦截器接口
+ * 
+ * 实现此接口以创建自定义路由拦截器
+ */
+export interface IRouteInterceptor {
+  /**
+   * 拦截路由跳转
+   * 
+   * @param url 目标路由路径
+   * @param params 路由参数
+   * @returns 返回 true 表示允许跳转,返回 false 表示拦截跳转
+   */
+  intercept(url: string, params?: Record<string, Object>): boolean | Promise<boolean>;
+}
+
+/**
+ * 登录检查拦截器
+ * 
+ * 检查用户是否已登录,未登录则跳转到登录页
+ */
+export class LoginCheckInterceptor implements IRouteInterceptor {
+  private static readonly TAG = 'LoginCheckInterceptor';
+  
+  /**
+   * 需要登录才能访问的路由路径列表
+   */
+  /** ARouter 传入的为 routeKey,此处列出需登录的 routeKey(与 RouteConfig 一致) */
+  private static readonly LOGIN_REQUIRED_PATHS: string[] = [
+    RoutePath.COMMUNITY_CREATE_POST,
+    RoutePath.USER_PERSONAL_INFO,
+    RoutePath.USER_SETTINGS,
+    RoutePath.RESET_PASSWORD,
+    'AUTH_RESET_PASSWORD',
+    RoutePath.USER_ACCOUNT_MANAGE,
+    RoutePath.USER_ACTIVITY_LIST,
+    RoutePath.USER_BLACKLIST,
+    RoutePath.USER_COLLECT_LIST,
+    RoutePath.USER_FEEDBACK,
+    RoutePath.USER_INVITE,
+    RoutePath.USER_MESSAGE_LIST,
+    RoutePath.USER_ORDER_LIST,
+    RoutePath.QRCODE_SCAN,
+    'VEHICLE_BIND',
+    'QRCODE_SCAN',
+    RoutePath.VEHICLE_BIND_CONFIRM,
+    RoutePath.VEHICLE_MANAGE,
+    RoutePath.RIDING_RECORD_LIST,
+    RoutePath.RIDING_RECORD_DETAIL,
+    RoutePath.FIRMWARE_UPGRADE,
+    RoutePath.FIRMWARE_UPGRADE_DETAIL,
+    'VEHICLE_BIND_CONFIRM',
+    'VEHICLE_MANAGE',
+    'RIDING_RECORD_LIST',
+    'RIDING_RECORD_DETAIL',
+    'FIRMWARE_UPGRADE',
+    'FIRMWARE_UPGRADE_DETAIL',
+    RoutePath.MAP,
+    RoutePath.KEY_SHARE,
+    RoutePath.BATTERY_DETAILS,
+    RoutePath.VEHICLE_BLE_SEARCH,
+    'MAP',
+    'KEY_SHARE',
+    'BATTERY_DETAILS',
+    'VEHICLE_BLE_SEARCH',
+    RoutePath.TIRE_PRESSURE,
+    RoutePath.AMBIENT_LIGHT_SETTINGS,
+    RoutePath.RGB_COLOR_PICKER,
+    RoutePath.SET_STARTUP_PASSWORD,
+    RoutePath.CREATE_SHARE,
+    RoutePath.DRIVING_RECORDER,
+    RoutePath.SMART_ACCESSORIES,
+    'TIRE_PRESSURE',
+    'AMBIENT_LIGHT_SETTINGS',
+    'RGB_COLOR_PICKER',
+    'SET_STARTUP_PASSWORD',
+    'CREATE_SHARE',
+    'DRIVING_RECORDER',
+    'SMART_ACCESSORIES',
+  ];
+  async intercept(url: string, params?: Record<string, Object>): Promise<boolean> {
+    // 检查是否需要登录
+    if (!LoginCheckInterceptor.LOGIN_REQUIRED_PATHS.includes(url)) {
+      return true; // 不需要登录,允许跳转
+    }
+    
+    const isLogin = await StorageManager.getBoolean(StorageKeys.APP_IS_LOGIN, false);
+    if (isLogin) {
+      return true;
+    }
+    
+    LogHelper.d(LoginCheckInterceptor.TAG, `用户未登录,拦截跳转到: ${url}`);
+    
+    HMRouterMgr.to('AUTH_LOGIN')
+      .withParam({
+        targetRoute: getRouteKeyFromPath(url) || url,
+        targetParams: params
+      } as ESObject)
+      .pushAsync()
+      .catch((error: Error) => {
+        LogHelper.e(LoginCheckInterceptor.TAG, '跳转到登录页失败', error);
+      });
+    
+    return false; // 拦截跳转
+  }
+}
+
+/**
+ * 路由拦截器管理器
+ * 
+ * 统一管理所有路由拦截器
+ */
+export class RouteInterceptorManager {
+  private static readonly TAG = 'RouteInterceptorManager';
+  private static interceptors: IRouteInterceptor[] = [];
+  private static isInitialized: boolean = false;
+  
+  /**
+   * 初始化拦截器管理器
+   * 
+   * @param customInterceptors 自定义拦截器列表(可选)
+   */
+  static init(customInterceptors?: IRouteInterceptor[]): void {
+    if (RouteInterceptorManager.isInitialized) {
+      LogHelper.w(RouteInterceptorManager.TAG, '拦截器管理器已初始化,跳过重复初始化');
+      return;
+    }
+    
+    // 添加默认拦截器
+    RouteInterceptorManager.interceptors.push(new LoginCheckInterceptor());
+    
+    // 添加自定义拦截器
+    if (customInterceptors && customInterceptors.length > 0) {
+      RouteInterceptorManager.interceptors.push(...customInterceptors);
+    }
+    
+    RouteInterceptorManager.isInitialized = true;
+    LogHelper.d(RouteInterceptorManager.TAG, `拦截器管理器初始化完成,共 ${RouteInterceptorManager.interceptors.length} 个拦截器`);
+  }
+  
+  /**
+   * 添加拦截器
+   * 
+   * @param interceptor 拦截器实例
+   */
+  static addInterceptor(interceptor: IRouteInterceptor): void {
+    RouteInterceptorManager.interceptors.push(interceptor);
+    LogHelper.d(RouteInterceptorManager.TAG, '添加拦截器成功');
+  }
+  
+  /**
+   * 执行拦截检查
+   * 
+   * @param url 目标路由路径
+   * @param params 路由参数
+   * @param skipInterceptors 是否跳过拦截器检查(用于登录页等特殊页面)
+   * @returns 返回 true 表示允许跳转,返回 false 表示被拦截
+   */
+  static async check(url: string, params?: Record<string, Object>, skipInterceptors: boolean = false): Promise<boolean> {
+    if (skipInterceptors) {
+      return true; // 跳过拦截器检查
+    }
+    
+    if (!RouteInterceptorManager.isInitialized) {
+      LogHelper.w(RouteInterceptorManager.TAG, '拦截器管理器未初始化,允许跳转');
+      return true;
+    }
+    
+    // 依次执行所有拦截器
+    for (const interceptor of RouteInterceptorManager.interceptors) {
+      try {
+        const result = await interceptor.intercept(url, params);
+        if (!result) {
+          LogHelper.d(RouteInterceptorManager.TAG, `拦截器拦截了跳转: ${url}`);
+          return false; // 被拦截
+        }
+      } catch (error) {
+        LogHelper.e(RouteInterceptorManager.TAG, '拦截器执行出错', error as Error);
+        // 拦截器出错时,默认允许跳转(避免影响正常功能)
+      }
+    }
+    
+    return true; // 所有拦截器都通过,允许跳转
+  }
+  
+  /**
+   * 清空所有拦截器
+   */
+  static clear(): void {
+    RouteInterceptorManager.interceptors = [];
+    RouteInterceptorManager.isInitialized = false;
+    LogHelper.d(RouteInterceptorManager.TAG, '已清空所有拦截器');
+  }
+}
+

+ 121 - 0
base-common/src/main/ets/common/router/RouteParamsHelper.ets

@@ -0,0 +1,121 @@
+import { HMRouterMgr } from '@hadss/hmrouter';
+import { LogHelper } from '../log/LogHelper';
+
+/**
+ * 路由参数获取工具类
+ * 
+ * 统一处理路由参数的获取,提供类型安全的参数获取方法
+ * 
+ * 使用方式:
+ * ```typescript
+ * aboutToAppear() {
+ *   const params = RouteParamsHelper.getParams();
+ *   if (params) {
+ *     this.postId = RouteParamsHelper.getNumber(params, 'postId', 0);
+ *     this.title = RouteParamsHelper.getString(params, 'title', '');
+ *   }
+ * }
+ * ```
+ */
+export class RouteParamsHelper {
+  private static readonly TAG = 'RouteParamsHelper';
+  
+  /**
+   * 获取路由参数
+   * 
+   * @returns 路由参数字典,如果不存在则返回 null
+   */
+  static getParams(): Record<string, Object> | null {
+    try {
+      const params = HMRouterMgr.getCurrentParam() as Record<string, Object> | undefined;
+      if (params) {
+        LogHelper.d(RouteParamsHelper.TAG, `获取路由参数: ${JSON.stringify(params)}`);
+        return params as Record<string, Object>;
+      }
+      return null;
+    } catch (error) {
+      LogHelper.e(RouteParamsHelper.TAG, '获取路由参数失败', error as Error);
+      return null;
+    }
+  }
+  
+  /**
+   * 获取字符串参数
+   * 
+   * @param params 参数字典
+   * @param key 参数键
+   * @param defaultValue 默认值
+   * @returns 参数值
+   */
+  static getString(params: Record<string, Object> | null, key: string, defaultValue: string = ''): string {
+    if (!params || !params[key]) {
+      return defaultValue;
+    }
+    const value = params[key];
+    if (typeof value === 'string') {
+      return value;
+    }
+    return String(value);
+  }
+  
+  /**
+   * 获取数字参数
+   * 
+   * @param params 参数字典
+   * @param key 参数键
+   * @param defaultValue 默认值
+   * @returns 参数值
+   */
+  static getNumber(params: Record<string, Object> | null, key: string, defaultValue: number = 0): number {
+    if (!params || !params[key]) {
+      return defaultValue;
+    }
+    const value = params[key];
+    if (typeof value === 'number') {
+      return value;
+    }
+    if (typeof value === 'string') {
+      const num = Number(value);
+      return isNaN(num) ? defaultValue : num;
+    }
+    return defaultValue;
+  }
+  
+  /**
+   * 获取布尔参数
+   * 
+   * @param params 参数字典
+   * @param key 参数键
+   * @param defaultValue 默认值
+   * @returns 参数值
+   */
+  static getBoolean(params: Record<string, Object> | null, key: string, defaultValue: boolean = false): boolean {
+    if (!params || !params[key]) {
+      return defaultValue;
+    }
+    const value = params[key];
+    if (typeof value === 'boolean') {
+      return value;
+    }
+    if (typeof value === 'string') {
+      return value === 'true' || value === '1';
+    }
+    return defaultValue;
+  }
+  
+  /**
+   * 获取对象参数
+   * 
+   * @param params 参数字典
+   * @param key 参数键
+   * @param defaultValue 默认值
+   * @returns 参数值
+   */
+  static getObject<T>(params: Record<string, Object> | null, key: string, defaultValue: T | null = null): T | null {
+    if (!params || !params[key]) {
+      return defaultValue;
+    }
+    return params[key] as T;
+  }
+}
+

+ 205 - 0
base-common/src/main/ets/common/router/RoutePath.ets

@@ -0,0 +1,205 @@
+/**
+ * 路由路径常量
+ * 
+ * 统一管理所有路由路径,避免硬编码
+ * 
+ * 规范:
+ * - 格式:/模块/页面
+ * - 命名:小写字母,单词间用下划线分隔
+ * - 所有路由路径必须定义在这里,禁止硬编码
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { RoutePath } from '@xdz/base-common';
+ * 
+ * RouterManager.navigate(RoutePath.LOGIN);
+ * ```
+ */
+export class RoutePath {
+  // ========== 应用模块 ==========
+  /**
+   * 主界面
+   */
+  static readonly MAIN = "pages/Index";
+  
+  // ========== 认证模块 ==========
+  /**
+   * 登录界面
+   */
+  static readonly LOGIN = "modules/auth/pages/LoginPage";
+  
+  /**
+   * 注册界面
+   */
+  static readonly REGISTER = "modules/auth/pages/RegisterPage";
+  
+  /**
+   * 验证码登录界面(统一登录页面)
+   */
+  static readonly VERIFY_CODE_LOGIN = "modules/auth/pages/UnifiedLoginPage";
+  
+  /**
+   * 密码登录界面(统一登录页面,通过参数区分)
+   */
+  static readonly PASSWORD_LOGIN = "modules/auth/pages/UnifiedLoginPage";
+  
+  /**
+   * 忘记密码界面
+   */
+  static readonly FORGOT_PASSWORD = "modules/auth/pages/ForgotPasswordPage";
+  
+  /**
+   * 第三方绑定界面
+   */
+  static readonly THIRD_PARTY_BINDING = "modules/auth/pages/ThirdPartyBindingPage";
+
+  /**
+   * 重置密码界面(A.5 从设置/账号安全进入)
+   */
+  static readonly RESET_PASSWORD = "modules/auth/pages/ResetPasswordPage";
+  
+  // ========== 社区模块 ==========
+  /**
+   * 帖子详情页
+   */
+  static readonly COMMUNITY_POST_DETAIL = "modules/community/pages/PostDetailPage";
+  
+  /**
+   * 发帖页
+   */
+  static readonly COMMUNITY_CREATE_POST = "modules/community/pages/CreatePostPage";
+  
+  // ========== 用户模块 ==========
+  /**
+   * 个人资料页
+   */
+  static readonly USER_PERSONAL_INFO = "modules/user/pages/PersonalInfoPage";
+  
+  /**
+   * 设置页
+   */
+  static readonly USER_SETTINGS = "modules/user/pages/SettingsPage";
+  
+  /**
+   * 账号管理页
+   */
+  static readonly USER_ACCOUNT_MANAGE = "modules/user/pages/AccountManagePage";
+  
+  /**
+   * 我的消息页
+   */
+  static readonly USER_MESSAGE_LIST = "modules/user/pages/MessageListPage";
+  
+  /**
+   * 我的收藏页
+   */
+  static readonly USER_COLLECT_LIST = "modules/user/pages/CollectListPage";
+  
+  /**
+   * 我的车辆页
+   */
+  static readonly USER_VEHICLE_LIST = "modules/user/pages/VehicleListPage";
+  
+  /**
+   * 我的订单页
+   */
+  static readonly USER_ORDER_LIST = "modules/user/pages/OrderListPage";
+  
+  /**
+   * 我的活动页
+   */
+  static readonly USER_ACTIVITY_LIST = "modules/user/pages/ActivityListPage";
+  
+  /**
+   * 邀友购车页
+   */
+  static readonly USER_INVITE = "modules/user/pages/InvitePage";
+  
+  /**
+   * 骑行统计页
+   */
+  static readonly USER_RIDING_STATISTICS = "modules/user/pages/RidingStatisticsPage";
+  
+  /**
+   * 意见反馈页
+   */
+  static readonly USER_FEEDBACK = "modules/user/pages/FeedbackPage";
+  
+  /**
+   * 联系我们页
+   */
+  static readonly USER_CONTACT = "modules/user/pages/ContactPage";
+  
+  /**
+   * 黑名单页
+   */
+  static readonly USER_BLACKLIST = "modules/user/pages/BlacklistPage";
+  
+  /**
+   * 简单占位页
+   */
+  static readonly USER_SIMPLE_PLACEHOLDER = "modules/user/pages/SimplePlaceholderPage";
+  
+  // ========== 车辆模块 ==========
+  /**
+   * 车辆绑定页
+   */
+  static readonly VEHICLE_BIND = "modules/vehicle/pages/VehicleBindPage";
+
+  /**
+   * 车辆扫码页(6.1.x 生命周期/权限/重试;6.2 串联绑定)
+   */
+  static readonly QRCODE_SCAN = "modules/vehicle/pages/VehicleQRScanPage";
+
+  /** 绑定确认页 */
+  static readonly VEHICLE_BIND_CONFIRM = "modules/vehicle/pages/VehicleBindConfirmPage";
+  /** 车辆管理页 */
+  static readonly VEHICLE_MANAGE = "modules/vehicle/pages/VehicleManagePage";
+  /** 骑行记录列表 */
+  static readonly RIDING_RECORD_LIST = "modules/vehicle/pages/RidingRecordListPage";
+  /** 骑行记录详情 */
+  static readonly RIDING_RECORD_DETAIL = "modules/vehicle/pages/RidingRecordDetailPage";
+  /** 固件升级列表 */
+  static readonly FIRMWARE_UPGRADE = "modules/vehicle/pages/FirmwareUpgradePage";
+  /** 固件升级详情 */
+  static readonly FIRMWARE_UPGRADE_DETAIL = "modules/vehicle/pages/FirmwareUpgradeDetailPage";
+  /** P1 地图页 */
+  static readonly MAP = "modules/vehicle/pages/MapPage";
+  /** P1 钥匙共享 */
+  static readonly KEY_SHARE = "modules/vehicle/pages/KeySharePage";
+  /** P1 电池详情 */
+  static readonly BATTERY_DETAILS = "modules/vehicle/pages/BatteryDetailsPage";
+  /** P1 蓝牙设备搜索 */
+  static readonly VEHICLE_BLE_SEARCH = "modules/vehicle/pages/BluetoothDeviceSearchPage";
+  /** P2 胎压 */
+  static readonly TIRE_PRESSURE = "modules/vehicle/pages/TirePressurePage";
+  /** P2 氛围灯设置 */
+  static readonly AMBIENT_LIGHT_SETTINGS = "modules/vehicle/pages/AmbientLightSettingsPage";
+  /** P2 RGB 颜色选择 */
+  static readonly RGB_COLOR_PICKER = "modules/vehicle/pages/RGBColorPickerPage";
+  /** P2 开机密码设置 */
+  static readonly SET_STARTUP_PASSWORD = "modules/vehicle/pages/SetStartupPasswordPage";
+  /** P2 创建分享 */
+  static readonly CREATE_SHARE = "modules/vehicle/pages/CreateSharePage";
+  /** P2 行车记录仪 */
+  static readonly DRIVING_RECORDER = "modules/vehicle/pages/DrivingRecorderPage";
+  /** P2 智能周边 */
+  static readonly SMART_ACCESSORIES = "modules/vehicle/pages/SmartAccessoriesPage";
+
+  // ========== 路由额外标记 ==========
+  /**
+   * 需要登录标记
+   */
+  static readonly NEED_LOGIN = 1;
+}
+
+/**
+ * 路由额外标记接口
+ */
+export interface RouteExtra {
+  /**
+   * 需要登录
+   */
+  NEED_LOGIN: number;
+}
+

+ 729 - 0
base-common/src/main/ets/common/router/RouterManager.ets

@@ -0,0 +1,729 @@
+import { HMRouterMgr } from '@hadss/hmrouter';
+import { RoutePath } from './RoutePath';
+import { RouteConfig } from './RouteConfig';
+import { RouteParamsHelper } from './RouteParamsHelper';
+import { LogHelper } from '../log/LogHelper';
+import { RouteInterceptorManager } from './RouteInterceptor';
+import { ARouter } from './ARouter';
+import { AuthGuardHolder } from '../auth/AuthGuardHolder';
+import type { IAuthGuard } from '../auth/IAuthGuard';
+
+/**
+ * 路由管理器(单例)
+ * 
+ * 统一管理所有页面跳转,使用 HMRouterMgr 进行跳转
+ * 
+ * 规范:
+ * - 所有页面跳转必须通过 RouterManager
+ * - 禁止直接使用 HMRouterMgr.to()
+ * - Token 过期跳转必须使用 navigateToLoginOnTokenExpired()
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { RouterManager } from '@xdz/base-common';
+ * 
+ * // 跳转到登录页
+ * RouterManager.navigateToLogin();
+ * 
+ * // 跳转到帖子详情页
+ * RouterManager.navigateToPostDetail(123);
+ * ```
+ */
+/**
+ * 将 RoutePath 文件路径转换为 RouteConfig routeKey
+ */
+export function getRouteKeyFromPath(filePath: string): string {
+  // 映射文件路径到 routeKey
+  const pathToKeyMap: Record<string, string> = {
+    "pages/Index": "APP_MAIN",
+    "modules/auth/pages/LoginPage": "AUTH_LOGIN",
+    "modules/auth/pages/RegisterPage": "AUTH_REGISTER",
+          "modules/auth/pages/UnifiedLoginPage": "AUTH_VERIFY_CODE_LOGIN",
+          // 密码登录路由映射到统一登录页面(通过参数区分模式)
+          "modules/auth/pages/PasswordLoginPage": "AUTH_PASSWORD_LOGIN",
+    "modules/auth/pages/ThirdPartyBindingPage": "AUTH_THIRD_PARTY_BINDING",
+    "modules/auth/pages/ResetPasswordPage": "AUTH_RESET_PASSWORD",
+    "modules/community/pages/PostDetailPage": "COMMUNITY_POST_DETAIL",
+    "modules/community/pages/CreatePostPage": "COMMUNITY_CREATE_POST",
+    "modules/user/pages/PersonalInfoPage": "USER_PERSONAL_INFO",
+    "modules/user/pages/SettingsPage": "USER_SETTINGS",
+    "modules/user/pages/AccountManagePage": "USER_ACCOUNT_MANAGE",
+    "modules/user/pages/MessageListPage": "USER_MESSAGE_LIST",
+    "modules/user/pages/CollectListPage": "USER_COLLECT_LIST",
+    "modules/user/pages/VehicleListPage": "USER_VEHICLE_LIST",
+    "modules/user/pages/OrderListPage": "USER_ORDER_LIST",
+    "modules/user/pages/ActivityListPage": "USER_ACTIVITY_LIST",
+    "modules/user/pages/InvitePage": "USER_INVITE",
+    "modules/user/pages/RidingStatisticsPage": "USER_RIDING_STATISTICS",
+    "modules/user/pages/FeedbackPage": "USER_FEEDBACK",
+    "modules/user/pages/ContactPage": "USER_CONTACT",
+    "modules/user/pages/BlacklistPage": "USER_BLACKLIST",
+    "modules/user/pages/SimplePlaceholderPage": "USER_SIMPLE_PLACEHOLDER",
+    "modules/vehicle/pages/VehicleBindPage": "VEHICLE_BIND",
+    "modules/vehicle/pages/VehicleQRScanPage": "QRCODE_SCAN",
+    "modules/vehicle/pages/VehicleBindConfirmPage": "VEHICLE_BIND_CONFIRM",
+    "modules/vehicle/pages/VehicleManagePage": "VEHICLE_MANAGE",
+    "modules/vehicle/pages/RidingRecordListPage": "RIDING_RECORD_LIST",
+    "modules/vehicle/pages/RidingRecordDetailPage": "RIDING_RECORD_DETAIL",
+    "modules/vehicle/pages/FirmwareUpgradePage": "FIRMWARE_UPGRADE",
+    "modules/vehicle/pages/FirmwareUpgradeDetailPage": "FIRMWARE_UPGRADE_DETAIL",
+    "modules/vehicle/pages/MapPage": "MAP",
+    "modules/vehicle/pages/KeySharePage": "KEY_SHARE",
+    "modules/vehicle/pages/BatteryDetailsPage": "BATTERY_DETAILS",
+    "modules/vehicle/pages/BluetoothDeviceSearchPage": "VEHICLE_BLE_SEARCH",
+    "modules/vehicle/pages/TirePressurePage": "TIRE_PRESSURE",
+    "modules/vehicle/pages/AmbientLightSettingsPage": "AMBIENT_LIGHT_SETTINGS",
+    "modules/vehicle/pages/RGBColorPickerPage": "RGB_COLOR_PICKER",
+    "modules/vehicle/pages/SetStartupPasswordPage": "SET_STARTUP_PASSWORD",
+    "modules/vehicle/pages/CreateSharePage": "CREATE_SHARE",
+    "modules/vehicle/pages/DrivingRecorderPage": "DRIVING_RECORDER",
+    "modules/vehicle/pages/SmartAccessoriesPage": "SMART_ACCESSORIES"
+  };
+  return pathToKeyMap[filePath] || filePath;
+}
+
+export class RouterManager {
+  private static readonly TAG = 'RouterManager';
+  private static logoutCallback: (() => void) | null = null;
+  /**
+   * 设置认证守卫(3.3.2,entry 在 init 后调用)
+   */
+  static setAuthGuard(guard: IAuthGuard | null): void {
+    AuthGuardHolder.setGuard(guard);
+  }
+
+  /**
+   * 初始化(在 AppInitializer 中调用)
+   * 
+   * @param logoutCallback 登出回调(从 entry 模块传入,与 setAuthGuard 二选一或同时使用)
+   */
+  static init(logoutCallback?: () => void): void {
+    RouterManager.logoutCallback = logoutCallback || null;
+    RouteInterceptorManager.init();
+    ARouter.init();
+    LogHelper.d(RouterManager.TAG, 'RouterManager 初始化完成');
+  }
+  
+  // ========== 认证相关路由 ==========
+  
+  /**
+   * 跳转到登录页(Token 过期专用)
+   * 
+   * 特点:
+   * - 清除路由栈
+   * - 无法返回
+   * - 清除登录状态
+   * 
+   * 使用场景:
+   * - Token 刷新失败
+   * - 401/402 响应且刷新失败
+   */
+  static navigateToLoginOnTokenExpired(): void {
+    LogHelper.d(RouterManager.TAG, 'Token 过期,跳转到登录页(清除路由栈)');
+    const guard = AuthGuardHolder.getGuard();
+    if (guard) {
+      guard.logout();
+    }
+    if (RouterManager.logoutCallback) {
+      RouterManager.logoutCallback();
+    }
+    // 清空路由栈并跳转到登录页
+    HMRouterMgr.to('AUTH_LOGIN').pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到登录页失败', error);
+    });
+  }
+  
+  /**
+   * 登录成功后回跳(2.2.4)
+   * 若当前页参数带有 targetRoute,则跳转至该路由;否则跳转主界面。
+   */
+  static navigateAfterLogin(): void {
+    const params = RouteParamsHelper.getParams();
+    const targetRoute = params ? RouteParamsHelper.getString(params, 'targetRoute', '') : '';
+    if (targetRoute !== '' && RouteConfig.hasRoute(targetRoute)) {
+      LogHelper.d(RouterManager.TAG, `登录回跳: ${targetRoute}`);
+      ARouter.build(targetRoute).skipInterceptor().navigation();
+    } else {
+      RouterManager.navigateToMain();
+    }
+  }
+
+  /**
+   * 跳转到登录页(普通跳转)
+   * 
+   * @param skipInterceptors 是否跳过拦截器(默认 false)
+   */
+  static async navigateToLogin(skipInterceptors: boolean = false): Promise<void> {
+    LogHelper.d('PageDebug', `[RouterManager] navigateToLogin 开始, skipInterceptors=${skipInterceptors}`);
+    // 跳转到登录页时,总是跳过拦截器(避免循环拦截)
+    const canNavigate = await RouteInterceptorManager.check(RoutePath.LOGIN, undefined, true);
+    LogHelper.d('PageDebug', `[RouterManager] RouteInterceptorManager.check 返回: ${canNavigate}`);
+    if (!canNavigate) {
+      LogHelper.w('PageDebug', '[RouterManager] 路由拦截器阻止跳转到登录页');
+      return;
+    }
+    
+    LogHelper.d('PageDebug', '[RouterManager] 准备跳转到登录页');
+    try {
+      // 检查 HMNavigation 是否存在
+      LogHelper.d('PageDebug', '[RouterManager] 检查 HMNavigation (mainNavigation) 是否存在...');
+      try {
+        const pathStack = HMRouterMgr.getPathStack('mainNavigation');
+        LogHelper.d('PageDebug', `[RouterManager] HMNavigation pathStack: ${pathStack ? '存在' : '不存在'}`);
+        if (pathStack) {
+          LogHelper.d('PageDebug', `[RouterManager] pathStack 详情: ${JSON.stringify(pathStack)}`);
+        }
+      } catch (stackError) {
+        LogHelper.e('PageDebug', '[RouterManager] 获取 pathStack 失败,可能 HMNavigation 未创建', stackError as Error);
+      }
+      
+      // 使用 HMRouter 标准跳转方式(必须指定 navigationId)
+      LogHelper.d('PageDebug', '[RouterManager] 调用 HMRouterMgr.push({ navigationId: "mainNavigation", pageUrl: "AUTH_LOGIN" })');
+      const pushResult = await HMRouterMgr.push({
+        navigationId: 'mainNavigation',
+        pageUrl: 'AUTH_LOGIN'
+      });
+      LogHelper.d('PageDebug', `[RouterManager] push 返回结果: ${pushResult}`);
+      LogHelper.d('PageDebug', '[RouterManager] 跳转到登录页成功,LoginPage 应该已创建');
+      
+      // 再次检查 pathStack,确认页面是否已添加
+      setTimeout(() => {
+        try {
+          const pathStackAfter = HMRouterMgr.getPathStack('mainNavigation');
+          LogHelper.d('PageDebug', `[RouterManager] push 后 pathStack: ${pathStackAfter ? '存在' : '不存在'}`);
+          if (pathStackAfter) {
+            LogHelper.d('PageDebug', `[RouterManager] push 后 pathStack 详情: ${JSON.stringify(pathStackAfter)}`);
+          }
+        } catch (e) {
+          LogHelper.e('PageDebug', '[RouterManager] push 后获取 pathStack 失败', e as Error);
+        }
+      }, 100);
+    } catch (error) {
+      LogHelper.e('PageDebug', '[RouterManager] 跳转到登录页异常', error as Error);
+      LogHelper.e(RouterManager.TAG, '跳转到登录页失败', error as Error);
+    }
+  }
+  
+  /**
+   * 跳转到注册页
+   */
+  static navigateToRegister(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.REGISTER);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到注册页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到验证码登录页(统一登录页面,默认显示验证码登录)
+   */
+  static navigateToVerifyCodeLogin(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.VERIFY_CODE_LOGIN);
+    try {
+      HMRouterMgr.push({
+        navigationId: 'mainNavigation',
+        pageUrl: pageUrl
+      });
+    } catch (error) {
+      LogHelper.e(RouterManager.TAG, '跳转到验证码登录页失败', error as Error);
+    }
+  }
+  
+  /**
+   * 跳转到密码登录页(统一登录页面,显示密码登录)
+   */
+  static navigateToPasswordLogin(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.PASSWORD_LOGIN);
+    try {
+      HMRouterMgr.push({
+        navigationId: 'mainNavigation',
+        pageUrl: pageUrl
+      });
+    } catch (error) {
+      LogHelper.e(RouterManager.TAG, '跳转到密码登录页失败', error as Error);
+    }
+  }
+  
+  /**
+   * 跳转到忘记密码页(实际跳转到重置密码页)
+   * @param mobile 手机号(可选,如果提供则传递给重置密码页)
+   */
+  static navigateToForgotPassword(mobile?: string): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.RESET_PASSWORD);
+    if (mobile) {
+      // ✅ 修复:传递手机号参数
+      try {
+        HMRouterMgr.push({
+          navigationId: 'mainNavigation',
+          pageUrl: pageUrl,
+          param: { mobile: mobile } as ESObject
+        });
+      } catch (error) {
+        LogHelper.e(RouterManager.TAG, '跳转到重置密码页失败', error as Error);
+      }
+    } else {
+      HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+        LogHelper.e(RouterManager.TAG, '跳转到重置密码页失败', error);
+      });
+    }
+  }
+
+  /** A.5 跳转重置密码页(从设置/账号安全进入,需登录) */
+  static navigateToResetPassword(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.RESET_PASSWORD);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到重置密码页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到第三方绑定页
+   * 
+   * @param platform 平台名称(如:wechat, qq)
+   * @param openId 第三方平台的 openId
+   */
+  static navigateToThirdPartyBinding(platform: string, openId: string): void {
+    // 使用 ARouter 统一跳转
+    ARouter.build("AUTH_THIRD_PARTY_BINDING")
+      .withString("platform", platform)
+      .withString("openId", openId)
+      .navigation()
+      .catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到第三方绑定页失败', error);
+    });
+  }
+  
+  // ========== 主界面路由 ==========
+  
+  /**
+   * 跳转到主界面
+   */
+  static navigateToMain(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.MAIN); // 应该解析为 'APP_MAIN'
+    LogHelper.d(RouterManager.TAG, `[navigateToMain] 开始跳转,pageUrl: ${pageUrl}`);
+    HMRouterMgr.to(pageUrl).pushAsync()
+      .then(() => {
+        LogHelper.d(RouterManager.TAG, '[navigateToMain] 跳转主界面成功');
+      })
+      .catch((error: Error) => {
+        LogHelper.e(RouterManager.TAG, '[navigateToMain] 跳转主界面失败', error);
+      });
+  }
+  
+  // ========== 社区相关路由 ==========
+  
+  /**
+   * 跳转到帖子详情页
+   * 
+   * @param postId 帖子ID
+   */
+  static async navigateToPostDetail(postId: number): Promise<void> {
+    // 使用 ARouter 统一跳转
+    ARouter.build("COMMUNITY_POST_DETAIL")
+      .withInt("postId", postId)
+      .navigation()
+      .catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到帖子详情页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到创建帖子页
+   */
+  static async navigateToCreatePost(): Promise<void> {
+    const canNavigate = await RouteInterceptorManager.check(RoutePath.COMMUNITY_CREATE_POST);
+    if (!canNavigate) {
+      return;
+    }
+    
+    const pageUrl = getRouteKeyFromPath(RoutePath.COMMUNITY_CREATE_POST);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到创建帖子页失败', error);
+    });
+  }
+  
+  // ========== 用户相关路由 ==========
+  
+  /**
+   * 跳转到个人资料页
+   */
+  static async navigateToPersonalInfo(): Promise<void> {
+    const canNavigate = await RouteInterceptorManager.check(RoutePath.USER_PERSONAL_INFO);
+    if (!canNavigate) {
+      return;
+    }
+    
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_PERSONAL_INFO);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到个人资料页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到设置页
+   */
+  static async navigateToSettings(): Promise<void> {
+    const canNavigate = await RouteInterceptorManager.check(RoutePath.USER_SETTINGS);
+    if (!canNavigate) {
+      return;
+    }
+    
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_SETTINGS);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到设置页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到账号管理页
+   */
+  static async navigateToAccountManage(): Promise<void> {
+    const canNavigate = await RouteInterceptorManager.check(RoutePath.USER_ACCOUNT_MANAGE);
+    if (!canNavigate) {
+      return;
+    }
+    
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_ACCOUNT_MANAGE);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到账号管理页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到活动列表页
+   */
+  static navigateToActivityList(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_ACTIVITY_LIST);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到活动列表页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到黑名单页
+   */
+  static navigateToBlacklist(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_BLACKLIST);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到黑名单页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到收藏列表页
+   */
+  static navigateToCollectList(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_COLLECT_LIST);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到收藏列表页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到联系我们页
+   */
+  static navigateToContact(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_CONTACT);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到联系我们页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到简单占位页
+   * 
+   * @param title 页面标题
+   */
+  static navigateToSimplePlaceholder(title: string): void {
+    // 使用 ARouter 统一跳转
+    ARouter.build("USER_SIMPLE_PLACEHOLDER")
+      .withString("title", title)
+      .navigation()
+      .catch((error: Error) => {
+        LogHelper.e(RouterManager.TAG, '跳转到简单占位页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到意见反馈页
+   */
+  static navigateToFeedback(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_FEEDBACK);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到意见反馈页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到邀友购车页
+   */
+  static navigateToInvite(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_INVITE);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到邀友购车页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到消息列表页
+   */
+  static navigateToMessageList(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_MESSAGE_LIST);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到消息列表页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到订单列表页
+   */
+  static navigateToOrderList(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_ORDER_LIST);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到订单列表页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到骑行统计页
+   */
+  static navigateToRidingStatistics(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_RIDING_STATISTICS);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到骑行统计页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到车辆列表页
+   */
+  static navigateToVehicleList(): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_VEHICLE_LIST);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到车辆列表页失败', error);
+    });
+  }
+  
+  /**
+   * 跳转到占位页
+   * 
+   * @param title 页面标题
+   */
+  static navigateToPlaceholder(title: string): void {
+    const pageUrl = getRouteKeyFromPath(RoutePath.USER_SIMPLE_PLACEHOLDER);
+    HMRouterMgr.to(pageUrl).pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到占位页失败', error);
+    });
+  }
+  
+  // ========== 车辆相关路由 ==========
+  
+  /**
+   * 跳转到车辆绑定页
+   */
+  static navigateToVehicleBind(): void {
+    ARouter.build('VEHICLE_BIND').skipInterceptor().navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到车辆绑定页失败', e);
+    });
+  }
+
+  /**
+   * 跳转到车辆绑定页并回填识别码(6.2.1 串联车辆绑定:扫码/手动输入后带参进入)
+   */
+  static navigateToVehicleBindWithCode(code: string): void {
+    ARouter.build('VEHICLE_BIND').withParam('code', code).skipInterceptor().navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到车辆绑定页失败', e);
+    });
+  }
+
+  /**
+   * 跳转到车辆扫码页(6.1.x 生命周期/权限/重试;6.2.2 需登录,未登录会拦截并回跳扫码页)
+   */
+  static navigateToVehicleQRScan(): void {
+    ARouter.build('QRCODE_SCAN').navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到扫码页失败', e);
+    });
+  }
+
+  /** 跳转绑定确认页(固定参数签名,避免 JSON.parse + 动态key) */
+  static navigateToVehicleBindConfirm(code: string, deviceName?: string): void {
+    const builder = ARouter.build('VEHICLE_BIND_CONFIRM');
+    builder.withParam('code', code);
+    if (deviceName !== undefined && deviceName !== '') {
+      builder.withParam('deviceName', deviceName);
+    }
+    builder.skipInterceptor().navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到绑定确认页失败', e);
+    });
+  }
+
+  /** 跳转车辆管理页 */
+  static navigateToVehicleManage(vehicleId: number): void {
+    ARouter.build('VEHICLE_MANAGE').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到车辆管理页失败', e);
+    });
+  }
+
+  /** 跳转骑行记录列表 */
+  static navigateToRidingRecordList(vehicleId: number): void {
+    ARouter.build('RIDING_RECORD_LIST').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到骑行记录列表失败', e);
+    });
+  }
+
+  /** 跳转骑行记录详情 */
+  static navigateToRidingRecordDetail(recordId: string): void {
+    ARouter.build('RIDING_RECORD_DETAIL').withParam('recordId', recordId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到骑行记录详情失败', e);
+    });
+  }
+
+  /** 跳转固件升级列表 */
+  static navigateToFirmwareUpgrade(vehicleId: number): void {
+    ARouter.build('FIRMWARE_UPGRADE').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到固件升级页失败', e);
+    });
+  }
+
+  /** 跳转固件升级详情 */
+  static navigateToFirmwareUpgradeDetail(vehicleId: number, firmwareId: number, firmwareName?: string, firmwareVersion?: string): void {
+    const builder = ARouter.build('FIRMWARE_UPGRADE_DETAIL')
+      .withParam('vehicleId', vehicleId)
+      .withParam('firmwareId', firmwareId);
+    if (firmwareName !== undefined) builder.withParam('firmwareName', firmwareName);
+    if (firmwareVersion !== undefined) builder.withParam('firmwareVersion', firmwareVersion);
+    builder.navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到固件升级详情失败', e);
+    });
+  }
+
+  /** P1 跳转地图页 */
+  static navigateToMap(vehicleId: number): void {
+    ARouter.build('MAP').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到地图页失败', e);
+    });
+  }
+
+  /** P1 跳转钥匙共享页 */
+  static navigateToKeyShare(vehicleId: number): void {
+    ARouter.build('KEY_SHARE').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到钥匙共享页失败', e);
+    });
+  }
+
+  /** P1 跳转电池详情页 */
+  static navigateToBatteryDetails(vehicleId: number): void {
+    ARouter.build('BATTERY_DETAILS').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到电池详情页失败', e);
+    });
+  }
+
+  /** P1 跳转蓝牙设备搜索页 */
+  static navigateToBluetoothDeviceSearch(): void {
+    ARouter.build('VEHICLE_BLE_SEARCH').navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到蓝牙设备搜索页失败', e);
+    });
+  }
+
+  /** P2 胎压 */
+  static navigateToTirePressure(vehicleId: number): void {
+    ARouter.build('TIRE_PRESSURE').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到胎压页失败', e);
+    });
+  }
+
+  /** P2 氛围灯设置 */
+  static navigateToAmbientLightSettings(vehicleId: number): void {
+    ARouter.build('AMBIENT_LIGHT_SETTINGS').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到氛围灯设置页失败', e);
+    });
+  }
+
+  /** P2 RGB 颜色选择(可选 callbackKey 用于回传) */
+  static navigateToRGBColorPicker(callbackKey?: string): void {
+    const b = ARouter.build('RGB_COLOR_PICKER');
+    if (callbackKey !== undefined) b.withParam('callbackKey', callbackKey);
+    b.navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到RGB选择页失败', e);
+    });
+  }
+
+  /** P2 开机密码设置 */
+  static navigateToSetStartupPassword(vehicleId: number): void {
+    ARouter.build('SET_STARTUP_PASSWORD').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到开机密码页失败', e);
+    });
+  }
+
+  /** P2 创建分享 */
+  static navigateToCreateShare(vehicleId: number): void {
+    ARouter.build('CREATE_SHARE').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到创建分享页失败', e);
+    });
+  }
+
+  /** P2 行车记录仪 */
+  static navigateToDrivingRecorder(vehicleId: number): void {
+    ARouter.build('DRIVING_RECORDER').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到行车记录仪页失败', e);
+    });
+  }
+
+  /** P2 智能周边 */
+  static navigateToSmartAccessories(vehicleId?: number): void {
+    const b = ARouter.build('SMART_ACCESSORIES');
+    if (vehicleId !== undefined && vehicleId > 0) b.withParam('vehicleId', vehicleId);
+    b.navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到智能周边页失败', e);
+    });
+  }
+
+  /** P2 车辆设置 */
+  static navigateToVehicleSettings(vehicleId: number): void {
+    ARouter.build('VEHICLE_SETTINGS').withParam('vehicleId', vehicleId).navigation().catch((e: Error) => {
+      LogHelper.e(RouterManager.TAG, '跳转到车辆设置页失败', e);
+    });
+  }
+
+  /**
+   * 返回上一页
+   */
+  static back(): void {
+    HMRouterMgr.popAsync();
+  }
+  
+  /**
+   * 替换当前页面
+   * 
+   * @param path 路由路径
+   * @param params 路由参数(可选)
+   */
+  static replace(path: string, params?: Record<string, Object>): void {
+    const pageUrl = getRouteKeyFromPath(path);
+    const builder = HMRouterMgr.to(pageUrl);
+    if (params) {
+      builder.withParam(params);
+    }
+    builder.pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, `替换页面失败: ${path}`, error);
+    });
+  }
+  
+  /**
+   * 清空路由栈并跳转
+   * 
+   * @param path 路由路径
+   * @param params 路由参数(可选)
+   */
+  static clearStack(path: string, params?: Record<string, Object>): void {
+    const pageUrl = getRouteKeyFromPath(path);
+    const builder = HMRouterMgr.to(pageUrl);
+    if (params) {
+      builder.withParam(params);
+    }
+    builder.pushAsync().catch((error: Error) => {
+      LogHelper.e(RouterManager.TAG, `清空栈并跳转失败: ${path}`, error);
+    });
+  }
+}
+

+ 13 - 18
base-common/src/main/ets/common/socketio/SocketIOManager.ets

@@ -1,7 +1,10 @@
 import { Context, UIAbility } from '@kit.AbilityKit';
-import { ILog, StorageImpl } from '@xdz/base-core';
+import { ILog, StorageImpl, StorageKeys } from '@xdz/base-core';
 import { SocketIORepositoryFactory } from '@xdz/capability-socketio';
-import { AuthManager } from '../auth/AuthManager';
+// AuthManager 已迁移到 entry 模块
+// TODO: 后续改为依赖注入方式,避免 base-common 直接依赖 entry 模块
+// 临时方案:使用动态导入或通过参数传入(当前先注释,后续优化)
+// import { AuthManager } from '../../../entry/src/main/ets/modules/auth/AuthManager';
 
 const TAG = "SocketIOManager";
 
@@ -100,26 +103,24 @@ export class SocketIOManager {
   static async onForeground(): Promise<void> {
     ILog.d(TAG, "App 进入前台,检查 SocketIO 连接状态");
     
-    // 检查是否已登录
-    if (!await AuthManager.isLoggedIn()) {
-      ILog.d(TAG, "用户未登录,跳过 SocketIO 重连");
+    // 检查是否已登录(通过 TokenStore 检查,避免直接依赖 AuthManager)
+    const token = await StorageImpl.getInstance().getString(StorageKeys.TOKEN_ACCESS);
+    if (!token || token === '') {
+      ILog.d(TAG, "用户未登录(Token 为空),跳过 SocketIO 重连");
       return;
     }
     
     // 在后台执行重连逻辑(使用 Promise,不依赖 ExecutorManager)
     Promise.resolve().then(async () => {
       try {
-        // 直接获取 SocketIORepository(不使用反射)
         const socketIORepository = SocketIORepositoryFactory.getInstance();
         
-        // 检查是否已连接
         if (socketIORepository.isConnected()) {
           ILog.d(TAG, "SocketIO 已连接,无需重连");
           return;
         }
         
-        // 检查 token 是否存在
-        const token = await StorageImpl.getInstance().getString("access_token");
+        const token = await StorageImpl.getInstance().getString(StorageKeys.TOKEN_ACCESS);
         if (!token || token === '') {
           ILog.w(TAG, "Token 为空,无法重连 SocketIO");
           return;
@@ -137,16 +138,10 @@ export class SocketIOManager {
             }, 2000);
           });
           
-          // 如果连接仍然失败,可能是 Token 过期,尝试刷新 Token 后重连
+          // 如果连接仍然失败,可能是 Token 过期
+          // TODO: 后续改为通过回调或事件通知的方式刷新 Token,避免直接依赖 AuthManager
           if (!socketIORepository.isConnected()) {
-            ILog.d(TAG, "连接失败,可能是 Token 过期,尝试刷新 Token 后重连");
-            const refreshedToken = await AuthManager.refreshTokenIfNeeded();
-            if (refreshedToken && refreshedToken !== token) {
-              ILog.d(TAG, "Token 已刷新,使用新 Token 重连");
-              await socketIORepository.checkAndReconnect(null, null);
-            } else {
-              ILog.w(TAG, "Token 刷新失败或未刷新,无法重连");
-            }
+            ILog.w(TAG, "SocketIO 连接失败,可能需要刷新 Token(请通过 AppInitializer 处理)");
           } else {
             ILog.d(TAG, "SocketIO 重连成功");
           }

+ 0 - 40
base-common/src/main/ets/common/ui/BasePage.ets

@@ -1,40 +0,0 @@
-import { PageHelper, PageState } from './PageHelper';
-
-/**
- * 页面基类(已废弃,推荐使用 PageHelper)
- * 
- * 由于 HarmonyOS 的 @Component 装饰器不支持类继承,
- * 请使用 PageHelper 工具类代替
- * 
- * @deprecated 使用 PageHelper 代替
- */
-export class BasePage implements PageState {
-  // 保留用于向后兼容,但推荐使用 PageHelper
-  loading: boolean = false;
-  error: string | null = null;
-  
-  showLoading(): void {
-    PageHelper.showLoading(this);
-  }
-  
-  hideLoading(): void {
-    PageHelper.hideLoading(this);
-  }
-  
-  showError(message: string): void {
-    PageHelper.showError(this, message);
-  }
-  
-  clearError(): void {
-    PageHelper.clearError(this);
-  }
-  
-  showSuccess(message: string): void {
-    PageHelper.showSuccess(message);
-  }
-  
-  showToast(message: string): void {
-    PageHelper.showToast(message);
-  }
-}
-

+ 6 - 2
base-common/src/main/ets/common/ui/BaseViewModel.ets

@@ -3,8 +3,12 @@ import { LogHelper } from '../log/LogHelper';
 /**
  * ViewModel 基类
  * 
- * 提供统一的 ViewModel 功能,与 Android 版本保持一致
- * 注意:MVVM 支持放在 UI 层,与 Android 的 BaseFragment/BaseActivity 位置一致
+ * 提供统一的 ViewModel 功能,用于管理页面业务逻辑和状态
+ * 
+ * HarmonyOS 推荐使用方式:
+ * - ViewModel 中使用普通属性管理状态
+ * - 页面中使用 @State viewModel,让 @State 自动响应 ViewModel 属性的变化
+ * - 不需要使用 StateFlow 或手动 observe
  */
 
 /**

+ 28 - 0
base-common/src/main/ets/common/ui/BreakpointHelper.ets

@@ -0,0 +1,28 @@
+/**
+ * 断点类型:与 float.json 三档尺寸对应
+ * - compact: 360vp 及以下
+ * - medium: 361 ~ 450vp
+ * - expanded: 451vp 及以上
+ */
+export type BreakpointType = 'compact' | 'medium' | 'expanded';
+
+/** 断点宽度阈值(vp 逻辑宽度,与 Android values-sw360dp/411/480 对应) */
+const WIDTH_COMPACT = 400;
+const WIDTH_EXPANDED = 450;
+
+/**
+ * 根据逻辑宽度(vp)返回断点
+ * 用于按设备宽度选择尺寸 token(1.2.3 尺寸策略)
+ *
+ * 页面可通过 onAreaChange 获取宽度(px 需按 density 换算为 vp)后调用,
+ * 或使用 display.getDefaultDisplaySync() 获取屏幕宽度后换算。
+ */
+export function getBreakpointFromWidth(widthVp: number): BreakpointType {
+  if (widthVp < WIDTH_COMPACT) {
+    return 'compact';
+  }
+  if (widthVp <= WIDTH_EXPANDED) {
+    return 'medium';
+  }
+  return 'expanded';
+}

+ 142 - 0
base-common/src/main/ets/common/ui/GlassmorphismAnimator.ets

@@ -0,0 +1,142 @@
+import { ILog } from '@xdz/base-core';
+
+const TAG = "GlassmorphismAnimator";
+
+/**
+ * 玻璃态动画辅助类
+ * 
+ * 提供玻璃态效果的动画功能,包括:
+ * - 呼吸效果(透明度动画)
+ * - 浮动效果(位置动画)
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { GlassmorphismAnimator } from '@xdz/base-common';
+ * 
+ * // 添加呼吸效果
+ * GlassmorphismAnimator.addBreathingEffect(this.myComponent);
+ * 
+ * // 添加浮动效果
+ * GlassmorphismAnimator.addFloatingEffect(this.myComponent);
+ * ```
+ * 
+ * 注意:HarmonyOS 的动画实现方式与 Android 不同
+ * 这里提供接口定义,实际动画需要在组件中使用 @AnimatableExtend 或 animateTo
+ */
+export class GlassmorphismAnimator {
+  
+  /**
+   * 添加呼吸效果(透明度动画)
+   * 
+   * 注意:HarmonyOS 中动画需要在组件内部使用 animateTo 或 @AnimatableExtend
+   * 这里提供辅助方法,返回动画配置对象,供组件使用
+   * 
+   * @param component 组件实例(HarmonyOS 中不使用,保留以保持接口一致)
+   * @param duration 动画持续时间(毫秒),默认 2000
+   * @param alphaMin 最小透明度(0-1),默认 0.3
+   * @param alphaMax 最大透明度(0-1),默认 1.0
+   * @return 动画配置对象(供组件使用)
+   */
+  static addBreathingEffect(
+    component: object,
+    duration: number = 2000,
+    alphaMin: number = 0.3,
+    alphaMax: number = 1.0
+  ): BreathingEffectConfig {
+    ILog.d(TAG, `添加呼吸效果: duration=${duration}, alphaMin=${alphaMin}, alphaMax=${alphaMax}`);
+    
+    return {
+      duration: duration,
+      alphaMin: alphaMin,
+      alphaMax: alphaMax
+    };
+  }
+  
+  /**
+   * 添加浮动效果(位置动画)
+   * 
+   * 注意:HarmonyOS 中动画需要在组件内部使用 animateTo 或 @AnimatableExtend
+   * 这里提供辅助方法,返回动画配置对象,供组件使用
+   * 
+   * @param component 组件实例(HarmonyOS 中不使用,保留以保持接口一致)
+   * @param duration 动画持续时间(毫秒),默认 3000
+   * @param offset 浮动偏移量(像素),默认 10
+   * @return 动画配置对象(供组件使用)
+   */
+  static addFloatingEffect(
+    component: object,
+    duration: number = 3000,
+    offset: number = 10
+  ): FloatingEffectConfig {
+    ILog.d(TAG, `添加浮动效果: duration=${duration}, offset=${offset}`);
+    
+    return {
+      duration: duration,
+      offset: offset
+    };
+  }
+}
+
+/**
+ * 呼吸效果配置
+ */
+export interface BreathingEffectConfig {
+  duration: number;
+  alphaMin: number;
+  alphaMax: number;
+}
+
+/**
+ * 浮动效果配置
+ */
+export interface FloatingEffectConfig {
+  duration: number;
+  offset: number;
+}
+
+/**
+ * 使用示例(在组件中):
+ * 
+ * ```typescript
+ * @Component
+ * struct MyComponent {
+ *   @State private opacity: number = 1.0;
+ *   @State private translateY: number = 0;
+ *   
+ *   aboutToAppear() {
+ *     // 获取呼吸效果配置
+ *     const breathingConfig = GlassmorphismAnimator.addBreathingEffect(this, 2000, 0.3, 1.0);
+ *     
+ *     // 使用 animateTo 实现呼吸效果
+ *     animateTo({
+ *       duration: breathingConfig.duration,
+ *       iterations: -1, // 无限循环
+ *       curve: Curve.EaseInOut
+ *     }, () => {
+ *       this.opacity = breathingConfig.alphaMax;
+ *     });
+ *     
+ *     // 获取浮动效果配置
+ *     const floatingConfig = GlassmorphismAnimator.addFloatingEffect(this, 3000, 10);
+ *     
+ *     // 使用 animateTo 实现浮动效果
+ *     animateTo({
+ *       duration: floatingConfig.duration,
+ *       iterations: -1,
+ *       curve: Curve.EaseInOut
+ *     }, () => {
+ *       this.translateY = floatingConfig.offset;
+ *     });
+ *   }
+ *   
+ *   build() {
+ *     Column() {
+ *       Text('Glassmorphism')
+ *         .opacity(this.opacity)
+ *         .translate({ y: this.translateY })
+ *     }
+ *   }
+ * }
+ * ```
+ */
+

+ 63 - 0
base-common/src/main/ets/common/ui/LayoutConstants.ets

@@ -0,0 +1,63 @@
+/**
+ * 布局常量(统一标准)
+ * 参考 Android dimens.xml,确保所有页面使用相同的间距标准
+ * 
+ * 使用方式:
+ * ```typescript
+ * import { LayoutConstants } from '@xdz/base-common';
+ * 
+ * Row()
+ *   .height(LayoutConstants.TOP_BAR_HEIGHT)
+ *   .margin({ top: LayoutConstants.TOP_SAFE_AREA })
+ * ```
+ */
+export class LayoutConstants {
+  /**
+   * 顶部安全区域(状态栏下方间距)
+   * 参考 Android: top_safe_area = 40dp (24dp 状态栏 + 16dp 额外间距)
+   * HarmonyOS 使用 px,统一使用 16px 作为顶部间距
+   * 
+   * 所有页面的顶部元素统一使用这个值,避免高高低低不统一!
+   */
+  static readonly TOP_SAFE_AREA: number = 16; // 16px
+  
+  /**
+   * 顶部导航栏标准高度
+   * 参考 Android: 56dp
+   * HarmonyOS 统一使用 56px
+   */
+  static readonly TOP_BAR_HEIGHT: number = 56; // 56px
+  
+  /**
+   * 顶部导航栏底部间距
+   * 导航栏和内容之间的间距
+   */
+  static readonly TOP_BAR_BOTTOM_MARGIN: number = 12; // 12px
+  
+  /**
+   * 标准间距(小)
+   */
+  static readonly SPACE_SMALL: number = 8;
+  
+  /**
+   * 标准间距(中)
+   */
+  static readonly SPACE_MEDIUM: number = 16;
+  
+  /**
+   * 标准间距(大)
+   */
+  static readonly SPACE_LARGE: number = 24;
+  
+  /**
+   * 底部安全区域(Home Indicator 高度)
+   * 参考 Android: navigation_bar_height = 48dp
+   * HarmonyOS 底部 Home Indicator 约为 34px
+   */
+  static readonly BOTTOM_SAFE_AREA: number = 34;
+  
+  /**
+   * 页面水平内边距(左右)
+   */
+  static readonly PAGE_HORIZONTAL_PADDING: number = 16;
+}

+ 9 - 15
base-common/src/main/ets/common/ui/MessageHelper.ets

@@ -63,7 +63,6 @@ export class MessageHelper {
    * @param message 消息内容
    */
   static showToast(message: string): void {
-    // 使用已弃用的API,待迁移
     promptAction.showToast({
       message: message,
       duration: MessageHelper.toastDuration
@@ -98,36 +97,31 @@ export class MessageHelper {
       interface PromptButton {
         text: string;
         color: string;
-        action: () => void;
       }
       
       const buttons: PromptButton[] = options.buttons?.map(btn => {
         const promptBtn: PromptButton = {
           text: btn.text,
-          color: btn.color || '#007DFF',
-          action: () => {
-            if (btn.action) {
-              btn.action();
-            }
-            resolve();
-          }
+          color: btn.color || '#007DFF'
         };
         return promptBtn;
       }) || [
         {
           text: '确定',
-          color: '#007DFF',
-          action: () => resolve()
+          color: '#007DFF'
         }
       ];
       
-      const dialogOptions: promptAction.ShowDialogOptions = {
+      promptAction.showDialog({
         title: options.title,
         message: options.message,
         buttons: buttons
-      };
-      
-      promptAction.showDialog(dialogOptions);
+      }, (err, result) => {
+        if (!err && result !== undefined && typeof result === 'number' && options.buttons && options.buttons[result] && options.buttons[result].action) {
+          options.buttons[result].action!();
+        }
+        resolve();
+      });
     });
   }
 }

+ 0 - 0
base-common/src/main/ets/common/ui/PageHelper.ets


Some files were not shown because too many files changed in this diff