Commit 2a3621f8408a29461f5101e8faa5999701a2d8f5

Authored by 吴启风
1 parent 258578de

feat:课程层级调整(增加unit层)

lib/common/request/apis.dart
... ... @@ -42,6 +42,9 @@ class Apis {
42 42 // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897663
43 43 static const String courseModule = 'home/courseModule';
44 44  
  45 + /// 课程单元列表
  46 + static const String courseUnit = 'home/courseUnit';
  47 +
45 48 /// 课程列表
46 49 // GET /home/courseLesson
47 50 // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897662
... ...
lib/common/request/dao/home_dao.dart
... ... @@ -2,18 +2,27 @@ import 'package:wow_english/common/request/request_client.dart';
2 2 import 'package:wow_english/models/course_entity.dart';
3 3  
4 4 import '../../../models/course_module_entity.dart';
  5 +import '../../../models/course_unit_entity.dart';
5 6  
6 7 class HomeDao {
7   - ///获取课程模块信息
  8 + ///获取课程模块(列表)信息
8 9 static Future<List<CourseModuleEntity?>?> courseModule() async {
9 10 var data = await requestClient.get<List<CourseModuleEntity>>(Apis.courseModule);
10 11 return data;
11 12 }
12 13  
  14 + ///课程单元列表
  15 + static Future<CourseUnitEntity?> courseUnit(int moduleId) async {
  16 + Map<String, dynamic> mapData = {};
  17 + mapData['moduleId'] = moduleId;
  18 + var data = await requestClient.get<CourseUnitEntity>(Apis.courseUnit, queryParameters: mapData);
  19 + return data;
  20 + }
  21 +
13 22 ///课程列表
14   - static Future<CourseEntity?> courseLesson({String moduleId = ''}) async {
  23 + static Future<CourseEntity?> courseLesson({int? moduleId}) async {
15 24 Map<String, dynamic> mapData = {};
16   - if (moduleId.isNotEmpty) {
  25 + if (moduleId != null) {
17 26 mapData['moduleId'] = moduleId;
18 27 }
19 28 var data = await requestClient.get<CourseEntity>(Apis.courseLesson, queryParameters: mapData);
... ...
lib/generated/json/app_config_entity.g.dart
1 1 import 'package:wow_english/generated/json/base/json_convert_content.dart';
2 2 import 'package:wow_english/models/app_config_entity.dart';
3 3  
4   -AppConfigEntity $AppConfigEntityEntityFromJson(
5   - Map<String, dynamic> json) {
6   - final AppConfigEntity appConfigEntityEntity = AppConfigEntity();
  4 +AppConfigEntity $AppConfigEntityFromJson(Map<String, dynamic> json) {
  5 + final AppConfigEntity appConfigEntity = AppConfigEntity();
7 6 final bool? androidForceUpdate = jsonConvert.convert<bool>(
8 7 json['androidForceUpdate']);
9 8 if (androidForceUpdate != null) {
10   - appConfigEntityEntity.androidForceUpdate = androidForceUpdate;
  9 + appConfigEntity.androidForceUpdate = androidForceUpdate;
11 10 }
12 11 final bool? androidRecommendUpdate = jsonConvert.convert<bool>(
13 12 json['androidRecommendUpdate']);
14 13 if (androidRecommendUpdate != null) {
15   - appConfigEntityEntity.androidRecommendUpdate = androidRecommendUpdate;
  14 + appConfigEntity.androidRecommendUpdate = androidRecommendUpdate;
16 15 }
17 16 final String? androidUpdatePackageUrl = jsonConvert.convert<String>(
18 17 json['androidUpdatePackageUrl']);
19 18 if (androidUpdatePackageUrl != null) {
20   - appConfigEntityEntity.androidUpdatePackageUrl = androidUpdatePackageUrl;
  19 + appConfigEntity.androidUpdatePackageUrl = androidUpdatePackageUrl;
21 20 }
22 21 final int? androidVersion = jsonConvert.convert<int>(json['androidVersion']);
23 22 if (androidVersion != null) {
24   - appConfigEntityEntity.androidVersion = androidVersion;
  23 + appConfigEntity.androidVersion = androidVersion;
25 24 }
26 25 final bool? iosForceUpdate = jsonConvert.convert<bool>(
27 26 json['iosForceUpdate']);
28 27 if (iosForceUpdate != null) {
29   - appConfigEntityEntity.iosForceUpdate = iosForceUpdate;
  28 + appConfigEntity.iosForceUpdate = iosForceUpdate;
30 29 }
31 30 final bool? iosRecommendUpdate = jsonConvert.convert<bool>(
32 31 json['iosRecommendUpdate']);
33 32 if (iosRecommendUpdate != null) {
34   - appConfigEntityEntity.iosRecommendUpdate = iosRecommendUpdate;
  33 + appConfigEntity.iosRecommendUpdate = iosRecommendUpdate;
35 34 }
36 35 final int? iosVersion = jsonConvert.convert<int>(json['iosVersion']);
37 36 if (iosVersion != null) {
38   - appConfigEntityEntity.iosVersion = iosVersion;
  37 + appConfigEntity.iosVersion = iosVersion;
  38 + }
  39 + final String? updatePackageDescription = jsonConvert.convert<String>(
  40 + json['updatePackageDescription']);
  41 + if (updatePackageDescription != null) {
  42 + appConfigEntity.updatePackageDescription = updatePackageDescription;
39 43 }
40 44 final String? noticeBeforePurchaseUrl = jsonConvert.convert<String>(
41 45 json['noticeBeforePurchaseUrl']);
42 46 if (noticeBeforePurchaseUrl != null) {
43   - appConfigEntityEntity.noticeBeforePurchaseUrl = noticeBeforePurchaseUrl;
  47 + appConfigEntity.noticeBeforePurchaseUrl = noticeBeforePurchaseUrl;
44 48 }
45 49 final String? safe = jsonConvert.convert<String>(json['safe']);
46 50 if (safe != null) {
47   - appConfigEntityEntity.safe = safe;
  51 + appConfigEntity.safe = safe;
48 52 }
49   - return appConfigEntityEntity;
  53 + return appConfigEntity;
50 54 }
51 55  
52   -Map<String, dynamic> $AppConfigEntityEntityToJson(
53   - AppConfigEntity entity) {
  56 +Map<String, dynamic> $AppConfigEntityToJson(AppConfigEntity entity) {
54 57 final Map<String, dynamic> data = <String, dynamic>{};
55 58 data['androidForceUpdate'] = entity.androidForceUpdate;
56 59 data['androidRecommendUpdate'] = entity.androidRecommendUpdate;
... ... @@ -59,12 +62,13 @@ Map&lt;String, dynamic&gt; $AppConfigEntityEntityToJson(
59 62 data['iosForceUpdate'] = entity.iosForceUpdate;
60 63 data['iosRecommendUpdate'] = entity.iosRecommendUpdate;
61 64 data['iosVersion'] = entity.iosVersion;
  65 + data['updatePackageDescription'] = entity.updatePackageDescription;
62 66 data['noticeBeforePurchaseUrl'] = entity.noticeBeforePurchaseUrl;
63 67 data['safe'] = entity.safe;
64 68 return data;
65 69 }
66 70  
67   -extension AppConfigEntityEntityExtension on AppConfigEntity {
  71 +extension AppConfigEntityExtension on AppConfigEntity {
68 72 AppConfigEntity copyWith({
69 73 bool? androidForceUpdate,
70 74 bool? androidRecommendUpdate,
... ... @@ -73,6 +77,7 @@ extension AppConfigEntityEntityExtension on AppConfigEntity {
73 77 bool? iosForceUpdate,
74 78 bool? iosRecommendUpdate,
75 79 int? iosVersion,
  80 + String? updatePackageDescription,
76 81 String? noticeBeforePurchaseUrl,
77 82 String? safe,
78 83 }) {
... ... @@ -86,6 +91,8 @@ extension AppConfigEntityEntityExtension on AppConfigEntity {
86 91 ..iosForceUpdate = iosForceUpdate ?? this.iosForceUpdate
87 92 ..iosRecommendUpdate = iosRecommendUpdate ?? this.iosRecommendUpdate
88 93 ..iosVersion = iosVersion ?? this.iosVersion
  94 + ..updatePackageDescription = updatePackageDescription ??
  95 + this.updatePackageDescription
89 96 ..noticeBeforePurchaseUrl = noticeBeforePurchaseUrl ??
90 97 this.noticeBeforePurchaseUrl
91 98 ..safe = safe ?? this.safe;
... ...
lib/generated/json/base/json_convert_content.dart
... ... @@ -9,6 +9,7 @@ import &#39;package:wow_english/models/app_config_entity.dart&#39;;
9 9 import 'package:wow_english/models/course_entity.dart';
10 10 import 'package:wow_english/models/course_module_entity.dart';
11 11 import 'package:wow_english/models/course_process_entity.dart';
  12 +import 'package:wow_english/models/course_unit_entity.dart';
12 13 import 'package:wow_english/models/follow_read_entity.dart';
13 14 import 'package:wow_english/models/listen_entity.dart';
14 15 import 'package:wow_english/models/product_entity.dart';
... ... @@ -192,6 +193,14 @@ class JsonConvert {
192 193 return data.map<CourseProcessVideos>((Map<String, dynamic> e) =>
193 194 CourseProcessVideos.fromJson(e)).toList() as M;
194 195 }
  196 + if (<CourseUnitEntity>[] is M) {
  197 + return data.map<CourseUnitEntity>((Map<String, dynamic> e) =>
  198 + CourseUnitEntity.fromJson(e)).toList() as M;
  199 + }
  200 + if (<CourseUnitDetail>[] is M) {
  201 + return data.map<CourseUnitDetail>((Map<String, dynamic> e) =>
  202 + CourseUnitDetail.fromJson(e)).toList() as M;
  203 + }
195 204 if (<FollowReadEntity>[] is M) {
196 205 return data.map<FollowReadEntity>((Map<String, dynamic> e) =>
197 206 FollowReadEntity.fromJson(e)).toList() as M;
... ... @@ -246,6 +255,8 @@ class JsonConvertClassCollection {
246 255 (CourseProcessTopicsTopicAnswerList)
247 256 .toString(): CourseProcessTopicsTopicAnswerList.fromJson,
248 257 (CourseProcessVideos).toString(): CourseProcessVideos.fromJson,
  258 + (CourseUnitEntity).toString(): CourseUnitEntity.fromJson,
  259 + (CourseUnitDetail).toString(): CourseUnitDetail.fromJson,
249 260 (FollowReadEntity).toString(): FollowReadEntity.fromJson,
250 261 (ListenEntity).toString(): ListenEntity.fromJson,
251 262 (ProductEntity).toString(): ProductEntity.fromJson,
... ...
lib/generated/json/course_module_entity.g.dart
... ... @@ -3,7 +3,7 @@ import &#39;package:wow_english/models/course_module_entity.dart&#39;;
3 3  
4 4 CourseModuleEntity $CourseModuleEntityFromJson(Map<String, dynamic> json) {
5 5 final CourseModuleEntity courseModuleEntity = CourseModuleEntity();
6   - final String? id = jsonConvert.convert<String>(json['id']);
  6 + final int? id = jsonConvert.convert<int>(json['id']);
7 7 if (id != null) {
8 8 courseModuleEntity.id = id;
9 9 }
... ... @@ -90,7 +90,7 @@ Map&lt;String, dynamic&gt; $CourseModuleEntityToJson(CourseModuleEntity entity) {
90 90  
91 91 extension CourseModuleEntityExtension on CourseModuleEntity {
92 92 CourseModuleEntity copyWith({
93   - String? id,
  93 + int? id,
94 94 String? code,
95 95 int? courseModuleThemeId,
96 96 int? courseTotal,
... ...
lib/generated/json/course_unit_entity.g.dart 0 → 100644
  1 +import 'package:wow_english/generated/json/base/json_convert_content.dart';
  2 +import 'package:wow_english/models/course_unit_entity.dart';
  3 +
  4 +CourseUnitEntity $CourseUnitEntityFromJson(Map<String, dynamic> json) {
  5 + final CourseUnitEntity courseUnitEntity = CourseUnitEntity();
  6 + final List<
  7 + CourseUnitDetail>? courseUnitVOList = (json['courseUnitVOList'] as List<
  8 + dynamic>?)
  9 + ?.map(
  10 + (e) => jsonConvert.convert<CourseUnitDetail>(e) as CourseUnitDetail)
  11 + .toList();
  12 + if (courseUnitVOList != null) {
  13 + courseUnitEntity.courseUnitVOList = courseUnitVOList;
  14 + }
  15 + final int? nowStep = jsonConvert.convert<int>(json['nowStep']);
  16 + if (nowStep != null) {
  17 + courseUnitEntity.nowStep = nowStep;
  18 + }
  19 + final int? total = jsonConvert.convert<int>(json['total']);
  20 + if (total != null) {
  21 + courseUnitEntity.total = total;
  22 + }
  23 + final int? nowCourseModuleId = jsonConvert.convert<int>(
  24 + json['nowCourseModuleId']);
  25 + if (nowCourseModuleId != null) {
  26 + courseUnitEntity.nowCourseModuleId = nowCourseModuleId;
  27 + }
  28 + final String? nowCourseModuleName = jsonConvert.convert<String>(
  29 + json['nowCourseModuleName']);
  30 + if (nowCourseModuleName != null) {
  31 + courseUnitEntity.nowCourseModuleName = nowCourseModuleName;
  32 + }
  33 + final String? courseModuleThemeColor = jsonConvert.convert<String>(
  34 + json['courseModuleThemeColor']);
  35 + if (courseModuleThemeColor != null) {
  36 + courseUnitEntity.courseModuleThemeColor = courseModuleThemeColor;
  37 + }
  38 + final String? courseModuleCode = jsonConvert.convert<String>(
  39 + json['courseModuleCode']);
  40 + if (courseModuleCode != null) {
  41 + courseUnitEntity.courseModuleCode = courseModuleCode;
  42 + }
  43 + return courseUnitEntity;
  44 +}
  45 +
  46 +Map<String, dynamic> $CourseUnitEntityToJson(CourseUnitEntity entity) {
  47 + final Map<String, dynamic> data = <String, dynamic>{};
  48 + data['courseUnitVOList'] =
  49 + entity.courseUnitVOList?.map((v) => v.toJson()).toList();
  50 + data['nowStep'] = entity.nowStep;
  51 + data['total'] = entity.total;
  52 + data['nowCourseModuleId'] = entity.nowCourseModuleId;
  53 + data['nowCourseModuleName'] = entity.nowCourseModuleName;
  54 + data['courseModuleThemeColor'] = entity.courseModuleThemeColor;
  55 + data['courseModuleCode'] = entity.courseModuleCode;
  56 + return data;
  57 +}
  58 +
  59 +extension CourseUnitEntityExtension on CourseUnitEntity {
  60 + CourseUnitEntity copyWith({
  61 + List<CourseUnitDetail>? courseUnitVOList,
  62 + int? nowStep,
  63 + int? total,
  64 + int? nowCourseModuleId,
  65 + String? nowCourseModuleName,
  66 + String? courseModuleThemeColor,
  67 + String? courseModuleCode,
  68 + }) {
  69 + return CourseUnitEntity()
  70 + ..courseUnitVOList = courseUnitVOList ?? this.courseUnitVOList
  71 + ..nowStep = nowStep ?? this.nowStep
  72 + ..total = total ?? this.total
  73 + ..nowCourseModuleId = nowCourseModuleId ?? this.nowCourseModuleId
  74 + ..nowCourseModuleName = nowCourseModuleName ?? this.nowCourseModuleName
  75 + ..courseModuleThemeColor = courseModuleThemeColor ??
  76 + this.courseModuleThemeColor
  77 + ..courseModuleCode = courseModuleCode ?? this.courseModuleCode;
  78 + }
  79 +}
  80 +
  81 +CourseUnitDetail $CourseUnitDetailFromJson(Map<String, dynamic> json) {
  82 + final CourseUnitDetail courseUnitDetail = CourseUnitDetail();
  83 + final int? courseModuleId = jsonConvert.convert<int>(json['courseModuleId']);
  84 + if (courseModuleId != null) {
  85 + courseUnitDetail.courseModuleId = courseModuleId;
  86 + }
  87 + final int? id = jsonConvert.convert<int>(json['id']);
  88 + if (id != null) {
  89 + courseUnitDetail.id = id;
  90 + }
  91 + final String? name = jsonConvert.convert<String>(json['name']);
  92 + if (name != null) {
  93 + courseUnitDetail.name = name;
  94 + }
  95 + final String? coverUrl = jsonConvert.convert<String>(json['coverUrl']);
  96 + if (coverUrl != null) {
  97 + courseUnitDetail.coverUrl = coverUrl;
  98 + }
  99 + final bool? lock = jsonConvert.convert<bool>(json['lock']);
  100 + if (lock != null) {
  101 + courseUnitDetail.lock = lock;
  102 + }
  103 + final int? sortOrder = jsonConvert.convert<int>(json['sortOrder']);
  104 + if (sortOrder != null) {
  105 + courseUnitDetail.sortOrder = sortOrder;
  106 + }
  107 + final int? status = jsonConvert.convert<int>(json['status']);
  108 + if (status != null) {
  109 + courseUnitDetail.status = status;
  110 + }
  111 + return courseUnitDetail;
  112 +}
  113 +
  114 +Map<String, dynamic> $CourseUnitDetailToJson(CourseUnitDetail entity) {
  115 + final Map<String, dynamic> data = <String, dynamic>{};
  116 + data['courseModuleId'] = entity.courseModuleId;
  117 + data['id'] = entity.id;
  118 + data['name'] = entity.name;
  119 + data['coverUrl'] = entity.coverUrl;
  120 + data['lock'] = entity.lock;
  121 + data['sortOrder'] = entity.sortOrder;
  122 + data['status'] = entity.status;
  123 + return data;
  124 +}
  125 +
  126 +extension CourseUnitDetailExtension on CourseUnitDetail {
  127 + CourseUnitDetail copyWith({
  128 + int? courseModuleId,
  129 + int? id,
  130 + String? name,
  131 + String? coverUrl,
  132 + bool? lock,
  133 + int? sortOrder,
  134 + int? status,
  135 + }) {
  136 + return CourseUnitDetail()
  137 + ..courseModuleId = courseModuleId ?? this.courseModuleId
  138 + ..id = id ?? this.id
  139 + ..name = name ?? this.name
  140 + ..coverUrl = coverUrl ?? this.coverUrl
  141 + ..lock = lock ?? this.lock
  142 + ..sortOrder = sortOrder ?? this.sortOrder
  143 + ..status = status ?? this.status;
  144 + }
  145 +}
0 146 \ No newline at end of file
... ...
lib/models/course_module_entity.dart
... ... @@ -5,7 +5,7 @@ import &#39;package:wow_english/generated/json/course_module_entity.g.dart&#39;;
5 5  
6 6 @JsonSerializable()
7 7 class CourseModuleEntity {
8   - late String id;
  8 + late int id;
9 9 String? code;
10 10 int? courseModuleThemeId;
11 11 int? courseTotal;
... ...
lib/models/course_unit_entity.dart 0 → 100644
  1 +import 'package:wow_english/generated/json/base/json_field.dart';
  2 +import 'package:wow_english/generated/json/course_unit_entity.g.dart';
  3 +import 'dart:convert';
  4 +
  5 +export 'package:wow_english/generated/json/course_unit_entity.g.dart';
  6 +
  7 +@JsonSerializable()
  8 +class CourseUnitEntity {
  9 +
  10 + // 课程详情列表
  11 + List<CourseUnitDetail>? courseUnitVOList;
  12 +
  13 + // 当前进行了多少节课程
  14 + int? nowStep;
  15 +
  16 + // 当前模块一共多少节课程
  17 + int? total;
  18 +
  19 + // 当前模块id
  20 + int? nowCourseModuleId;
  21 +
  22 + // 当前模块名
  23 + String? nowCourseModuleName;
  24 +
  25 + // 主题颜色值
  26 + String? courseModuleThemeColor;
  27 +
  28 + // 课程模块code
  29 + String? courseModuleCode;
  30 +
  31 + CourseUnitEntity();
  32 +
  33 + factory CourseUnitEntity.fromJson(Map<String, dynamic> json) => $CourseUnitEntityFromJson(json);
  34 +
  35 + Map<String, dynamic> toJson() => $CourseUnitEntityToJson(this);
  36 +
  37 + @override
  38 + String toString() {
  39 + return jsonEncode(this);
  40 + }
  41 +}
  42 +
  43 +
  44 +@JsonSerializable()
  45 +class CourseUnitDetail {
  46 +
  47 + // 模块id
  48 + int? courseModuleId;
  49 +
  50 + // 单元
  51 + int? id;
  52 +
  53 + // 单元名称
  54 + String? name;
  55 +
  56 + // 单元封面
  57 + String? coverUrl;
  58 +
  59 + bool? lock;
  60 +
  61 + int? sortOrder;
  62 +
  63 + int? status;
  64 +
  65 + CourseUnitDetail();
  66 +
  67 + factory CourseUnitDetail.fromJson(Map<String, dynamic> json) => $CourseUnitDetailFromJson(json);
  68 +
  69 + Map<String, dynamic> toJson() => $CourseUnitDetailToJson(this);
  70 +
  71 + @override
  72 + String toString() {
  73 + return jsonEncode(this);
  74 + }
  75 +}
0 76 \ No newline at end of file
... ...
lib/pages/home/bloc/home_bloc.dart
... ... @@ -13,7 +13,7 @@ part &#39;home_event.dart&#39;;
13 13 part 'home_state.dart';
14 14  
15 15 class HomeBloc extends Bloc<HomeEvent, HomeState> {
16   - final String? moduleId;
  16 + final int? moduleId;
17 17  
18 18 CourseEntity? _modelData;
19 19  
... ... @@ -33,7 +33,7 @@ class HomeBloc extends Bloc&lt;HomeEvent, HomeState&gt; {
33 33 void _requestData(RequestDataEvent event, Emitter<HomeState> emitter) async {
34 34 try {
35 35 await loading(() async {
36   - _modelData = await HomeDao.courseLesson(moduleId: moduleId ?? '');
  36 + _modelData = await HomeDao.courseLesson(moduleId: moduleId);
37 37 emitter(HomeDataLoadState());
38 38 });
39 39 } catch (e) {
... ...
lib/pages/home/home_page.dart
... ... @@ -6,7 +6,7 @@ import &#39;package:wow_english/common/extension/string_extension.dart&#39;;
6 6 import 'package:wow_english/models/course_entity.dart';
7 7 import 'package:wow_english/pages/home/widgets/home_bouns_item.dart';
8 8 import 'package:wow_english/pages/home/widgets/home_tab_header_widget.dart';
9   -import 'package:wow_english/pages/home/widgets/home_vidoe_item.dart';
  9 +import 'package:wow_english/pages/home/widgets/home_video_item.dart';
10 10 import 'package:wow_english/route/route.dart';
11 11 import 'package:wow_english/utils/toast_util.dart';
12 12  
... ... @@ -17,7 +17,7 @@ class HomePage extends StatelessWidget {
17 17 const HomePage({super.key, this.moduleId});
18 18  
19 19 /// 模块id
20   - final String? moduleId;
  20 + final int? moduleId;
21 21  
22 22 @override
23 23 Widget build(BuildContext context) {
... ...
lib/pages/home/widgets/home_vidoe_item.dart renamed to lib/pages/home/widgets/home_video_item.dart
lib/pages/lessons/lesson_page.dart
... ... @@ -171,7 +171,7 @@ class _LessonPageView extends StatelessWidget {
171 171 model: model,
172 172 isSelected: bloc.currentPageIndex == index,
173 173 onClickEvent: () {
174   - pushNamedAndRemoveUntil(AppRouteName.home, (route) => false,arguments: {'moduleId':model?.id});
  174 + pushNamed(AppRouteName.unit, arguments: {'courseModuleEntity':model});
175 175 },
176 176 ),
177 177 ),
... ...
lib/pages/unit/bloc.dart 0 → 100644
  1 +import 'package:bloc/bloc.dart';
  2 +
  3 +import '../../common/request/dao/home_dao.dart';
  4 +import '../../common/request/exception.dart';
  5 +import '../../models/course_unit_entity.dart';
  6 +import '../../utils/loading.dart';
  7 +import '../../utils/toast_util.dart';
  8 +import 'event.dart';
  9 +import 'state.dart';
  10 +
  11 +class UnitBloc extends Bloc<UnitEvent, UnitState> {
  12 +
  13 + CourseUnitEntity? _modelData;
  14 +
  15 + CourseUnitEntity? get modelData => _modelData;
  16 +
  17 +
  18 + UnitBloc() : super(UnitState().init()) {
  19 + on<RequestUnitDataEvent>(_requestData);
  20 + }
  21 +
  22 + void _requestData(RequestUnitDataEvent event, Emitter<UnitState> emitter) async {
  23 + try {
  24 + await loading(() async {
  25 + _modelData = await HomeDao.courseUnit(event.moduleId);
  26 + emitter(UnitDataLoadState());
  27 + });
  28 + } catch (e) {
  29 + if (e is ApiException) {
  30 + showToast(e.message ?? '请求失败,请检查网络连接');
  31 + }
  32 + }
  33 + }
  34 +}
... ...
lib/pages/unit/event.dart 0 → 100644
  1 +abstract class UnitEvent {}
  2 +
  3 +// 获取课程单元数据
  4 +class RequestUnitDataEvent extends UnitEvent {
  5 + final int moduleId;
  6 +
  7 + RequestUnitDataEvent(this.moduleId);
  8 +}
... ...
lib/pages/unit/state.dart 0 → 100644
  1 +class UnitState {
  2 + UnitState init() {
  3 + return UnitState();
  4 + }
  5 +
  6 + UnitState clone() {
  7 + return UnitState();
  8 + }
  9 +}
  10 +
  11 +class UnitDataLoadState extends UnitState {}
0 12 \ No newline at end of file
... ...
lib/pages/unit/view.dart 0 → 100644
  1 +import 'package:flutter/material.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  4 +import 'package:wow_english/pages/unit/state.dart';
  5 +import 'package:wow_english/pages/unit/widget/course_unit_header_widget.dart';
  6 +import 'package:wow_english/pages/unit/widget/course_unit_item.dart';
  7 +import 'package:wow_english/route/route.dart';
  8 +
  9 +import '../../models/course_module_entity.dart';
  10 +import '../../models/course_unit_entity.dart';
  11 +import '../../utils/toast_util.dart';
  12 +import 'bloc.dart';
  13 +import 'event.dart';
  14 +
  15 +class UnitPage extends StatelessWidget {
  16 + const UnitPage({super.key, required this.courseEntity});
  17 +
  18 + /// 模块
  19 + final CourseModuleEntity courseEntity;
  20 +
  21 + @override
  22 + Widget build(BuildContext context) {
  23 + return BlocProvider(
  24 + create: (BuildContext context) =>
  25 + UnitBloc()..add(RequestUnitDataEvent(courseEntity.id)),
  26 + child: Builder(builder: (context) => _buildPage(context)),
  27 + );
  28 + }
  29 +
  30 + Widget _buildPage(BuildContext context) {
  31 + return BlocBuilder<UnitBloc, UnitState>(builder: (context, state) {
  32 + final bloc = BlocProvider.of<UnitBloc>(context);
  33 + return Scaffold(
  34 + body: Container(
  35 + color: Colors.white,
  36 + child: Center(
  37 + child: Column(
  38 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  39 + children: [
  40 + CourseUnitHeaderWidget(entity: courseEntity),
  41 + Expanded(
  42 + child: ListView.builder(
  43 + itemCount:
  44 + bloc.modelData?.courseUnitVOList?.length ?? 0,
  45 + scrollDirection: Axis.horizontal,
  46 + itemBuilder: (BuildContext context, int index) {
  47 + CourseUnitDetail? data =
  48 + bloc.modelData?.courseUnitVOList?[index];
  49 + return GestureDetector(
  50 + onTap: () {
  51 + if (data.lock == true) {
  52 + showToast('当前unit暂未解锁');
  53 + return;
  54 + }
  55 +
  56 + ///进入课堂
  57 + pushNamedAndRemoveUntil(
  58 + AppRouteName.home, (route) => route.isFirst,
  59 + arguments: {
  60 + 'moduleId': data.courseModuleId,
  61 + 'unitId': data.id
  62 + });
  63 + },
  64 + child: CourseUnitItem(
  65 + unitEntity: bloc.modelData!,
  66 + unitLesson: data!,
  67 + ),
  68 + );
  69 + })),
  70 + SafeArea(
  71 + child: Column(
  72 + children: [
  73 + 6.verticalSpace,
  74 + ],
  75 + ),
  76 + )
  77 + ],
  78 + ),
  79 + ),
  80 + ),
  81 + );
  82 + });
  83 + }
  84 +}
... ...
lib/pages/unit/widget/course_unit_header_widget.dart 0 → 100644
  1 +import 'package:flutter/material.dart';
  2 +import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  4 +import 'package:wow_english/common/extension/string_extension.dart';
  5 +import 'package:wow_english/pages/user/bloc/user_bloc.dart';
  6 +
  7 +import '../../../models/course_module_entity.dart';
  8 +import '../../home/courese_module_model.dart';
  9 +
  10 +class CourseUnitHeaderWidget extends StatelessWidget {
  11 + const CourseUnitHeaderWidget({super.key, this.entity});
  12 +
  13 + final CourseModuleEntity? entity;
  14 +
  15 + @override
  16 + Widget build(BuildContext context) {
  17 + return BlocBuilder<UserBloc, UserState>(
  18 + builder: (context, state) {
  19 + return Container(
  20 + height: 45,
  21 + width: double.infinity,
  22 + color:
  23 + CourseModuleModel(entity?.code ?? 'Phase-1').color,
  24 + padding: EdgeInsets.symmetric(horizontal: 9.5.w),
  25 + child: Row(
  26 + children: [
  27 + ScreenUtil().bottomBarHeight.horizontalSpace,
  28 + GestureDetector(
  29 + onTap: () {
  30 + Navigator.pop(context);
  31 + },
  32 + child: Container(
  33 + alignment: Alignment.center,
  34 + child: Image.asset(
  35 + 'back_around'.assetPng,
  36 + height: 40.h,
  37 + width: 40.w,
  38 + ),
  39 + ),
  40 + ),
  41 + 20.horizontalSpace,
  42 + Expanded(
  43 + child: Text(entity?.name ??
  44 + CourseModuleModel(entity?.code ?? 'Phase-1')
  45 + .courseModuleTitle,
  46 + textAlign: TextAlign.left,
  47 + style: const TextStyle(color: Colors.white, fontSize: 30.0),
  48 + )),
  49 + ScreenUtil().bottomBarHeight.horizontalSpace,
  50 + ],
  51 + ));
  52 + },
  53 + );
  54 + }
  55 +}
... ...
lib/pages/unit/widget/course_unit_item.dart 0 → 100644
  1 +import 'package:flutter/material.dart';
  2 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  3 +import 'package:wow_english/common/extension/string_extension.dart';
  4 +import 'package:wow_english/common/widgets/ow_image_widget.dart';
  5 +
  6 +import '../../../models/course_unit_entity.dart';
  7 +
  8 +class CourseUnitItem extends StatelessWidget {
  9 + const CourseUnitItem(
  10 + {super.key, required this.unitEntity, required this.unitLesson});
  11 +
  12 + final CourseUnitEntity unitEntity;
  13 + final CourseUnitDetail unitLesson;
  14 +
  15 + @override
  16 + Widget build(BuildContext context) {
  17 + return Padding(
  18 + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 24.h),
  19 + child: Container(
  20 + width: 165.w,
  21 + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 24.h),
  22 + decoration: BoxDecoration(
  23 + image: DecorationImage(
  24 + image: AssetImage('gendubeij'.assetPng), fit: BoxFit.fill),
  25 + ),
  26 + child: Column(
  27 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
  28 + children: [
  29 + Expanded(
  30 + child: Container(
  31 + decoration: BoxDecoration(
  32 + border: Border.all(
  33 + width: 2,
  34 + color: const Color(0xFF140C10),
  35 + ),
  36 + borderRadius: BorderRadius.circular(6)),
  37 + child: OwImageWidget(
  38 + name: unitLesson.coverUrl ?? '',
  39 + fit: BoxFit.fitHeight,
  40 + ),
  41 + )),
  42 + 20.verticalSpace,
  43 + SizedBox(
  44 + height: 40.h,
  45 + child: Text(
  46 + unitLesson.name ?? '',
  47 + maxLines: 2,
  48 + overflow: TextOverflow.ellipsis,
  49 + style:
  50 + TextStyle(fontSize: 11.sp, color: const Color(0xFF140C10)),
  51 + ),
  52 + )
  53 + ],
  54 + ),
  55 + ),
  56 + );
  57 + }
  58 +}
... ...
lib/route/route.dart
... ... @@ -26,11 +26,12 @@ import &#39;package:wow_english/pages/user/setting/setting_page.dart&#39;;
26 26 import 'package:wow_english/pages/user/user_page.dart';
27 27 import 'package:wow_english/pages/video/lookvideo/look_video_page.dart';
28 28  
  29 +import '../models/course_module_entity.dart';
29 30 import '../pages/reading/reading_page.dart';
30 31 import '../pages/shopping/view.dart';
  32 +import '../pages/unit/view.dart';
31 33 import '../pages/user/setting/delete_account_page.dart';
32 34 import '../pages/user/setting/reback_page.dart';
33   -import '../utils/log_util.dart';
34 35  
35 36 class AppRouteName {
36 37 static const String splash = 'splash';
... ... @@ -43,7 +44,8 @@ class AppRouteName {
43 44 /// 设置密码,修改密码;不要自己调用,使用[SetPassWordPage.push]方法,隐藏这种实现
44 45 //static const String setPwd = 'setPwd';
45 46 static const String webView = 'webView';
46   - static const String lesson = 'lesson';
  47 + static const String unit = 'courseUnits';
  48 + static const String lesson = 'courseModules';
47 49 static const String listen = 'listen';
48 50 static const String shop = 'shop';
49 51 static const String exLesson = 'exLesson';
... ... @@ -100,9 +102,9 @@ class AppRouter {
100 102 case AppRouteName.games:
101 103 return CupertinoPageRoute(builder: (_) => const GamesPage());
102 104 case AppRouteName.home:
103   - var moduleId = '';
  105 + int? moduleId;
104 106 if (settings.arguments != null) {
105   - moduleId = (settings.arguments as Map)['moduleId'] as String;
  107 + moduleId = (settings.arguments as Map).getOrNull('moduleId') as int?;
106 108 }
107 109 return CupertinoPageRoute(
108 110 builder: (_) => HomePage(
... ... @@ -112,6 +114,12 @@ class AppRouter {
112 114 return CupertinoPageRoute(builder: (_) => const ForgetPasswordHomePage());
113 115 case AppRouteName.lesson:
114 116 return CupertinoPageRoute(builder: (_) => const LessonPage());
  117 + case AppRouteName.unit:
  118 + CourseModuleEntity courseEntity = CourseModuleEntity();
  119 + if (settings.arguments != null) {
  120 + courseEntity = (settings.arguments as Map).getOrNull('courseModuleEntity') as CourseModuleEntity;
  121 + }
  122 + return CupertinoPageRoute(builder: (_) => UnitPage(courseEntity: courseEntity));
115 123 case AppRouteName.listen:
116 124 return CupertinoPageRoute(builder: (_) => const ListenPage());
117 125 case AppRouteName.shop:
... ...