flutter架 构项目基础
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:new_learn/features/exam/exam_question.dart';
|
||||
import 'package:new_learn/features/exam/question_type.dart';
|
||||
|
||||
/// ============================================================
|
||||
/// 【paperProvider】试卷题目数据源 —— Riverpod 内存主状态
|
||||
///
|
||||
/// 一、架构定位(对应方案分析结论):
|
||||
/// 题目是"会话数据"不是"资产":进卷拉一次、退出即弃,
|
||||
/// 不落 Isar(Isar 只负责跨会话的答案进度,见 answer_provider)。
|
||||
/// 100 题内存占用 ≈ 1MB,PageView.builder 懒加载按需构建,
|
||||
/// 大数组传入无性能压力。
|
||||
///
|
||||
/// 二、mock 模式(对标 Vue3 内联 mock 体验):
|
||||
/// const bool mock = true 时直接本地生成题目(Future.delayed
|
||||
/// 模拟接口延迟),改 false 后接真实接口(DioClient),
|
||||
/// 一行开关切换,热重启即生效。
|
||||
///
|
||||
/// 三、paperSizeProvider:demo 专用,控制生成题数(50/100/200),
|
||||
/// paperProvider watch 它 → 改变自动重新加载(Riverpod 响应式)。
|
||||
/// ============================================================
|
||||
|
||||
/// Demo 专用:试卷题目数量(50/100/200,入口页选择)
|
||||
class PaperSizeNotifier extends Notifier<int> {
|
||||
@override
|
||||
int build() => 100;
|
||||
|
||||
void setSize(int size) => state = size;
|
||||
}
|
||||
|
||||
final paperSizeProvider =
|
||||
NotifierProvider<PaperSizeNotifier, int>(PaperSizeNotifier.new);
|
||||
|
||||
/// 试卷题目加载器
|
||||
final paperProvider = AsyncNotifierProvider<PaperNotifier, List<ExamQuestion>>(
|
||||
PaperNotifier.new,
|
||||
);
|
||||
|
||||
class PaperNotifier extends AsyncNotifier<List<ExamQuestion>> {
|
||||
/// 接口 mock 开关:true = 本地生成;false = 接真实接口(DioClient)
|
||||
static const bool mock = true;
|
||||
|
||||
@override
|
||||
Future<List<ExamQuestion>> build() async {
|
||||
final size = ref.watch(paperSizeProvider);
|
||||
if (mock) {
|
||||
// 模拟接口延迟:首屏展示 loading,验证加载态
|
||||
await Future.delayed(const Duration(milliseconds: 600));
|
||||
return MockExamData.generate(size);
|
||||
}
|
||||
// 真实接口:GET /api/v1/Paper/{paperId}/Questions
|
||||
// final resp = await DioClient.instance.get('/api/v1/Paper/1/Questions');
|
||||
// return (resp.data['list'] as List).map(Question.fromJson).toList();
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
/// ============================================================
|
||||
/// 【MockExamData】大数据模拟生成器(100 题 × 4 题型)
|
||||
///
|
||||
/// 模拟真实试卷的题目构成:单选 / 多选 / 判断 / 解答 循环分布,
|
||||
/// 题干带少量 HTML 标签(RichTextContent 富文本渲染路径),
|
||||
/// 用于验证 PageView.builder 大数据滑动性能与题型分发。
|
||||
/// ============================================================
|
||||
class MockExamData {
|
||||
/// 学科题材池(按题号轮换,避免题目千篇一律)
|
||||
static const List<(String, String)> _stems = [
|
||||
('数学', '计算 12 × 8 = ?'),
|
||||
('语文', '下列词语书写<u>完全正确</u>的一项是?'),
|
||||
('英语', '— What does he do?<br>— He is a(n) <b>____</b>.'),
|
||||
('科学', '植物进行光合作用的主要器官是?'),
|
||||
('常识', '地球是太阳系中最大的行星。'),
|
||||
('语文', '“落霞与孤鹜齐飞”出自哪篇名作?'),
|
||||
('数学', '一个三角形最多有几个直角?'),
|
||||
('英语', '下列单词中发音与其他三项不同的一项是?'),
|
||||
];
|
||||
|
||||
static List<ExamQuestion> generate(int count) {
|
||||
return List.generate(count, (i) {
|
||||
final (subject, stem) = _stems[i % _stems.length];
|
||||
return switch (i % 4) {
|
||||
// 0 → 单选(4 个选项)
|
||||
0 => ExamQuestion(
|
||||
questionId: i + 1,
|
||||
type: QuestionType.single,
|
||||
title: '<p><b>【$subject】</b> 第 ${i + 1} 题</p><p>$stem</p>',
|
||||
options: const ['选项 A 的内容', '选项 B 的内容', '选项 C 的内容', '选项 D 的内容'],
|
||||
answer: 'A',
|
||||
analysis: '本题考察基础知识点,正确答案为 A。',
|
||||
),
|
||||
// 1 → 多选(答案两个字母)
|
||||
1 => ExamQuestion(
|
||||
questionId: i + 1,
|
||||
type: QuestionType.multi,
|
||||
title:
|
||||
'<p><b>【$subject】</b> 第 ${i + 1} 题(多选)</p><p>$stem</p>',
|
||||
options: const ['选项 A 的内容', '选项 B 的内容', '选项 C 的内容', '选项 D 的内容'],
|
||||
answer: 'A,C',
|
||||
analysis: '本题有两个正确答案:A 与 C。',
|
||||
),
|
||||
// 2 → 判断(对 / 错)
|
||||
2 => ExamQuestion(
|
||||
questionId: i + 1,
|
||||
type: QuestionType.judge,
|
||||
title:
|
||||
'<p><b>【$subject】</b> 第 ${i + 1} 题(判断)</p><p>$stem</p>',
|
||||
options: const ['对', '错'],
|
||||
answer: i % 6 == 0 ? '错' : '对',
|
||||
analysis: '依据教材定义判断,答案为 ${i % 6 == 0 ? "错" : "对"}。',
|
||||
),
|
||||
// 3 → 解答题(文本输入)
|
||||
_ => ExamQuestion(
|
||||
questionId: i + 1,
|
||||
type: QuestionType.essay,
|
||||
title:
|
||||
'<p><b>【$subject】</b> 第 ${i + 1} 题(解答)</p><p>$stem</p>',
|
||||
options: const [],
|
||||
answer: '水有三种状态:液态、固态、气态。',
|
||||
analysis: '解答题需人工批改,参考答案:水有三种状态。',
|
||||
),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user