Selaa lähdekoodia

fix:无网络状态答题逻辑优化

ythtc 3 viikkoa sitten
vanhempi
commit
922afde704
1 muutettua tiedostoa jossa 87 lisäystä ja 33 poistoa
  1. 87 33
      VenusKitto/Power/QuizStageController.swift

+ 87 - 33
VenusKitto/Power/QuizStageController.swift

@@ -1215,7 +1215,7 @@ class QuizStageController: UIViewController, ATAdLoadingDelegate, ATBannerDelega
         guard loadingOverlay == nil else { return }
         let overlay = UIView()
         overlay.translatesAutoresizingMaskIntoConstraints = false
-        overlay.backgroundColor = UIColor.black.withAlphaComponent(0.35)
+        overlay.backgroundColor = UIColor.clear
         overlay.isUserInteractionEnabled = true  // block touches
 
         let spinner = UIActivityIndicatorView(style: .large)
@@ -1670,8 +1670,49 @@ class QuizStageController: UIViewController, ATAdLoadingDelegate, ATBannerDelega
         let selectedId: String?
         let isFirst = (selectedButton == choiceBtnA)
         if isFirst { selectedId = option1ItemId } else { selectedId = option2ItemId }
+        
+        guard let sid = selectedId else {
+            print("[答题] 选项ID为空")
+            resetAnswerState()
+            return
+        }
+
+        // 显示加载状态
+        showSystemLoading()
+//        verdictLabel.text = "提交中..."
 
-        // Always显示正确答案标记
+        // 计算答题耗时
+        let durationSec: Int = {
+            if let start = questionStartAt { return max(0, Int(Date().timeIntervalSince(start))) }
+            return 0
+        }()
+        
+        // 先请求API,成功后再显示结果
+        answerQuestion(questionId: q.id, itemId: sid, duration: durationSec, selectedButton: selectedButton) { [weak self] success in
+            guard let self = self else { return }
+            
+            DispatchQueue.main.async {
+                self.hideSystemLoading()
+                
+                if success {
+                    // API成功,显示答题结果
+                    self.showAnswerResult(question: q, selectedId: sid, selectedButton: selectedButton, isFirst: isFirst)
+                    
+                    // 1秒后进入下一题
+                    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
+                        self?.goToNextQuestion()
+                    }
+                } else {
+                    // API失败,重置状态允许重新答题
+                    self.resetAnswerState()
+                    self.showToast(message: "提交失败,请重试")
+                }
+            }
+        }
+    }
+    
+    // 显示答题结果(正确/错误标记)
+    private func showAnswerResult(question: QAQuestion, selectedId: String, selectedButton: UIButton, isFirst: Bool) {
         let correctImage = UIImage(named: "res_cwqxdp40")
         let wrongImage = UIImage(named: "res_4h4cvu8h")
 
@@ -1680,11 +1721,11 @@ class QuizStageController: UIViewController, ATAdLoadingDelegate, ATBannerDelega
         markB.isHidden = true
 
         // 正确项标绿勾
-        if option1ItemId == q.correctItemId { markA.image = correctImage; markA.isHidden = false }
-        if option2ItemId == q.correctItemId { markB.image = correctImage; markB.isHidden = false }
+        if option1ItemId == question.correctItemId { markA.image = correctImage; markA.isHidden = false }
+        if option2ItemId == question.correctItemId { markB.image = correctImage; markB.isHidden = false }
 
         // 如果选错,则在所选按钮旁显示红叉
-        let isCorrect = (selectedId == q.correctItemId)
+        let isCorrect = (selectedId == question.correctItemId)
         if !isCorrect {
             if isFirst { markA.image = wrongImage; markA.isHidden = false }
             else { markB.image = wrongImage; markB.isHidden = false }
@@ -1699,40 +1740,48 @@ class QuizStageController: UIViewController, ATAdLoadingDelegate, ATBannerDelega
         } else {
             selectedButton.setBackgroundImage(UIImage(named: "res_zup626a7"), for: .normal)
         }
-
-        // 计算答题耗时并上报
-        let durationSec: Int = {
-            if let start = questionStartAt { return max(0, Int(Date().timeIntervalSince(start))) }
-            return 0
-        }()
-        if let sid = selectedId {
-            answerQuestion(questionId: q.id, itemId: sid, duration: durationSec)
-        }
-
-        // 1秒后进入下一题/结束
-        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
-            self?.goToNextQuestion()
-        }
+    }
+    
+    // 重置答题状态(用于失败时恢复)
+    private func resetAnswerState() {
+        isAnswering = false
+        
+        // 恢复按钮状态(根据体力判断)
+        let currentPower = UserDefaults.standard.object(forKey: "power") as? Int ?? 0
+        let enabled = currentPower > 0
+        choiceBtnA.isEnabled = enabled
+        choiceBtnB.isEnabled = enabled
+        
+        // 恢复按钮背景
+        choiceBtnA.setBackgroundImage(UIImage(named: "res_o67j6d3t"), for: .normal)
+        choiceBtnB.setBackgroundImage(UIImage(named: "res_o67j6d3t"), for: .normal)
+        
+        // 隐藏标记
+        markA.isHidden = true
+        markB.isHidden = true
+        
+        // 恢复提示文字
+        verdictLabel.text = "请选择正确答案"
     }
     
     // MARK: - Answer Question API
-    private func answerQuestion(questionId: String, itemId: String, duration: Int) {
+    private func answerQuestion(questionId: String, itemId: String, duration: Int, selectedButton: UIButton, completion: @escaping (Bool) -> Void) {
         guard let url = URL(string: apiBaseURL + answerQuestionPath) else {
             print("[Answer] Invalid URL")
+            completion(false)
             return
         }
         let userId = accountInfo?.userId ?? (UserDefaults.standard.string(forKey: "roleID") ?? "")
         guard !userId.isEmpty else {
             print("[Answer] Missing userId")
-            DispatchQueue.main.async { [weak self] in
-                self?.showToast(message: "缺少用户ID,无法上报作答")
-            }
+            completion(false)
             return
         }
 
         var request = URLRequest(url: url)
         request.httpMethod = "POST"
         request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        request.timeoutInterval = 15 // 设置15秒超时
         let body: [String: Any] = [
             "duration": duration,
             "itemId": itemId,
@@ -1758,21 +1807,20 @@ class QuizStageController: UIViewController, ATAdLoadingDelegate, ATBannerDelega
             }
             if let error = error {
                 print("[Answer] error: \(error)")
-                DispatchQueue.main.async { [weak self] in
-                    self?.showToast(message: "网络异常,作答上报失败")
-                }
+                completion(false)
                 return
             }
             guard let data = data,
                   let obj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
+                print("[Answer] Invalid response data")
+                completion(false)
                 return
             }
             let code = obj["code"] as? Int ?? 0
             if code != 200 {
                 let msg = (obj["message"] as? String) ?? (obj["msg"] as? String) ?? "作答上报失败"
-                DispatchQueue.main.async { [weak self] in
-                    self?.showToast(message: msg)
-                }
+                print("[Answer] Response code not 200: \(msg)")
+                completion(false)
                 return
             }
 
@@ -1791,11 +1839,14 @@ class QuizStageController: UIViewController, ATAdLoadingDelegate, ATBannerDelega
             }
 
             DispatchQueue.main.async { [weak self] in
-                guard let self = self else { return }
+                guard let self = self else { 
+                    completion(false)
+                    return 
+                }
                 // 1) 扣体力
-        let currentPower = UserDefaults.standard.object(forKey: "power") as? Int ?? 0
-        let newPower = max(0, currentPower - 1)
-        self.staminaBadge.setTitle("体力:\(newPower)", for: .normal)
+                let currentPower = UserDefaults.standard.object(forKey: "power") as? Int ?? 0
+                let newPower = max(0, currentPower - 1)
+                self.staminaBadge.setTitle("体力:\(newPower)", for: .normal)
                 self.applyPowerToOptionButtons(newPower)
                 UserDefaults.standard.set(newPower, forKey: "power")
                 if newPower == 0 { self.showToast(message: "体力不足,请先领取") }
@@ -1842,6 +1893,9 @@ class QuizStageController: UIViewController, ATAdLoadingDelegate, ATBannerDelega
                     self.accountInfo = info
                     self.activePowerPopup?.configure(with: info)
                 }
+                
+                // API请求成功,调用完成回调
+                completion(true)
             }
         }.resume()
     }