173 lines
6.1 KiB
Dart
173 lines
6.1 KiB
Dart
/// ============================================================
|
||
/// 【课堂习题 · 数据加载】(1:1 迁移 Vue exerciseLoad.js)
|
||
///
|
||
/// - loadStartOvercome:edit 模式,GetRecordData + GetListByRecordQuestion,
|
||
/// 解析题目、追加 sort、补 hasOptionChildrenQuestion、挂学科 id;
|
||
/// - loadSubmitReport:view 模式,GetSubmitReport,错题模式过滤重排。
|
||
///
|
||
/// 调试:loadStartOvercome 在接口返回后会(仅 kDebugMode)追加
|
||
/// assets/mock/class_exercises_edit.json(取自 Vue exerciseLoad.js)。
|
||
/// ============================================================
|
||
library;
|
||
|
||
import 'dart:convert';
|
||
|
||
import 'package:flutter/foundation.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:new_learn/core/api/conquerPackage/classExercises/api.dart';
|
||
import 'package:new_learn/core/utils/question/exam_answer_card.dart';
|
||
import 'package:new_learn/core/utils/question/question_constant.dart';
|
||
import 'package:new_learn/core/utils/question/question_parser.dart';
|
||
import 'package:new_learn/features/conquerPackage/classExercises/controllers/exercise_session.dart';
|
||
import 'package:new_learn/features/conquerPackage/classExercises/controllers/exercise_sort.dart';
|
||
import 'package:new_learn/features/conquerPackage/classExercises/models/question_model.dart';
|
||
|
||
class ExerciseLoadResult {
|
||
const ExerciseLoadResult({
|
||
required this.recordId,
|
||
required this.navBarTitle,
|
||
required this.baseSubjectId,
|
||
required this.questions,
|
||
required this.originalMaxSort,
|
||
});
|
||
|
||
final String recordId;
|
||
final String navBarTitle;
|
||
final int? baseSubjectId;
|
||
final List<QuestionModel> questions;
|
||
|
||
/// view 全量题号最大值(错题模式下供页面保留原始题号总数)
|
||
final int originalMaxSort;
|
||
}
|
||
|
||
class ExerciseLoad {
|
||
ExerciseLoad._();
|
||
|
||
/// edit 模式加载(对标 loadStartOvercome)
|
||
///
|
||
/// [inputRecordId] 路由带入的 recordId;[currentIndex] 为起始大题索引,
|
||
/// 该题会写入当前 startTime;[baseSubjectIdOverride] 为路由/base 传入的
|
||
/// 学科 id(对应 Vue 的 baseSubjectId ?? resRecord.baseSubjectId)。
|
||
static Future<ExerciseLoadResult> loadStartOvercome({
|
||
required String inputRecordId,
|
||
int currentIndex = 0,
|
||
int? baseSubjectIdOverride,
|
||
}) async {
|
||
final api = ClassExercisesApi.instance;
|
||
final resRecord = await api.getRecordData(inputRecordId);
|
||
final resList = await api.getListByRecordQuestion(inputRecordId);
|
||
|
||
// 接口照常请求;debug 测试时再把 exerciseLoad.js 里的 JSON 试题追加进去
|
||
await _injectDebugQuestions(resList.items);
|
||
|
||
final navBarTitle = '${resRecord.name}专项智能攻克';
|
||
final subjectId = baseSubjectIdOverride ?? resRecord.baseSubjectId;
|
||
final subjectType = getSubjectTypeById(subjectId) ?? 0;
|
||
|
||
final parsed = <Map<String, dynamic>>[];
|
||
for (var i = 0; i < resList.items.length; i++) {
|
||
final item = resList.items[i];
|
||
if (i == currentIndex) {
|
||
item['startTime'] = getCurrentISO();
|
||
}
|
||
// 1=图片作答 / 手写;0=输入框
|
||
item['iSFilllankItemUpload'] = subjectType;
|
||
parsed.add(parseQuestionData(item, mergeOriginalChilds: true));
|
||
}
|
||
|
||
var list = appendQuestionSort(parsed);
|
||
list = appendExamQuestionChildOptionStatus(list, subjectId);
|
||
|
||
final bsid = subjectId;
|
||
for (final q in list) {
|
||
q['baseSubjectId'] = bsid;
|
||
}
|
||
|
||
return ExerciseLoadResult(
|
||
recordId: resRecord.recordId,
|
||
navBarTitle: navBarTitle,
|
||
baseSubjectId: bsid,
|
||
questions: list.map(QuestionModel.new).toList(),
|
||
originalMaxSort: 0,
|
||
);
|
||
}
|
||
|
||
/// view 模式加载(对标 loadSubmitReport)
|
||
///
|
||
/// [isWrong] 为 true 时只保留答错题并重排 wrongSort,同时把起始索引置 0
|
||
/// (调用方不要再用旧 currentIndex)。
|
||
static Future<ExerciseLoadResult> loadSubmitReport({
|
||
required String packId,
|
||
bool isWrong = false,
|
||
int currentIndex = 0,
|
||
}) async {
|
||
final api = ClassExercisesApi.instance;
|
||
final res = await api.getSubmitReport(packId);
|
||
|
||
final navBarTitle = '${res.name}专项智能攻克';
|
||
final subjectType = getSubjectTypeById(res.baseSubjectId) ?? 0;
|
||
|
||
final parsed = <Map<String, dynamic>>[];
|
||
for (var i = 0; i < res.questions.length; i++) {
|
||
final item = res.questions[i];
|
||
if (i == currentIndex) {
|
||
item['startTime'] = getCurrentISO();
|
||
}
|
||
item['iSFilllankItemUpload'] = subjectType;
|
||
parsed.add(parseQuestionData(item, mergeOriginalChilds: true));
|
||
}
|
||
|
||
var fullList = appendQuestionSort(parsed);
|
||
fullList = appendExamQuestionChildOptionStatus(fullList, res.baseSubjectId);
|
||
|
||
var maxSort = 0;
|
||
for (final item in fullList.map(QuestionModel.new).toList()) {
|
||
final end = getQuestionSortRange(item).end;
|
||
if (end > maxSort) maxSort = end;
|
||
}
|
||
|
||
List<QuestionModel> questions;
|
||
if (isWrong) {
|
||
questions = filterWrongQuestions(fullList.map(QuestionModel.new).toList());
|
||
} else {
|
||
questions = fullList.map(QuestionModel.new).toList();
|
||
}
|
||
|
||
for (final q in questions) {
|
||
q.baseSubjectId = res.baseSubjectId;
|
||
}
|
||
|
||
return ExerciseLoadResult(
|
||
recordId: res.id,
|
||
navBarTitle: navBarTitle,
|
||
baseSubjectId: res.baseSubjectId,
|
||
questions: questions,
|
||
originalMaxSort: maxSort,
|
||
);
|
||
}
|
||
|
||
/// 【仅 debug 测试】真实接口请求完成后,把 Vue exerciseLoad.js 里的
|
||
/// JSON 试题追加到列表尾部(对标 JS 里 `res.push(...listX)`)。
|
||
/// release 包直接 no-op;测完删掉 [loadStartOvercome] 里的调用即可。
|
||
static Future<void> _injectDebugQuestions(
|
||
List<Map<String, dynamic>> items,
|
||
) async {
|
||
if (!kDebugMode) return;
|
||
try {
|
||
final raw = await rootBundle
|
||
.loadString('assets/mock/class_exercises_edit.json');
|
||
final list = jsonDecode(raw);
|
||
if (list is List) {
|
||
for (final item in list) {
|
||
if (item is Map) {
|
||
items.add(Map<String, dynamic>.from(item));
|
||
}
|
||
}
|
||
debugPrint('[ExerciseLoad] 已追加 ${list.length} 道测试 JSON 试题');
|
||
}
|
||
} catch (e) {
|
||
debugPrint('[ExerciseLoad] 测试 JSON 追加失败: $e');
|
||
}
|
||
}
|
||
}
|