更新
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import 'package:new_learn/core/api/conquerPackage/classExercises/model.dart';
|
||||
import 'package:new_learn/core/network/dio_client.dart';
|
||||
|
||||
/// ============================================================
|
||||
/// 【课堂习题模块接口】
|
||||
///
|
||||
/// 对标 Vue 端 api/task/index.ts、api/userCollect/index.ts:
|
||||
///
|
||||
/// GetRecordData GET /api/v1/StudyPack/GetRecord/{recordId}
|
||||
/// GetListByRecordQuestion GET /api/v1/Question/GetListByRecord/{recordId}
|
||||
/// QuestionRenewTime POST /api/v1/Question/RenewTime
|
||||
/// PushAIGrading POST /api/v1/Question/PushAIGrading
|
||||
/// RecordSubmit POST /api/v1/StudyPack/RecordSubmit
|
||||
/// GetSubmitReport GET /api/v1/StudyPack/GetReport/{packId}(60s 超时)
|
||||
/// AddUserCollect POST /api/v1/UserCollect/AddUserCollect
|
||||
/// CancleCollect POST /api/v1/UserCollect/CancleCollect
|
||||
/// Feedback POST /api/v1/Question/Feedback
|
||||
///
|
||||
/// 说明:
|
||||
/// - RenewTime / PushAIGrading / RecordSubmit 不脱壳,返回原始 data,
|
||||
/// 由提交控制器读取 code / message / aiGradingCount / id;
|
||||
/// - 异常统一抛 ApiException,交页面/控制器处理。
|
||||
/// ============================================================
|
||||
class ClassExercisesApi {
|
||||
ClassExercisesApi._();
|
||||
|
||||
static final ClassExercisesApi instance = ClassExercisesApi._();
|
||||
|
||||
/// 获取学习记录信息(edit 模式 onLoad 第一步)
|
||||
Future<ClassExercisesRecord> getRecordData(String recordId) async {
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/StudyPack/GetRecord/$recordId',
|
||||
);
|
||||
return ClassExercisesRecord.fromJson(data);
|
||||
}
|
||||
|
||||
/// 根据学习记录获取题目列表
|
||||
Future<ClassExercisesQuestionList> getListByRecordQuestion(
|
||||
String recordId,
|
||||
) async {
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/Question/GetListByRecord/$recordId',
|
||||
);
|
||||
return ClassExercisesQuestionList.fromJson(data);
|
||||
}
|
||||
|
||||
/// 提交单题作答 / 更新作答时长
|
||||
/// body: {id, childId, courseId, userAnswer, startTime, endTime,
|
||||
/// answerStatus, index?}
|
||||
/// 返回原始响应(提交失败重试队列会读 requestParams/data 兜底)
|
||||
Future<dynamic> questionRenewTime(Map<String, dynamic> body) {
|
||||
return DioClient.instance.post('/api/v1/Question/RenewTime', data: body);
|
||||
}
|
||||
|
||||
/// 提交 AI 图片批改
|
||||
/// body: {id, childId, courseId, startTime, endTime,
|
||||
/// answerImgs:[{url,thumbnailUrl}]}
|
||||
Future<dynamic> pushAIGrading(Map<String, dynamic> body) {
|
||||
return DioClient.instance.post(
|
||||
'/api/v1/Question/PushAIGrading',
|
||||
data: body,
|
||||
);
|
||||
}
|
||||
|
||||
/// 交卷
|
||||
/// body: {recordId};返回 {code,message,aiGradingCount}
|
||||
Future<dynamic> recordSubmit(String recordId) {
|
||||
return DioClient.instance.post(
|
||||
'/api/v1/StudyPack/RecordSubmit',
|
||||
data: {'recordId': recordId},
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取攻克报告(view 模式数据源,题目批改可能耗时,超时 60s)
|
||||
Future<ClassExercisesReport> getSubmitReport(String packId) async {
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/StudyPack/GetReport/$packId',
|
||||
receiveTimeout: const Duration(seconds: 60),
|
||||
);
|
||||
return ClassExercisesReport.fromJson(data);
|
||||
}
|
||||
|
||||
/// 添加收藏 / 错题本
|
||||
/// body: {type, packId, questionId, recordQuestionId}
|
||||
/// 返回原始响应(成功时 res.id 为收藏记录 id)
|
||||
Future<dynamic> addUserCollect(Map<String, dynamic> body) {
|
||||
return DioClient.instance.post(
|
||||
'/api/v1/UserCollect/AddUserCollect',
|
||||
data: body,
|
||||
);
|
||||
}
|
||||
|
||||
/// 取消收藏 / 移出错题本
|
||||
/// body: {type, id}
|
||||
Future<dynamic> cancleCollect(Map<String, dynamic> body) {
|
||||
return DioClient.instance.post(
|
||||
'/api/v1/UserCollect/CancleCollect',
|
||||
data: body,
|
||||
);
|
||||
}
|
||||
|
||||
/// 题目反馈
|
||||
/// body: {id, questionId, feedbackTypes, description, images}
|
||||
Future<dynamic> feedback(Map<String, dynamic> body) {
|
||||
return DioClient.instance.post('/api/v1/Question/Feedback', data: body);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/// ============================================================
|
||||
/// 【课堂习题模块模型】接口响应壳解析
|
||||
///
|
||||
/// 对标 Vue 端:
|
||||
/// api/task/index.ts → GetRecordData / GetListByRecordQuestion
|
||||
/// / GetSubmitReport / RecordSubmit
|
||||
/// api/question/index.ts → RenewTime / PushAIGrading / Feedback
|
||||
///
|
||||
/// 说明:
|
||||
/// 题目字段非常多且解析器(questionParser)会动态增删字段,
|
||||
/// 题目列表统一以 `Map<String, dynamic>` 承载,业务侧再包 QuestionModel,
|
||||
/// 全量保留后端原字段名,不做字段裁剪。
|
||||
/// ============================================================
|
||||
library;
|
||||
|
||||
/// 从响应中取业务 payload(兼容 {code,message,data:{...}} 脱壳)
|
||||
Map<String, dynamic> unwrapData(dynamic resp) {
|
||||
if (resp is Map<String, dynamic>) {
|
||||
final data = resp['data'];
|
||||
if (data is Map<String, dynamic>) return data;
|
||||
return resp;
|
||||
}
|
||||
return <String, dynamic>{};
|
||||
}
|
||||
|
||||
/// GET StudyPack/GetRecord/{recordId} 响应
|
||||
class ClassExercisesRecord {
|
||||
const ClassExercisesRecord({
|
||||
this.recordId = '',
|
||||
this.name = '',
|
||||
this.baseSubjectId,
|
||||
this.raw = const {},
|
||||
});
|
||||
|
||||
/// 学习记录 id
|
||||
final String recordId;
|
||||
|
||||
/// 攻克包名称(用于 NavBar 标题:`${name}专项智能攻克`)
|
||||
final String name;
|
||||
|
||||
/// 学科 id(决定 iSFilllankItemUpload:0 输入框 / 1 图片作答)
|
||||
final int? baseSubjectId;
|
||||
|
||||
final Map<String, dynamic> raw;
|
||||
|
||||
factory ClassExercisesRecord.fromJson(dynamic json) {
|
||||
final data = unwrapData(json);
|
||||
return ClassExercisesRecord(
|
||||
recordId:
|
||||
data['recordId']?.toString() ?? data['id']?.toString() ?? '',
|
||||
name: data['name']?.toString() ?? '',
|
||||
baseSubjectId:
|
||||
int.tryParse('${data['baseSubjectId'] ?? ''}'),
|
||||
raw: data,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// GET Question/GetListByRecord/{recordId} 响应
|
||||
class ClassExercisesQuestionList {
|
||||
const ClassExercisesQuestionList({
|
||||
this.items = const [],
|
||||
this.raw = const {},
|
||||
});
|
||||
|
||||
/// 原始题目列表(字段全量保留,交给 parseQuestionData 处理)
|
||||
final List<Map<String, dynamic>> items;
|
||||
|
||||
final Map<String, dynamic> raw;
|
||||
|
||||
factory ClassExercisesQuestionList.fromJson(dynamic json) {
|
||||
final data = unwrapData(json);
|
||||
final rawList = data['questions'] ?? data['list'] ?? data['data'];
|
||||
final list = <Map<String, dynamic>>[];
|
||||
if (rawList is List) {
|
||||
for (final item in rawList) {
|
||||
if (item is Map) {
|
||||
list.add(Map<String, dynamic>.from(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ClassExercisesQuestionList(items: list, raw: data);
|
||||
}
|
||||
}
|
||||
|
||||
/// GET StudyPack/GetReport/{packId} 响应(view 模式数据源)
|
||||
class ClassExercisesReport {
|
||||
const ClassExercisesReport({
|
||||
this.id = '',
|
||||
this.name = '',
|
||||
this.baseSubjectId,
|
||||
this.questions = const [],
|
||||
this.raw = const {},
|
||||
});
|
||||
|
||||
/// 报告/记录 id(view 模式下作为 recordId 使用)
|
||||
final String id;
|
||||
|
||||
final String name;
|
||||
|
||||
final int? baseSubjectId;
|
||||
|
||||
/// 报告内题目列表(字段全量保留)
|
||||
final List<Map<String, dynamic>> questions;
|
||||
|
||||
final Map<String, dynamic> raw;
|
||||
|
||||
factory ClassExercisesReport.fromJson(dynamic json) {
|
||||
final data = unwrapData(json);
|
||||
final rawList = data['questions'];
|
||||
final list = <Map<String, dynamic>>[];
|
||||
if (rawList is List) {
|
||||
for (final item in rawList) {
|
||||
if (item is Map) {
|
||||
list.add(Map<String, dynamic>.from(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ClassExercisesReport(
|
||||
id: data['id']?.toString() ?? data['recordId']?.toString() ?? '',
|
||||
name: data['name']?.toString() ?? '',
|
||||
baseSubjectId: int.tryParse('${data['baseSubjectId'] ?? ''}'),
|
||||
questions: list,
|
||||
raw: data,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user