# 订单核销结果页面重构说明 ## 版本更新记录 ### 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错误能够立即被捕获并直接返回,不受重试次数限制 修改前的问题代码: ```java if (retryCount < maxRetryCount && response.code() >= 500) { if (response.code() == 502) { // 502处理逻辑 } // 其他重试逻辑 } ``` 修改后的正确代码: ```java // 对于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](file://c:\Users\mate1\Desktop\CODE\Android\oxFaceAndroid\app\src\main\java\com\ouxuan\oxface\network\NetworkStabilityManager.java#L212-L293) 中添加对 502 错误的特殊处理 - 502 Bad Gateway 错误直接返回给用户,不进行重试 ```java // 对于502 Bad Gateway错误,直接返回给用户,不进行重试 if (response.code() == 502) { Log.w(TAG, "服务器错误 " + response.code() + " (Bad Gateway),直接返回错误"); return response; } ``` 2. **优化错误信息显示**: - 在 [NetworkUtils.verifyOrder](file://c:\Users\mate1\Desktop\CODE\Android\oxFaceAndroid\app\src\main\java\com\ouxuan\oxface\network\utils\NetworkUtils.java#L722-L765) 中优化 502 错误信息 - 为 502 错误提供更友好的描述:"服务器暂时不可用,请稍后再试" ```java if (response.code() == 502) { errorMessage = "服务器暂时不可用,请稍后再试"; } ``` 3. **错误信息传递**: - 错误信息通过 [OrderSelectionActivity.onError](file://c:\Users\mate1\Desktop\CODE\Android\oxFaceAndroid\app\src\main\java\com\ouxuan\oxface\orderOX\OrderSelectionActivity.java#L414-L444) 传递到核销结果页面 - 状态设为 "核销失败",消息显示具体的错误原因 **效果**: - ✅ 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` 字段为字符串类型 ```json "info": "平时" ``` - **年月卡核销 (order_type=3)**: `info` 字段为对象类型 ```json "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](file://c:\Users\mate1\Desktop\CODE\Android\oxFaceAndroid\app\src\main\java\com\ouxuan\oxface\network\api\PadApiService.java#L1287-L1322) 类中的 [info](file://c:\Users\mate1\Desktop\CODE\Android\oxFaceAndroid\app\src\main\java\com\ouxuan\oxface\network\api\PadApiService.java#L1311-L1312) 字段从固定的 `VerifyOrderInfo` 对象类型改为灵活的 `JsonElement` 类型。 ```java // 修复前(有问题的代码) @SerializedName("info") private VerifyOrderInfo info; // 只能处理对象类型 // 修复后(正确的代码) @SerializedName("info") private com.google.gson.JsonElement info; // 支持字符串和对象类型 ``` **添加辅助方法**: ```java // 获取字符串类型的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 数据结构优化 ```java // 原始字段 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 布局文件重构 ```xml ``` #### 1.3 动态内容生成 根据订单类型动态生成不同的显示内容: ```java 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 传递完整核销结果 ```java // 在 OrderSelectionActivity 中 if (data != null) { intent.putExtra("verify_result", new Gson().toJson(data)); } ``` #### 3.2 解析完整数据结构 ```java // 在 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 处理 ```java 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 不同数据类型检查 ```java // 字符串类型处理 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. **性能优化**: 使用动态布局生成,避免冗余的视图创建 通过这次重构,彻底解决了不同订单类型核销时的数据结构不兼容问题,提升了用户体验和系统稳定性。