Commit 66a7e3e72c3c4e51c9848544ff0cc8b9202b828e

Authored by 吴启风
1 parent 22f36232

feat:退出课堂和结束课堂优化

lib/common/request/dao/listen_dao.dart
@@ -15,43 +15,66 @@ class ListenDao { @@ -15,43 +15,66 @@ class ListenDao {
15 15
16 ///视频跟读 16 ///视频跟读
17 static Future<List<FollowReadEntity?>?> followRead() async { 17 static Future<List<FollowReadEntity?>?> followRead() async {
18 - var data = await requestClient.get<List<FollowReadEntity?>>(Apis.followRead); 18 + var data =
  19 + await requestClient.get<List<FollowReadEntity?>>(Apis.followRead);
19 return data; 20 return data;
20 } 21 }
21 22
22 ///课程内容 23 ///课程内容
23 static Future<CourseProcessEntity?> process(courseLessonId) async { 24 static Future<CourseProcessEntity?> process(courseLessonId) async {
24 - var data = await requestClient.get<CourseProcessEntity>(Apis.process,queryParameters: {'courseLessonId':courseLessonId}); 25 + var data = await requestClient.get<CourseProcessEntity>(Apis.process,
  26 + queryParameters: {'courseLessonId': courseLessonId});
25 return data; 27 return data;
26 } 28 }
27 29
28 ///获取视频跟读内容 30 ///获取视频跟读内容
29 - static Future<List<ReadContentEntity?>?> readContent(videoFollowReadId) async {  
30 - var data = await requestClient.get<List<ReadContentEntity?>>(Apis.readContent,queryParameters: {'videoFollowReadId':videoFollowReadId}); 31 + static Future<List<ReadContentEntity?>?> readContent(
  32 + videoFollowReadId) async {
  33 + var data = await requestClient.get<List<ReadContentEntity?>>(
  34 + Apis.readContent,
  35 + queryParameters: {'videoFollowReadId': videoFollowReadId});
31 return data; 36 return data;
32 } 37 }
33 38
34 ///视频跟读提交结果 39 ///视频跟读提交结果
35 - static Future followResult(frequency,videoFollowReadId) async {  
36 - var data = await requestClient.post(Apis.followResult,data: {'frequency':frequency,'videoFollowReadContentId':videoFollowReadId}); 40 + static Future followResult(frequency, videoFollowReadId) async {
  41 + var data = await requestClient.post(Apis.followResult, data: {
  42 + 'frequency': frequency,
  43 + 'videoFollowReadContentId': videoFollowReadId
  44 + });
37 return data; 45 return data;
38 } 46 }
39 47
40 ///进入课堂 48 ///进入课堂
41 static Future enterClass(courseLessonId) async { 49 static Future enterClass(courseLessonId) async {
42 - var data = await requestClient.post(Apis.enterClass,data: {'courseLessonId':courseLessonId}); 50 + var data = await requestClient
  51 + .post(Apis.enterClass, data: {'courseLessonId': courseLessonId});
43 return data; 52 return data;
44 } 53 }
45 54
46 ///退出课堂 55 ///退出课堂
47 - static Future exitClass(courseLessonId,currentStep,{int? currentTime}) async {  
48 - var data = await requestClient.post(Apis.exitClass,data: {'courseLessonId':courseLessonId,'currentStep':currentStep,'currentTime':currentTime ?? getTimestampOfSecond()}); 56 + static Future exitClass(courseLessonId,
  57 + {int? currentStep, int? currentTime}) async {
  58 + var data = await requestClient.post(Apis.exitClass, data: {
  59 + 'courseLessonId': courseLessonId,
  60 +
  61 + ///如果currentStep不为空,才传currentStep参数
  62 + if (currentStep != null) 'currentStep': currentStep,
  63 +
  64 + ///如果currentTime不为空,才传currentTime参数
  65 + if (currentTime != null) 'currentTime': currentTime
  66 + });
49 return data; 67 return data;
50 } 68 }
51 69
52 ///完成课堂 70 ///完成课堂
53 - static Future endClass(courseLessonId,currentStep,{int? currentTime}) async {  
54 - var data = await requestClient.post(Apis.endClass,data: {'courseLessonId':courseLessonId,'currentStep':currentStep,'currentTime':currentTime ?? getTimestampOfSecond()}); 71 + static Future endClass(courseLessonId,
  72 + {int? currentStep, int? currentTime}) async {
  73 + var data = await requestClient.post(Apis.endClass, data: {
  74 + 'courseLessonId': courseLessonId,
  75 + if (currentStep != null) 'currentStep': currentStep,
  76 + if (currentTime != null) 'currentTime': currentTime
  77 + });
55 return data; 78 return data;
56 } 79 }
57 } 80 }
lib/pages/practice/bloc/topic_picture_bloc.dart
@@ -326,9 +326,9 @@ class TopicPictureBloc extends BaseSectionBloc&lt;TopicPictureEvent, TopicPictureSt @@ -326,9 +326,9 @@ class TopicPictureBloc extends BaseSectionBloc&lt;TopicPictureEvent, TopicPictureSt
326 sectionComplete(() { 326 sectionComplete(() {
327 popPage( 327 popPage(
328 data:{ 328 data:{
329 - 'currentStep':currentPage.toString(), 329 + 'currentStep':currentPage,
330 'courseLessonId':courseLessonId, 330 'courseLessonId':courseLessonId,
331 - 'isLastPage': true, 331 + 'isCompleted': true,
332 'nextSection': true 332 'nextSection': true
333 }); 333 });
334 }, againSectionTap: () { 334 }, againSectionTap: () {
lib/pages/practice/topic_picture_page.dart
@@ -71,9 +71,9 @@ class _TopicPicturePage extends StatelessWidget { @@ -71,9 +71,9 @@ class _TopicPicturePage extends StatelessWidget {
71 onTap: () { 71 onTap: () {
72 popPage( 72 popPage(
73 data:{ 73 data:{
74 - 'currentStep':bloc.currentPage.toString(), 74 + 'currentStep':bloc.currentPage,
75 'courseLessonId':bloc.courseLessonId, 75 'courseLessonId':bloc.courseLessonId,
76 - 'isLastPage': bloc.isLastPage(), 76 + 'isCompleted': bloc.isLastPage(),
77 }); 77 });
78 // Navigator.pop(context); 78 // Navigator.pop(context);
79 }, 79 },
lib/pages/repeataftercontent/widgets/repeat_video_widget.dart
@@ -140,13 +140,14 @@ class _RepeatVideoWidgetState extends State&lt;RepeatVideoWidget&gt; { @@ -140,13 +140,14 @@ class _RepeatVideoWidgetState extends State&lt;RepeatVideoWidget&gt; {
140 : 140 :
141 Container( 141 Container(
142 color: Colors.white, 142 color: Colors.white,
143 - child: Text(  
144 - '视频加载中....',  
145 - style: TextStyle(  
146 - fontSize: 20.sp,  
147 - color: Colors.black  
148 - ),  
149 - ), 143 + child: const CircularProgressIndicator(),
  144 + // Text(
  145 + // '视频加载中....',
  146 + // style: TextStyle(
  147 + // fontSize: 20.sp,
  148 + // color: Colors.black
  149 + // ),
  150 + // ),
150 ), 151 ),
151 ); 152 );
152 } 153 }
lib/pages/section/bloc/section_bloc.dart
@@ -34,34 +34,31 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; { @@ -34,34 +34,31 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; {
34 34
35 CourseUnitEntity get courseUnitEntity => _courseUnitEntity; 35 CourseUnitEntity get courseUnitEntity => _courseUnitEntity;
36 36
37 - CourseUnitDetail _courseUnitDetail; 37 + ///courseUnitId与课程环节列表的映射
  38 + final Map<int, List<CourseSectionEntity>?> _courseSectionDatasMap = {};
38 39
39 - CourseUnitDetail get courseUnitDetail => _courseUnitDetail;  
40 -  
41 - List<CourseSectionEntity>? _courseSectionDatas;  
42 -  
43 - List<CourseSectionEntity>? get courseSectionDatas => _courseSectionDatas; 40 + Map<int, List<CourseSectionEntity>?> get courseSectionDatasMap => _courseSectionDatasMap;
44 41
45 CourseProcessEntity? _processEntity; 42 CourseProcessEntity? _processEntity;
46 43
47 CourseProcessEntity? get processEntity => _processEntity; 44 CourseProcessEntity? get processEntity => _processEntity;
48 45
49 - SectionBloc(this._courseUnitEntity, this._courseUnitDetail, 46 + SectionBloc(this._courseUnitEntity, this._currentPage,
50 this._pageController, this._listController) 47 this._pageController, this._listController)
51 : super(LessonInitial()) { 48 : super(LessonInitial()) {
52 - on<RequestDataEvent>(_requestData); 49 + on<RequestDataEvent>(_requestSectionsData);
53 on<RequestEndClassEvent>(_requestEndClass); 50 on<RequestEndClassEvent>(_requestEndClass);
54 on<RequestEnterClassEvent>(_requestEnterClass); 51 on<RequestEnterClassEvent>(_requestEnterClass);
55 on<RequestVideoLessonEvent>(_requestVideoLesson); 52 on<RequestVideoLessonEvent>(_requestVideoLesson);
56 on<CurrentUnitIndexChangeEvent>(_pageControllerChange); 53 on<CurrentUnitIndexChangeEvent>(_pageControllerChange);
57 } 54 }
58 55
59 - void _requestData( 56 + void _requestSectionsData(
60 RequestDataEvent event, Emitter<SectionState> emitter) async { 57 RequestDataEvent event, Emitter<SectionState> emitter) async {
61 try { 58 try {
62 await loading(() async { 59 await loading(() async {
63 - _courseSectionDatas =  
64 - await LessonDao.courseSection(courseUnitId: _courseUnitDetail.id!); 60 + _courseSectionDatasMap[event.courseUnitId] =
  61 + await LessonDao.courseSection(courseUnitId: event.courseUnitId);
65 emitter(LessonDataLoadState()); 62 emitter(LessonDataLoadState());
66 }); 63 });
67 } catch (e) { 64 } catch (e) {
@@ -102,18 +99,18 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; { @@ -102,18 +99,18 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; {
102 99
103 void _requestEndClass( 100 void _requestEndClass(
104 RequestEndClassEvent event, Emitter<SectionState> emitter) async { 101 RequestEndClassEvent event, Emitter<SectionState> emitter) async {
105 - if (event.isLastPage) {  
106 - await await ListenDao.endClass(event.courseLessonId, event.currentStep, 102 + if (event.isCompleted) {
  103 + await await ListenDao.endClass(event.courseLessonId,
  104 + currentStep: event.currentStep,
107 currentTime: event.currentTime); 105 currentTime: event.currentTime);
108 } else { 106 } else {
109 - await await ListenDao.exitClass(event.courseLessonId, event.currentStep, 107 + await await ListenDao.exitClass(event.courseLessonId,
  108 + currentStep: event.currentStep,
110 currentTime: event.currentTime); 109 currentTime: event.currentTime);
111 } 110 }
112 - debugPrint("WQF _requestEndClass autoNextSection=${event.autoNextSection}");  
113 if (event.autoNextSection) { 111 if (event.autoNextSection) {
114 final nextCourseSection = 112 final nextCourseSection =
115 - getNextCourseSectionBySort(int.parse(event.courseLessonId));  
116 - debugPrint("WQF nextCourseSection = $nextCourseSection"); 113 + getNextCourseSection(int.parse(event.courseLessonId));
117 ///进入课堂 114 ///进入课堂
118 add(RequestEnterClassEvent(nextCourseSection!.id.toString(), 115 add(RequestEnterClassEvent(nextCourseSection!.id.toString(),
119 nextCourseSection.courseType)); 116 nextCourseSection.courseType));
@@ -126,30 +123,72 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; { @@ -126,30 +123,72 @@ class SectionBloc extends Bloc&lt;SectionEvent, SectionState&gt; {
126 emitter(CurrentPageIndexState()); 123 emitter(CurrentPageIndexState());
127 } 124 }
128 125
129 - // 未锁定的页 126 + // 未锁定的页(单元)
130 int unlockPageCount() { 127 int unlockPageCount() {
131 return _courseUnitEntity.courseUnitVOList 128 return _courseUnitEntity.courseUnitVOList
132 ?.indexWhereOrNull((element) => element.lock == true) ?? 129 ?.indexWhereOrNull((element) => element.lock == true) ??
133 1; 130 1;
134 } 131 }
135 132
136 - CourseSectionEntity? getNextCourseSectionBySort(int courseLessonId) {  
137 - final curCourseSectionEntity = _courseSectionDatas  
138 - ?.firstWhere((element) => element.id == courseLessonId);  
139 - final curSort = curCourseSectionEntity?.sortOrder ?? 0;  
140 - CourseSectionEntity? nextCourseSectionEntity = _courseSectionDatas  
141 - ?.firstWhere((element) => element.sortOrder == curSort + 1); 133 + CourseUnitDetail getCourseUnitDetail({int? pageIndex}) {
  134 + return _courseUnitEntity.courseUnitVOList![pageIndex ?? _currentPage];
  135 + }
  136 +
  137 + ///根据courseLessonId查找对应的courseSection
  138 + CourseSectionEntity? findCourseSectionById(int courseLessonId) {
  139 + for (var entry in courseSectionDatasMap.entries) {
  140 + var sectionList = entry.value;
  141 + if (sectionList != null) {
  142 + for (var section in sectionList) {
  143 + if (section.id == courseLessonId) {
  144 + return section;
  145 + }
  146 + }
  147 + }
  148 + }
  149 + return null;
  150 + }
  151 +
  152 + ///根据sortOrder查找对应的courseSection
  153 + CourseSectionEntity? findCourseSectionBySort(int sortOrder) {
  154 + for (var entry in courseSectionDatasMap.entries) {
  155 + var sectionList = entry.value;
  156 + if (sectionList != null) {
  157 + for (var section in sectionList) {
  158 + if (section.sortOrder == sortOrder) {
  159 + return section;
  160 + }
  161 + }
  162 + }
  163 + }
  164 + return null;
  165 + }
  166 +
  167 + ///根据courseLessonId查找对应的CourseUnitDetail
  168 + CourseUnitDetail? findCourseUnitDetailById(int courseLessonId) {
  169 + final curCourseSectionEntity = findCourseSectionById(courseLessonId);
  170 + if (curCourseSectionEntity != null) {
  171 + final curCourseUnitDetail = _courseUnitEntity.courseUnitVOList?.firstWhere((element) =>
  172 + element.id == curCourseSectionEntity.courseUnitId);
  173 + return curCourseUnitDetail;
  174 + }
  175 + return null;
  176 + }
  177 +
  178 + CourseSectionEntity? getNextCourseSection(int courseLessonId) {
  179 + final curCourseSectionEntity = findCourseSectionById(courseLessonId);
  180 + final curSectionSort = curCourseSectionEntity?.sortOrder ?? 0;
  181 + final nextCourseSectionEntity = findCourseSectionBySort(curSectionSort + 1);
142 if (nextCourseSectionEntity != null) { 182 if (nextCourseSectionEntity != null) {
143 return nextCourseSectionEntity; 183 return nextCourseSectionEntity;
144 } else { 184 } else {
145 ///跨unit选lesson 185 ///跨unit选lesson
146 - final curCourseUnitDetail = _courseUnitEntity.courseUnitVOList  
147 - ?.firstWhere(  
148 - (element) => element.id == curCourseSectionEntity?.courseUnitId); 186 + final curCourseUnitDetail = findCourseUnitDetailById(courseLessonId);
149 if (curCourseUnitDetail != null) { 187 if (curCourseUnitDetail != null) {
150 final nextCourseUnitDetail = _courseUnitEntity.courseUnitVOList 188 final nextCourseUnitDetail = _courseUnitEntity.courseUnitVOList
151 - ?.firstWhere((element) => element.sortOrder == 0); 189 + ?.firstWhere((element) => element.sortOrder == (curCourseUnitDetail.sortOrder! + 1));
152 if (nextCourseUnitDetail != null) { 190 if (nextCourseUnitDetail != null) {
  191 + add(RequestDataEvent(nextCourseUnitDetail.id!));
153 ///pageView翻页了,可能需要预加载 todo 192 ///pageView翻页了,可能需要预加载 todo
154 return null; 193 return null;
155 } else { 194 } else {
lib/pages/section/bloc/section_event.dart
@@ -3,7 +3,11 @@ part of &#39;section_bloc.dart&#39;; @@ -3,7 +3,11 @@ part of &#39;section_bloc.dart&#39;;
3 @immutable 3 @immutable
4 abstract class SectionEvent {} 4 abstract class SectionEvent {}
5 5
6 -class RequestDataEvent extends SectionEvent {} 6 +class RequestDataEvent extends SectionEvent {
  7 + final int courseUnitId;
  8 +
  9 + RequestDataEvent(this.courseUnitId);
  10 +}
7 11
8 ///获取视频课程内容 12 ///获取视频课程内容
9 class RequestVideoLessonEvent extends SectionEvent { 13 class RequestVideoLessonEvent extends SectionEvent {
@@ -24,17 +28,23 @@ class RequestEnterClassEvent extends SectionEvent { @@ -24,17 +28,23 @@ class RequestEnterClassEvent extends SectionEvent {
24 ///结束课堂 28 ///结束课堂
25 class RequestEndClassEvent extends SectionEvent { 29 class RequestEndClassEvent extends SectionEvent {
26 final String courseLessonId; 30 final String courseLessonId;
27 - final String currentStep;  
28 31
29 - ///是否是最后一页(决定调结束接口还是退出接口)  
30 - final bool isLastPage; 32 + ///当前进展(进度类,比如练习、绘本)
  33 + final int? currentStep;
  34 +
  35 + ///当前时间(进度类,比如音视频)
31 final int? currentTime; 36 final int? currentTime;
32 37
  38 + ///课程环节是否完成(决定调结束接口还是退出接口)
  39 + final bool isCompleted;
  40 +
33 ///自动进入下一环节 41 ///自动进入下一环节
34 final bool autoNextSection; 42 final bool autoNextSection;
35 43
36 - RequestEndClassEvent(this.courseLessonId, this.currentStep, this.isLastPage,  
37 - {this.currentTime, this.autoNextSection = false}); 44 + RequestEndClassEvent(this.courseLessonId, isCompleted,
  45 + {this.currentStep, this.currentTime, autoNextSection})
  46 + : isCompleted = isCompleted ?? false,
  47 + autoNextSection = autoNextSection ?? false;
38 } 48 }
39 49
40 ///页面切换 50 ///页面切换
lib/pages/section/section_page.dart
@@ -20,21 +20,21 @@ import &#39;courese_module_model.dart&#39;; @@ -20,21 +20,21 @@ import &#39;courese_module_model.dart&#39;;
20 /// 环节列表页 20 /// 环节列表页
21 class SectionPage extends StatelessWidget { 21 class SectionPage extends StatelessWidget {
22 const SectionPage( 22 const SectionPage(
23 - {super.key,  
24 - required this.courseUnitEntity,  
25 - required this.courseUnitDetail}); 23 + {super.key, required this.courseUnitEntity, required this.courseUnitId});
26 24
27 final CourseUnitEntity courseUnitEntity; 25 final CourseUnitEntity courseUnitEntity;
28 26
29 /// unitId 27 /// unitId
30 - final CourseUnitDetail courseUnitDetail; 28 + final int courseUnitId;
31 29
32 @override 30 @override
33 Widget build(BuildContext context) { 31 Widget build(BuildContext context) {
  32 + int initialPage = courseUnitEntity.courseUnitVOList
  33 + ?.indexWhere((element) => element.id == courseUnitId) ??
  34 + 0;
34 return BlocProvider( 35 return BlocProvider(
35 - create: (context) => SectionBloc(courseUnitEntity, courseUnitDetail,  
36 - PageController(), ScrollController())  
37 - ..add(RequestDataEvent()), 36 + create: (context) => SectionBloc(courseUnitEntity, initialPage,
  37 + PageController(initialPage: initialPage), ScrollController()),
38 child: _SectionPageView(context), 38 child: _SectionPageView(context),
39 ); 39 );
40 } 40 }
@@ -76,16 +76,18 @@ class _SectionPageView extends StatelessWidget { @@ -76,16 +76,18 @@ class _SectionPageView extends StatelessWidget {
76 }).then((value) { 76 }).then((value) {
77 if (value != null) { 77 if (value != null) {
78 Map<String, dynamic> dataMap = value as Map<String, dynamic>; 78 Map<String, dynamic> dataMap = value as Map<String, dynamic>;
79 - bloc.add(RequestEndClassEvent(dataMap['courseLessonId']!,  
80 - dataMap['currentTime']!, true, autoNextSection: dataMap['nextSection'] as bool)); 79 + bloc.add(RequestEndClassEvent(
  80 + dataMap['courseLessonId']!, dataMap['isCompleted'],
  81 + currentTime: dataMap['currentTime'],
  82 + autoNextSection: dataMap['nextSection']));
81 } 83 }
82 }); 84 });
83 return; 85 return;
84 } 86 }
85 87
86 if (state is RequestEnterClassState) { 88 if (state is RequestEnterClassState) {
87 - if (state.courseType != SectionType.practice.value  
88 - && state.courseType != SectionType.pictureBook.value) { 89 + if (state.courseType != SectionType.practice.value &&
  90 + state.courseType != SectionType.pictureBook.value) {
89 ///视频类型 91 ///视频类型
90 ///获取视频课程内容 92 ///获取视频课程内容
91 bloc.add(RequestVideoLessonEvent( 93 bloc.add(RequestVideoLessonEvent(
@@ -101,8 +103,11 @@ class _SectionPageView extends StatelessWidget { @@ -101,8 +103,11 @@ class _SectionPageView extends StatelessWidget {
101 if (value != null) { 103 if (value != null) {
102 Map<String, dynamic> dataMap = value as Map<String, dynamic>; 104 Map<String, dynamic> dataMap = value as Map<String, dynamic>;
103 bloc.add(RequestEndClassEvent( 105 bloc.add(RequestEndClassEvent(
104 - dataMap['courseLessonId']!, dataMap['currentStep']!,  
105 - dataMap['isLastPage']! as bool, autoNextSection: dataMap['nextSection'] as bool)); 106 + dataMap['courseLessonId']!,
  107 + dataMap['isCompleted'],
  108 + currentStep: dataMap['currentStep'],
  109 + autoNextSection: dataMap['nextSection'],
  110 + ));
106 } 111 }
107 }); 112 });
108 return; 113 return;
@@ -116,8 +121,9 @@ class _SectionPageView extends StatelessWidget { @@ -116,8 +121,9 @@ class _SectionPageView extends StatelessWidget {
116 if (value != null) { 121 if (value != null) {
117 Map<String, dynamic> dataMap = value as Map<String, dynamic>; 122 Map<String, dynamic> dataMap = value as Map<String, dynamic>;
118 bloc.add(RequestEndClassEvent( 123 bloc.add(RequestEndClassEvent(
119 - dataMap['courseLessonId']!, dataMap['currentStep']!,  
120 - dataMap['isLastPage']! as bool, autoNextSection: dataMap['nextSection'] as bool)); 124 + dataMap['courseLessonId']!, dataMap['isCompleted'],
  125 + currentStep: dataMap['currentStep'],
  126 + autoNextSection: dataMap['nextSection']));
121 } 127 }
122 }); 128 });
123 return; 129 return;
@@ -139,7 +145,7 @@ class _SectionPageView extends StatelessWidget { @@ -139,7 +145,7 @@ class _SectionPageView extends StatelessWidget {
139 mainAxisAlignment: MainAxisAlignment.spaceBetween, 145 mainAxisAlignment: MainAxisAlignment.spaceBetween,
140 children: [ 146 children: [
141 SectionHeaderWidget( 147 SectionHeaderWidget(
142 - title: bloc.courseUnitDetail.name, 148 + title: bloc.getCourseUnitDetail().name,
143 courseModuleCode: bloc.courseUnitEntity.courseModuleCode), 149 courseModuleCode: bloc.courseUnitEntity.courseModuleCode),
144 Expanded( 150 Expanded(
145 child: Padding( 151 child: Padding(
@@ -156,7 +162,10 @@ class _SectionPageView extends StatelessWidget { @@ -156,7 +162,10 @@ class _SectionPageView extends StatelessWidget {
156 ///去掉 Android 上默认的边缘拖拽效果 162 ///去掉 Android 上默认的边缘拖拽效果
157 behavior: ScrollConfiguration.of(context) 163 behavior: ScrollConfiguration.of(context)
158 .copyWith(overscroll: false), 164 .copyWith(overscroll: false),
159 - child: _itemTransCard(index, context), 165 + child: _itemTransCard(
  166 + bloc.getCourseUnitDetail(pageIndex: index),
  167 + index,
  168 + context),
160 ); 169 );
161 }), 170 }),
162 ), // 设置外部padding, 171 ), // 设置外部padding,
@@ -209,55 +218,80 @@ class _SectionPageView extends StatelessWidget { @@ -209,55 +218,80 @@ class _SectionPageView extends StatelessWidget {
209 }); 218 });
210 } 219 }
211 220
212 -Widget _itemTransCard(int index, BuildContext context) { 221 +Widget _itemTransCard(
  222 + CourseUnitDetail courseUnitDetail, int pageIndex, BuildContext context) {
213 final bloc = BlocProvider.of<SectionBloc>(context); 223 final bloc = BlocProvider.of<SectionBloc>(context);
214 - return NestedListView.builder(  
215 - itemCount: bloc.courseSectionDatas?.length ?? 0,  
216 - scrollDirection: Axis.horizontal,  
217 - itemBuilder: (BuildContext context, int index) {  
218 - CourseSectionEntity sectionData = bloc.courseSectionDatas![index];  
219 - if (sectionData.courseType == SectionType.bouns.value) {  
220 - //彩蛋  
221 - return GestureDetector(  
222 - onTap: () {  
223 - if (!UserUtil.isLogined()) {  
224 - pushNamed(AppRouteName.login);  
225 - return;  
226 - }  
227 - if (sectionData.lock == true) {  
228 - showToast('当前课程暂未解锁');  
229 - return;  
230 - } 224 + List<CourseSectionEntity>? courseSectionEntities =
  225 + bloc.courseSectionDatasMap[courseUnitDetail.id];
  226 + if (courseSectionEntities == null) {
  227 + bloc.add(RequestDataEvent(courseUnitDetail.id!));
  228 + return Center(
  229 + child: Column(
  230 + mainAxisAlignment: MainAxisAlignment.center,
  231 + children: [
  232 + const Text(
  233 + '暂无数据',
  234 + style: TextStyle(fontSize: 24.0),
  235 + ),
  236 + const SizedBox(height: 16.0),
  237 + // 间距
  238 + CircularProgressIndicator(
  239 + color: CourseModuleModel(
  240 + bloc.courseUnitEntity.courseModuleCode ?? 'Phase-1')
  241 + .color),
  242 + // 加载动画
  243 + ],
  244 + ),
  245 + );
  246 + } else {
  247 + return NestedListView.builder(
  248 + itemCount: bloc.courseSectionDatasMap[courseUnitDetail.id]?.length ?? 0,
  249 + scrollDirection: Axis.horizontal,
  250 + itemBuilder: (BuildContext context, int index) {
  251 + CourseSectionEntity sectionData = courseSectionEntities[index];
  252 + if (sectionData.courseType == SectionType.bouns.value) {
  253 + //彩蛋
  254 + return GestureDetector(
  255 + onTap: () {
  256 + if (!UserUtil.isLogined()) {
  257 + pushNamed(AppRouteName.login);
  258 + return;
  259 + }
  260 + if (sectionData.lock == true) {
  261 + showToast('当前课程暂未解锁');
  262 + return;
  263 + }
231 264
232 - ///进入课堂  
233 - bloc.add(RequestEnterClassEvent(  
234 - sectionData.id.toString(), sectionData.courseType));  
235 - },  
236 - child: SectionBoundsItem(  
237 - imageUrl: sectionData.coverUrl,  
238 - ),  
239 - );  
240 - } else {  
241 - return GestureDetector(  
242 - onTap: () {  
243 - if (!UserUtil.isLogined()) {  
244 - pushNamed(AppRouteName.login);  
245 - return;  
246 - }  
247 - if (sectionData.lock == true) {  
248 - showToast('当前课程暂未解锁');  
249 - return;  
250 - } 265 + ///进入课堂
  266 + bloc.add(RequestEnterClassEvent(
  267 + sectionData.id.toString(), sectionData.courseType));
  268 + },
  269 + child: SectionBoundsItem(
  270 + imageUrl: sectionData.coverUrl,
  271 + ),
  272 + );
  273 + } else {
  274 + return GestureDetector(
  275 + onTap: () {
  276 + if (!UserUtil.isLogined()) {
  277 + pushNamed(AppRouteName.login);
  278 + return;
  279 + }
  280 + if (sectionData.lock == true) {
  281 + showToast('当前课程暂未解锁');
  282 + return;
  283 + }
251 284
252 - ///进入课堂  
253 - bloc.add(RequestEnterClassEvent(  
254 - sectionData.id.toString(), sectionData.courseType));  
255 - },  
256 - child: SectionVideoItem(  
257 - unitEntity: bloc.courseUnitEntity,  
258 - lessons: sectionData,  
259 - ),  
260 - );  
261 - }  
262 - }); 285 + ///进入课堂
  286 + bloc.add(RequestEnterClassEvent(
  287 + sectionData.id.toString(), sectionData.courseType));
  288 + },
  289 + child: SectionVideoItem(
  290 + unitEntity: bloc.courseUnitEntity,
  291 + lessons: sectionData,
  292 + ),
  293 + );
  294 + }
  295 + });
  296 + }
263 } 297 }
lib/pages/unit/view.dart
@@ -64,7 +64,7 @@ class UnitPage extends StatelessWidget { @@ -64,7 +64,7 @@ class UnitPage extends StatelessWidget {
64 pushNamed(AppRouteName.courseSection, 64 pushNamed(AppRouteName.courseSection,
65 arguments: { 65 arguments: {
66 'courseUnitEntity': bloc.unitData, 66 'courseUnitEntity': bloc.unitData,
67 - 'courseUnitDetail': data 67 + 'courseUnitId': data.id
68 }); 68 });
69 }, 69 },
70 child: CourseUnitItem( 70 child: CourseUnitItem(
lib/pages/video/lookvideo/widgets/video_widget.dart
@@ -51,10 +51,7 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; { @@ -51,10 +51,7 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
51 if (_controller!.value.isInitialized) { 51 if (_controller!.value.isInitialized) {
52 if (_controller!.value.isPlaying) { 52 if (_controller!.value.isPlaying) {
53 setState(() { 53 setState(() {
54 - double currentSecond =  
55 - (_controller!.value.position.inMinutes.remainder(60) * 60 +  
56 - _controller!.value.position.inSeconds.remainder(60))  
57 - .toDouble(); 54 + double currentSecond = getCurrentPositionSeconds().toDouble();
58 int totalSecond = 55 int totalSecond =
59 _controller!.value.duration.inMinutes.remainder(60) * 60 + 56 _controller!.value.duration.inMinutes.remainder(60) * 60 +
60 _controller!.value.duration.inSeconds.remainder(60); 57 _controller!.value.duration.inSeconds.remainder(60);
@@ -75,13 +72,10 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; { @@ -75,13 +72,10 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
75 _controller!.value.duration.inSeconds) { 72 _controller!.value.duration.inSeconds) {
76 final lookVideoBloc = context.read<LookVideoBloc>(); 73 final lookVideoBloc = context.read<LookVideoBloc>();
77 lookVideoBloc.sectionComplete(() { 74 lookVideoBloc.sectionComplete(() {
78 - String currentTime =  
79 - (_controller!.value.position.inMinutes.remainder(60) * 60 +  
80 - _controller!.value.position.inSeconds.remainder(60))  
81 - .toString();  
82 popPage(data: { 75 popPage(data: {
83 'courseLessonId': widget.courseLessonId, 76 'courseLessonId': widget.courseLessonId,
84 - 'currentTime': currentTime, 77 + 'currentTime': getCurrentPositionSeconds(),
  78 + 'isCompleted': true,
85 'nextSection': widget.isTopic 79 'nextSection': widget.isTopic
86 }); 80 });
87 } as VoidCallback, 81 } as VoidCallback,
@@ -127,13 +121,9 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; { @@ -127,13 +121,9 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
127 popPage(); 121 popPage();
128 return; 122 return;
129 } 123 }
130 - String currentTime =  
131 - (_controller!.value.position.inMinutes.remainder(60) * 60 +  
132 - _controller!.value.position.inSeconds.remainder(60))  
133 - .toString();  
134 popPage(data: { 124 popPage(data: {
135 'courseLessonId': widget.courseLessonId, 125 'courseLessonId': widget.courseLessonId,
136 - 'currentTime': currentTime 126 + 'currentTime': getCurrentPositionSeconds(),
137 }); 127 });
138 } 128 }
139 } else if (type == OperationType.playState) { 129 } else if (type == OperationType.playState) {
@@ -250,10 +240,11 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; { @@ -250,10 +240,11 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
250 ) 240 )
251 : Container( 241 : Container(
252 color: Colors.white, 242 color: Colors.white,
253 - child: Text(  
254 - '视频加载中....',  
255 - style: TextStyle(fontSize: 20.sp, color: Colors.black),  
256 - ), 243 + child: const CircularProgressIndicator(),
  244 + // Text(
  245 + // '视频加载中....',
  246 + // style: TextStyle(fontSize: 20.sp, color: Colors.black),
  247 + // ),
257 ), 248 ),
258 ), 249 ),
259 ), 250 ),
@@ -270,4 +261,10 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; { @@ -270,4 +261,10 @@ class _VideoWidgetState extends State&lt;VideoWidget&gt; {
270 } 261 }
271 super.dispose(); 262 super.dispose();
272 } 263 }
  264 +
  265 + ///获取当前进度秒数
  266 + int getCurrentPositionSeconds() {
  267 + return (_controller!.value.position.inMinutes.remainder(60) * 60 +
  268 + _controller!.value.position.inSeconds.remainder(60));
  269 + }
273 } 270 }
lib/route/route.dart
@@ -126,17 +126,17 @@ class AppRouter { @@ -126,17 +126,17 @@ class AppRouter {
126 builder: (_) => UnitPage(courseModuleEntity: courseModuleEntity)); 126 builder: (_) => UnitPage(courseModuleEntity: courseModuleEntity));
127 case AppRouteName.courseSection: 127 case AppRouteName.courseSection:
128 CourseUnitEntity courseUnitEntity = CourseUnitEntity(); 128 CourseUnitEntity courseUnitEntity = CourseUnitEntity();
129 - CourseUnitDetail courseUnitDetail = CourseUnitDetail(); 129 + int courseUnitDetail = 0;
130 if (settings.arguments != null) { 130 if (settings.arguments != null) {
131 courseUnitEntity = (settings.arguments as Map) 131 courseUnitEntity = (settings.arguments as Map)
132 .getOrNull('courseUnitEntity') as CourseUnitEntity; 132 .getOrNull('courseUnitEntity') as CourseUnitEntity;
133 courseUnitDetail = (settings.arguments as Map) 133 courseUnitDetail = (settings.arguments as Map)
134 - .getOrNull('courseUnitDetail') as CourseUnitDetail; 134 + .getOrNull('courseUnitId');
135 } 135 }
136 return CupertinoPageRoute( 136 return CupertinoPageRoute(
137 builder: (_) => SectionPage( 137 builder: (_) => SectionPage(
138 courseUnitEntity: courseUnitEntity, 138 courseUnitEntity: courseUnitEntity,
139 - courseUnitDetail: courseUnitDetail)); 139 + courseUnitId: courseUnitDetail));
140 case AppRouteName.listen: 140 case AppRouteName.listen:
141 return CupertinoPageRoute(builder: (_) => const ListenPage()); 141 return CupertinoPageRoute(builder: (_) => const ListenPage());
142 case AppRouteName.shop: 142 case AppRouteName.shop: