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 { @override int build() => 100; void setSize(int size) => state = size; } final paperSizeProvider = NotifierProvider(PaperSizeNotifier.new); /// 试卷题目加载器 final paperProvider = AsyncNotifierProvider>( PaperNotifier.new, ); class PaperNotifier extends AsyncNotifier> { /// 接口 mock 开关:true = 本地生成;false = 接真实接口(DioClient) static const bool mock = true; @override Future> 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 = ?'), ('语文', '下列词语书写完全正确的一项是?'), ('英语', '— What does he do?
— He is a(n) ____.'), ('科学', '植物进行光合作用的主要器官是?'), ('常识', '地球是太阳系中最大的行星。'), ('语文', '“落霞与孤鹜齐飞”出自哪篇名作?'), ('数学', '一个三角形最多有几个直角?'), ('英语', '下列单词中发音与其他三项不同的一项是?'), ]; static List 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: '

【$subject】 第 ${i + 1} 题

$stem

', options: const ['选项 A 的内容', '选项 B 的内容', '选项 C 的内容', '选项 D 的内容'], answer: 'A', analysis: '本题考察基础知识点,正确答案为 A。', ), // 1 → 多选(答案两个字母) 1 => ExamQuestion( questionId: i + 1, type: QuestionType.multi, title: '

【$subject】 第 ${i + 1} 题(多选)

$stem

', options: const ['选项 A 的内容', '选项 B 的内容', '选项 C 的内容', '选项 D 的内容'], answer: 'A,C', analysis: '本题有两个正确答案:A 与 C。', ), // 2 → 判断(对 / 错) 2 => ExamQuestion( questionId: i + 1, type: QuestionType.judge, title: '

【$subject】 第 ${i + 1} 题(判断)

$stem

', options: const ['对', '错'], answer: i % 6 == 0 ? '错' : '对', analysis: '依据教材定义判断,答案为 ${i % 6 == 0 ? "错" : "对"}。', ), // 3 → 解答题(文本输入) _ => ExamQuestion( questionId: i + 1, type: QuestionType.essay, title: '

【$subject】 第 ${i + 1} 题(解答)

$stem

', options: const [], answer: '水有三种状态:液态、固态、气态。', analysis: '解答题需人工批改,参考答案:水有三种状态。', ), }; }); } }