oxFaceAndroid
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

10 KiB

订单核销结果页面重构说明

版本更新记录

v2.0.2 - 502错误处理逻辑优化 (2025-09-10)

问题描述: 尽管在 v2.0.1 中添加了502错误处理逻辑,但在实际测试中发现系统仍会对502错误进行重试。这是因为502错误检查逻辑放在了重试条件内部,导致逻辑顺序有问题。

根本原因: 在 NetworkStabilityManager.RetryInterceptor 中,502错误的检查逻辑被放置在 if (retryCount < maxRetryCount && response.code() >= 500) 条件内部,这意味着只有在还有重试机会时才会检查502错误,导致逻辑不够优先。

解决方案

  1. 重构重试拦截器逻辑

    • 将502错误检查提前到重试条件之前
    • 确保502错误能够立即被捕获并直接返回,不受重试次数限制

    修改前的问题代码:

    if (retryCount < maxRetryCount && response.code() >= 500) {
        if (response.code() == 502) {
            // 502处理逻辑
        }
        // 其他重试逻辑
    }
    

    修改后的正确代码:

    // 对于502 Bad Gateway错误,直接返回给用户,不进行重试
    if (response.code() == 502) {
        Log.w(TAG, "服务器错误 " + response.code() + " (Bad Gateway),直接返回错误");
        return response;
    }
       
    // 其他5xx错误的重试逻辑
    if (retryCount < maxRetryCount && response.code() >= 500) {
        // 重试逻辑
    }
    
  2. 验证修复效果

    • 502错误将不再出现重试日志
    • 错误信息直接传递到核销结果页面
    • 用户体验得到进一步改善

效果

  • 502错误立即被捕获,不进入重试逻辑
  • 消除了"准备重试"的误导性日志信息
  • 错误响应更加及时
  • 用户等待时间进一步缩短

v2.0.1 - 502错误处理优化 (2025-09-10)

问题描述: 核销接口返回 502 Bad Gateway 错误时,系统会自动重试,用户希望直接显示错误信息而不重试。

解决方案

  1. 修改网络重试逻辑

    • 在 NetworkStabilityManager.RetryInterceptor 中添加对 502 错误的特殊处理
    • 502 Bad Gateway 错误直接返回给用户,不进行重试
    // 对于502 Bad Gateway错误,直接返回给用户,不进行重试
    if (response.code() == 502) {
        Log.w(TAG, "服务器错误 " + response.code() + " (Bad Gateway),直接返回错误");
        return response;
    }
    
  2. 优化错误信息显示

    • 在 NetworkUtils.verifyOrder 中优化 502 错误信息
    • 为 502 错误提供更友好的描述:"服务器暂时不可用,请稍后再试"
    if (response.code() == 502) {
        errorMessage = "服务器暂时不可用,请稍后再试";
    }
    
  3. 错误信息传递

    • 错误信息通过 OrderSelectionActivity.onError 传递到核销结果页面
    • 状态设为 "核销失败",消息显示具体的错误原因

效果

  • 502 错误不再重试,直接显示给用户
  • 提供更友好的错误信息描述
  • 错误信息正确显示在核销结果页面
  • 提升用户体验,减少等待时间

v2.0.0 - 初始重构版本 (2025-09-10)

(之前的重构内容...)


问题分析

原始问题

在执行次卡核销(order_type=1)时出现错误:

Expected BEGIN_OBJECT but was STRING at line 1 column 345 path $.data.result.info

根本原因

服务端对于不同订单类型返回的 info 字段数据结构不一致:

  • 次卡核销 (order_type=1): info 字段为字符串类型

    "info": "平时"
    
  • 年月卡核销 (order_type=3): info 字段为对象类型

    "info": {
      "card_no": "2509085314",
      "rest_number": 5,
      "status": 1,
      "verify_desc": "人脸验证...",
      "verify_time": "2025-09-10 11:26:36",
      "verify_type": 2
    }
    

原有代码没有根据 order_type 正确处理这种数据结构差异。

解决方案

1. 修复 PadApiService.VerifyOrderResult 数据模型

核心问题修复:将 VerifyOrderResult 类中的 info 字段从固定的 VerifyOrderInfo 对象类型改为灵活的 JsonElement 类型。

// 修复前(有问题的代码)
@SerializedName("info")
private VerifyOrderInfo info;  // 只能处理对象类型

// 修复后(正确的代码)
@SerializedName("info")
private com.google.gson.JsonElement info;  // 支持字符串和对象类型

添加辅助方法

// 获取字符串类型的info(次卡核销)
public String getInfoAsString() {
    if (info != null && info.isJsonPrimitive()) {
        return info.getAsString();
    }
    return "";
}

// 获取对象类型的info(年月卡核销)
public JsonObject getInfoAsJsonObject() {
    if (info != null && info.isJsonObject()) {
        return info.getAsJsonObject();
    }
    return null;
}

2. 重构 OrderVerificationResultActivity

1.1 数据结构优化

// 原始字段
private TextView tvTitle, tvOrderNo, tvVerificationCode, tvOrderType, tvCardNo, tvStatus, tvMessage, tvProject;
private String orderNo, verificationCode, orderType, cardNo, status, message, project;

// 重构后字段
private TextView tvTitle, tvStatus, tvMessage;
private ScrollView scrollContent;
private LinearLayout layoutContent;
private int orderType; // 改为int类型
private JsonElement orderInfo; // 支持多种数据类型
private PadApiService.VerifyOrderResult verifyResult; // 完整核销结果

1.2 布局文件重构

<!-- 原始静态布局 -->
<LinearLayout android:id="@+id/ll_order_info">
  <!-- 固定的订单号、验证码、订单类型等字段 -->
</LinearLayout>

<!-- 重构后动态布局 -->
<ScrollView android:id="@+id/scroll_content">
  <LinearLayout android:id="@+id/layout_content" />
</ScrollView>

1.3 动态内容生成

根据订单类型动态生成不同的显示内容:

private void buildOrderTypeSpecificContent() {
    switch (orderType) {
        case 0: // 场次核销
            buildSiteContent();
            break;
        case 1: // 人次核销
            buildPeopleContent();
            break;
        case 3: // 年月卡
            buildCardContent();
            break;
        case 5: // 课程
            buildCourseContent();
            break;
    }
}

2. 根据 uni 端逻辑实现不同订单类型展示

2.1 场次核销 (order_type=0)

显示场次信息列表:

  • 场馆名称
  • 开始时间

2.2 人次核销 (order_type=1)

显示人次相关信息:

  • 验证码
  • 订单编号
  • 有效时间
  • 预订信息(info 字符串)

2.3 年月卡 (order_type=3)

显示年月卡信息:

  • 验证码
  • 名称(项目)
  • 卡号(NO.xxx)
  • 核销方式
  • 核销时间

2.4 课程 (order_type=5)

显示课程信息:

  • 上课时间
  • 上课教练
  • 上课地点
  • 课程名称
  • 订单编号
  • 签到方式
  • 签到时间

3. 数据传递优化

3.1 传递完整核销结果

// 在 OrderSelectionActivity 中
if (data != null) {
    intent.putExtra("verify_result", new Gson().toJson(data));
}

3.2 解析完整数据结构

// 在 OrderVerificationResultActivity 中
String verifyResultJson = intent.getStringExtra("verify_result");
if (verifyResultJson != null) {
    verifyResult = gson.fromJson(verifyResultJson, PadApiService.VerifyOrderResponse.class).getResult();
    orderInfo = JsonParser.parseString(gson.toJson(verifyResult.getInfo()));
}

4. 兼容性处理

4.1 JsonElement 处理

private String getJsonString(JsonObject jsonObject, String key, String defaultValue) {
    if (jsonObject.has(key) && !jsonObject.get(key).isJsonNull()) {
        return jsonObject.get(key).getAsString();
    }
    return defaultValue;
}

4.2 不同数据类型检查

// 字符串类型处理
if (orderInfo != null && orderInfo.isJsonPrimitive()) {
    String bookingInfo = orderInfo.getAsString();
}

// 对象类型处理
if (orderInfo != null && orderInfo.isJsonObject()) {
    JsonObject cardInfo = orderInfo.getAsJsonObject();
}

优势分析

1. 数据结构兼容性

  • 支持 info 字段的字符串和对象两种类型
  • 根据 order_type 智能选择处理方式
  • 避免 JSON 解析异常

2. 界面显示灵活性

  • 动态生成内容,支持不同订单类型
  • 滚动视图支持长内容显示
  • 统一的界面风格和交互

3. 代码可维护性

  • 模块化的内容构建方法
  • 清晰的数据传递流程
  • 完善的错误处理机制

4. 用户体验

  • 针对不同订单类型优化信息展示
  • 保持与 uni 端一致的信息结构
  • 友好的错误提示和状态显示

测试验证

创建了完整的单元测试来验证:

  • 次卡核销数据解析
  • 年月卡核销数据解析
  • 订单类型名称转换
  • 验证码格式化
  • 使用时长格式化

使用说明

1. 次卡核销场景

系统会自动检测 order_type=1,将 info 字段作为字符串处理,显示预订信息。

2. 年月卡核销场景

系统会自动检测 order_type=3,将 info 字段作为对象处理,提取卡号、核销方式等详细信息。

3. 其他订单类型

支持场次(order_type=0)和课程(order_type=5)核销,根据相应的数据结构显示内容。

注意事项

  1. 数据完整性: 确保从上级页面传递完整的 verify_result 数据
  2. 错误处理: 当数据解析失败时,会降级显示基本订单信息
  3. 向后兼容: 保持与现有调用方式的兼容性
  4. 性能优化: 使用动态布局生成,避免冗余的视图创建

通过这次重构,彻底解决了不同订单类型核销时的数据结构不兼容问题,提升了用户体验和系统稳定性。