Kaynağa Gözat

我的课程

Steven 5 ay önce
ebeveyn
işleme
04cae55b65
64 değiştirilmiş dosya ile 4742 ekleme ve 251 silme
  1. 160 6
      KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj
  2. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@2x.png
  3. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@3x.png
  4. 6 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/Contents.json
  5. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/live_courseGroup_icon.imageset/Contents.json
  6. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/live_courseGroup_icon.imageset/live_courseGroup_icon@2x.png
  7. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/live_courseGroup_icon.imageset/live_courseGroup_icon@3x.png
  8. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/mine_page_live_tag.imageset/Contents.json
  9. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/mine_page_live_tag.imageset/mine_page_live_tag@2x.png
  10. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/mine_page_live_tag.imageset/mine_page_live_tag@3x.png
  11. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/myCourse_bg.imageset/Contents.json
  12. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/myCourse_bg.imageset/myCourse_bg@2x.png
  13. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/myCourse_bg.imageset/myCourse_bg@3x.png
  14. 14 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.h
  15. 23 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.m
  16. 6 6
      KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.xib
  17. 5 5
      KulexiuForStudent/KulexiuForStudent/Module/Course/View/MusicRoomCourseCell.xib
  18. 1 1
      KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/Controller/HomeArrangeCourseController.m
  19. 1 1
      KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/CourseTeacherDescCell.m
  20. 1 0
      KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/HomeArrangeAccompanyCourseView.m
  21. 2 0
      KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/HomeArrangeRankView.h
  22. 25 16
      KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/HomeArrangeRankView.m
  23. 2 1
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Controller/MyCourseViewController.h
  24. 149 37
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Controller/MyCourseViewController.m
  25. 19 12
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/LiveLessonModel.h
  26. 121 75
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/LiveLessonModel.m
  27. 30 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/ProgramCourseGroupModel.h
  28. 169 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/ProgramCourseGroupModel.m
  29. 10 12
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/VideoCourseModel.h
  30. 64 75
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/VideoCourseModel.m
  31. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/AccompanyCourseGroup/MyAccompanyCourseGroupView.h
  32. 355 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/AccompanyCourseGroup/MyAccompanyCourseGroupView.m
  33. 19 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupListCell.h
  34. 87 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupListCell.m
  35. 208 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupListCell.xib
  36. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupView.h
  37. 368 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupView.m
  38. 19 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicGroupListCell.h
  39. 80 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicGroupListCell.m
  40. 141 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicGroupListCell.xib
  41. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicRoomCourseGroupView.h
  42. 354 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicRoomCourseGroupView.m
  43. 24 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseGroupNavView.h
  44. 54 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseGroupNavView.m
  45. 86 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseGroupNavView.xib
  46. 33 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseRankSortView.h
  47. 338 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseRankSortView.m
  48. 140 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseRankSortView.xib
  49. 31 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseSearchView.h
  50. 65 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseSearchView.m
  51. 129 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseSearchView.xib
  52. 0 1
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLessonBodyView.m
  53. 1 1
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLiveCourseCell.m
  54. 19 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.h
  55. 86 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.m
  56. 147 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.xib
  57. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyVipCourseGroupView.h
  58. 356 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyVipCourseGroupView.m
  59. 2 2
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseCell.m
  60. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoCourseGroupView.h
  61. 346 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoCourseGroupView.m
  62. 19 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoGroupListCell.h
  63. 75 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoGroupListCell.m
  64. 196 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoGroupListCell.xib

+ 160 - 6
KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj

@@ -256,7 +256,6 @@
 		BC11921B280ED6A900A716F7 /* NewClassPopCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC11920F280ED6A900A716F7 /* NewClassPopCell.xib */; };
 		BC11921C280ED6A900A716F7 /* NewClassPopView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC119211280ED6A900A716F7 /* NewClassPopView.m */; };
 		BC11921D280ED6A900A716F7 /* NewClassPopCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC119212280ED6A900A716F7 /* NewClassPopCell.m */; };
-		BC119222280ED6F500A716F7 /* LiveLessonModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC11921E280ED6F400A716F7 /* LiveLessonModel.m */; };
 		BC119223280ED6F500A716F7 /* AccompanyLessonModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC11921F280ED6F400A716F7 /* AccompanyLessonModel.m */; };
 		BC11922A280ED8E800A716F7 /* LTSCalendarBottomView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC119224280ED8E700A716F7 /* LTSCalendarBottomView.m */; };
 		BC11922B280ED8E800A716F7 /* CourseNavView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC119226280ED8E800A716F7 /* CourseNavView.m */; };
@@ -306,6 +305,8 @@
 		BC1D02432C0490AB001F6A94 /* KSMuteTipsView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1D02402C0490AB001F6A94 /* KSMuteTipsView.m */; };
 		BC1E28492C77151A0063E0A1 /* KSDeleteFailedAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1E28482C77151A0063E0A1 /* KSDeleteFailedAlertView.m */; };
 		BC1E284B2C7715210063E0A1 /* KSDeleteFailedAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC1E284A2C7715210063E0A1 /* KSDeleteFailedAlertView.xib */; };
+		BC206EE32CEF29A6001F2B85 /* MyCourseRankSortView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC206EE12CEF29A6001F2B85 /* MyCourseRankSortView.m */; };
+		BC206EE42CEF29A6001F2B85 /* MyCourseRankSortView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC206EE22CEF29A6001F2B85 /* MyCourseRankSortView.xib */; };
 		BC27A06E280FF56C00F91E27 /* AccompanyEvaluateCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC27A06A280FF56B00F91E27 /* AccompanyEvaluateCell.xib */; };
 		BC27A06F280FF56C00F91E27 /* AccompanyStudentEvaCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC27A06B280FF56C00F91E27 /* AccompanyStudentEvaCell.m */; };
 		BC27A070280FF56C00F91E27 /* AccompanyStudentEvaCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC27A06C280FF56C00F91E27 /* AccompanyStudentEvaCell.xib */; };
@@ -572,6 +573,25 @@
 		BC71D2872888083B0010F14B /* tabbar4.json in Resources */ = {isa = PBXBuildFile; fileRef = BC71D2822888083B0010F14B /* tabbar4.json */; };
 		BC71D2882888083B0010F14B /* tabbar3.json in Resources */ = {isa = PBXBuildFile; fileRef = BC71D2832888083B0010F14B /* tabbar3.json */; };
 		BC71D2892888083B0010F14B /* tabbar5.json in Resources */ = {isa = PBXBuildFile; fileRef = BC71D2842888083B0010F14B /* tabbar5.json */; };
+		BC7354812CEED28000C2B35C /* MyMusicGroupListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC73546D2CEED28000C2B35C /* MyMusicGroupListCell.xib */; };
+		BC7354822CEED28000C2B35C /* MyVideoGroupListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC7354792CEED28000C2B35C /* MyVideoGroupListCell.xib */; };
+		BC7354832CEED28000C2B35C /* MyLiveCourseGroupListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC7354672CEED28000C2B35C /* MyLiveCourseGroupListCell.xib */; };
+		BC7354842CEED28000C2B35C /* MyCourseSearchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC7354732CEED28000C2B35C /* MyCourseSearchView.xib */; };
+		BC7354852CEED28000C2B35C /* MyProgramCourseGroupCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC73547D2CEED28000C2B35C /* MyProgramCourseGroupCell.xib */; };
+		BC7354862CEED28000C2B35C /* MyVipCourseGroupView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC73547F2CEED28000C2B35C /* MyVipCourseGroupView.m */; };
+		BC7354872CEED28000C2B35C /* MyCourseSearchView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354722CEED28000C2B35C /* MyCourseSearchView.m */; };
+		BC7354882CEED28000C2B35C /* MyVideoCourseGroupView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354762CEED28000C2B35C /* MyVideoCourseGroupView.m */; };
+		BC7354892CEED28000C2B35C /* MyLiveCourseGroupListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354662CEED28000C2B35C /* MyLiveCourseGroupListCell.m */; };
+		BC73548A2CEED28000C2B35C /* MyAccompanyCourseGroupView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354632CEED28000C2B35C /* MyAccompanyCourseGroupView.m */; };
+		BC73548B2CEED28000C2B35C /* MyLiveCourseGroupView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354692CEED28000C2B35C /* MyLiveCourseGroupView.m */; };
+		BC73548C2CEED28000C2B35C /* MyMusicGroupListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC73546C2CEED28000C2B35C /* MyMusicGroupListCell.m */; };
+		BC73548D2CEED28000C2B35C /* MyProgramCourseGroupCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC73547C2CEED28000C2B35C /* MyProgramCourseGroupCell.m */; };
+		BC73548E2CEED28000C2B35C /* MyVideoGroupListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354782CEED28000C2B35C /* MyVideoGroupListCell.m */; };
+		BC73548F2CEED28000C2B35C /* MyMusicRoomCourseGroupView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC73546F2CEED28000C2B35C /* MyMusicRoomCourseGroupView.m */; };
+		BC7354942CEED2AE00C2B35C /* ProgramCourseGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354932CEED2AE00C2B35C /* ProgramCourseGroupModel.m */; };
+		BC7354952CEED2AE00C2B35C /* LiveLessonModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354912CEED2AE00C2B35C /* LiveLessonModel.m */; };
+		BC7354992CEED2EB00C2B35C /* MyCourseGroupNavView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC7354982CEED2EB00C2B35C /* MyCourseGroupNavView.xib */; };
+		BC73549A2CEED2EB00C2B35C /* MyCourseGroupNavView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7354972CEED2EB00C2B35C /* MyCourseGroupNavView.m */; };
 		BC736A92288036E8004A9B0A /* MyVideoSearchView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC736A90288036E8004A9B0A /* MyVideoSearchView.m */; };
 		BC736A93288036E8004A9B0A /* MyVideoSearchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC736A91288036E8004A9B0A /* MyVideoSearchView.xib */; };
 		BC756CB628FE4E5D00AA9ECB /* KSChatTagView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC756CB528FE4E5D00AA9ECB /* KSChatTagView.m */; };
@@ -1463,10 +1483,8 @@
 		BC119210280ED6A900A716F7 /* NewClassPopCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewClassPopCell.h; sourceTree = "<group>"; };
 		BC119211280ED6A900A716F7 /* NewClassPopView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewClassPopView.m; sourceTree = "<group>"; };
 		BC119212280ED6A900A716F7 /* NewClassPopCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewClassPopCell.m; sourceTree = "<group>"; };
-		BC11921E280ED6F400A716F7 /* LiveLessonModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LiveLessonModel.m; sourceTree = "<group>"; };
 		BC11921F280ED6F400A716F7 /* AccompanyLessonModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AccompanyLessonModel.m; sourceTree = "<group>"; };
 		BC119220280ED6F500A716F7 /* AccompanyLessonModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccompanyLessonModel.h; sourceTree = "<group>"; };
-		BC119221280ED6F500A716F7 /* LiveLessonModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiveLessonModel.h; sourceTree = "<group>"; };
 		BC119224280ED8E700A716F7 /* LTSCalendarBottomView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LTSCalendarBottomView.m; sourceTree = "<group>"; };
 		BC119225280ED8E800A716F7 /* CourseNavView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CourseNavView.h; sourceTree = "<group>"; };
 		BC119226280ED8E800A716F7 /* CourseNavView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CourseNavView.m; sourceTree = "<group>"; };
@@ -1545,6 +1563,9 @@
 		BC1E28472C77151A0063E0A1 /* KSDeleteFailedAlertView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KSDeleteFailedAlertView.h; sourceTree = "<group>"; };
 		BC1E28482C77151A0063E0A1 /* KSDeleteFailedAlertView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSDeleteFailedAlertView.m; sourceTree = "<group>"; };
 		BC1E284A2C7715210063E0A1 /* KSDeleteFailedAlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KSDeleteFailedAlertView.xib; sourceTree = "<group>"; };
+		BC206EE02CEF29A6001F2B85 /* MyCourseRankSortView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyCourseRankSortView.h; sourceTree = "<group>"; };
+		BC206EE12CEF29A6001F2B85 /* MyCourseRankSortView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyCourseRankSortView.m; sourceTree = "<group>"; };
+		BC206EE22CEF29A6001F2B85 /* MyCourseRankSortView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCourseRankSortView.xib; sourceTree = "<group>"; };
 		BC255E822B29425F00A1FC27 /* SwiftImportHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftImportHeader.h; sourceTree = "<group>"; };
 		BC255E832B29425F00A1FC27 /* WebViewBaseConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewBaseConfig.h; sourceTree = "<group>"; };
 		BC27A068280FF56B00F91E27 /* AccompanyEvaluateCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccompanyEvaluateCell.h; sourceTree = "<group>"; };
@@ -1948,6 +1969,38 @@
 		BC71D2822888083B0010F14B /* tabbar4.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tabbar4.json; sourceTree = "<group>"; };
 		BC71D2832888083B0010F14B /* tabbar3.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tabbar3.json; sourceTree = "<group>"; };
 		BC71D2842888083B0010F14B /* tabbar5.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tabbar5.json; sourceTree = "<group>"; };
+		BC7354622CEED28000C2B35C /* MyAccompanyCourseGroupView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyAccompanyCourseGroupView.h; sourceTree = "<group>"; };
+		BC7354632CEED28000C2B35C /* MyAccompanyCourseGroupView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyAccompanyCourseGroupView.m; sourceTree = "<group>"; };
+		BC7354652CEED28000C2B35C /* MyLiveCourseGroupListCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyLiveCourseGroupListCell.h; sourceTree = "<group>"; };
+		BC7354662CEED28000C2B35C /* MyLiveCourseGroupListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyLiveCourseGroupListCell.m; sourceTree = "<group>"; };
+		BC7354672CEED28000C2B35C /* MyLiveCourseGroupListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyLiveCourseGroupListCell.xib; sourceTree = "<group>"; };
+		BC7354682CEED28000C2B35C /* MyLiveCourseGroupView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyLiveCourseGroupView.h; sourceTree = "<group>"; };
+		BC7354692CEED28000C2B35C /* MyLiveCourseGroupView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyLiveCourseGroupView.m; sourceTree = "<group>"; };
+		BC73546B2CEED28000C2B35C /* MyMusicGroupListCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyMusicGroupListCell.h; sourceTree = "<group>"; };
+		BC73546C2CEED28000C2B35C /* MyMusicGroupListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyMusicGroupListCell.m; sourceTree = "<group>"; };
+		BC73546D2CEED28000C2B35C /* MyMusicGroupListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyMusicGroupListCell.xib; sourceTree = "<group>"; };
+		BC73546E2CEED28000C2B35C /* MyMusicRoomCourseGroupView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyMusicRoomCourseGroupView.h; sourceTree = "<group>"; };
+		BC73546F2CEED28000C2B35C /* MyMusicRoomCourseGroupView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyMusicRoomCourseGroupView.m; sourceTree = "<group>"; };
+		BC7354712CEED28000C2B35C /* MyCourseSearchView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyCourseSearchView.h; sourceTree = "<group>"; };
+		BC7354722CEED28000C2B35C /* MyCourseSearchView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyCourseSearchView.m; sourceTree = "<group>"; };
+		BC7354732CEED28000C2B35C /* MyCourseSearchView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCourseSearchView.xib; sourceTree = "<group>"; };
+		BC7354752CEED28000C2B35C /* MyVideoCourseGroupView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyVideoCourseGroupView.h; sourceTree = "<group>"; };
+		BC7354762CEED28000C2B35C /* MyVideoCourseGroupView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyVideoCourseGroupView.m; sourceTree = "<group>"; };
+		BC7354772CEED28000C2B35C /* MyVideoGroupListCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyVideoGroupListCell.h; sourceTree = "<group>"; };
+		BC7354782CEED28000C2B35C /* MyVideoGroupListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyVideoGroupListCell.m; sourceTree = "<group>"; };
+		BC7354792CEED28000C2B35C /* MyVideoGroupListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyVideoGroupListCell.xib; sourceTree = "<group>"; };
+		BC73547B2CEED28000C2B35C /* MyProgramCourseGroupCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyProgramCourseGroupCell.h; sourceTree = "<group>"; };
+		BC73547C2CEED28000C2B35C /* MyProgramCourseGroupCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyProgramCourseGroupCell.m; sourceTree = "<group>"; };
+		BC73547D2CEED28000C2B35C /* MyProgramCourseGroupCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyProgramCourseGroupCell.xib; sourceTree = "<group>"; };
+		BC73547E2CEED28000C2B35C /* MyVipCourseGroupView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyVipCourseGroupView.h; sourceTree = "<group>"; };
+		BC73547F2CEED28000C2B35C /* MyVipCourseGroupView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyVipCourseGroupView.m; sourceTree = "<group>"; };
+		BC7354902CEED2AE00C2B35C /* LiveLessonModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LiveLessonModel.h; sourceTree = "<group>"; };
+		BC7354912CEED2AE00C2B35C /* LiveLessonModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LiveLessonModel.m; sourceTree = "<group>"; };
+		BC7354922CEED2AE00C2B35C /* ProgramCourseGroupModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProgramCourseGroupModel.h; sourceTree = "<group>"; };
+		BC7354932CEED2AE00C2B35C /* ProgramCourseGroupModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProgramCourseGroupModel.m; sourceTree = "<group>"; };
+		BC7354962CEED2EB00C2B35C /* MyCourseGroupNavView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyCourseGroupNavView.h; sourceTree = "<group>"; };
+		BC7354972CEED2EB00C2B35C /* MyCourseGroupNavView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyCourseGroupNavView.m; sourceTree = "<group>"; };
+		BC7354982CEED2EB00C2B35C /* MyCourseGroupNavView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCourseGroupNavView.xib; sourceTree = "<group>"; };
 		BC736A8F288036E8004A9B0A /* MyVideoSearchView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyVideoSearchView.h; sourceTree = "<group>"; };
 		BC736A90288036E8004A9B0A /* MyVideoSearchView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyVideoSearchView.m; sourceTree = "<group>"; };
 		BC736A91288036E8004A9B0A /* MyVideoSearchView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyVideoSearchView.xib; sourceTree = "<group>"; };
@@ -3882,10 +3935,12 @@
 		BC1191FB280ED63C00A716F7 /* Model */ = {
 			isa = PBXGroup;
 			children = (
+				BC7354902CEED2AE00C2B35C /* LiveLessonModel.h */,
+				BC7354912CEED2AE00C2B35C /* LiveLessonModel.m */,
+				BC7354922CEED2AE00C2B35C /* ProgramCourseGroupModel.h */,
+				BC7354932CEED2AE00C2B35C /* ProgramCourseGroupModel.m */,
 				BC119220280ED6F500A716F7 /* AccompanyLessonModel.h */,
 				BC11921F280ED6F400A716F7 /* AccompanyLessonModel.m */,
-				BC119221280ED6F500A716F7 /* LiveLessonModel.h */,
-				BC11921E280ED6F400A716F7 /* LiveLessonModel.m */,
 				BC0D1F732810165400C5D9E5 /* VideoCourseModel.h */,
 				BC0D1F742810165400C5D9E5 /* VideoCourseModel.m */,
 				BC494A7E28696BC300CCD343 /* MusicRoomListModel.h */,
@@ -3897,6 +3952,15 @@
 		BC1191FC280ED63C00A716F7 /* View */ = {
 			isa = PBXGroup;
 			children = (
+				BC7354962CEED2EB00C2B35C /* MyCourseGroupNavView.h */,
+				BC7354972CEED2EB00C2B35C /* MyCourseGroupNavView.m */,
+				BC7354982CEED2EB00C2B35C /* MyCourseGroupNavView.xib */,
+				BC7354642CEED28000C2B35C /* AccompanyCourseGroup */,
+				BC73546A2CEED28000C2B35C /* LiveCourseGroup */,
+				BC7354702CEED28000C2B35C /* MusicRoomCourseGroup */,
+				BC7354742CEED28000C2B35C /* MyCourseSortView */,
+				BC73547A2CEED28000C2B35C /* VideoCourseGroup */,
+				BC7354802CEED28000C2B35C /* VIPCourseGroup */,
 				BC119202280ED6A600A716F7 /* MyLessonBodyView.h */,
 				BC119200280ED6A600A716F7 /* MyLessonBodyView.m */,
 				BC119208280ED6A800A716F7 /* MyLessonSearchView.h */,
@@ -5213,6 +5277,76 @@
 			path = TabbarAnimation;
 			sourceTree = "<group>";
 		};
+		BC7354642CEED28000C2B35C /* AccompanyCourseGroup */ = {
+			isa = PBXGroup;
+			children = (
+				BC7354622CEED28000C2B35C /* MyAccompanyCourseGroupView.h */,
+				BC7354632CEED28000C2B35C /* MyAccompanyCourseGroupView.m */,
+			);
+			path = AccompanyCourseGroup;
+			sourceTree = "<group>";
+		};
+		BC73546A2CEED28000C2B35C /* LiveCourseGroup */ = {
+			isa = PBXGroup;
+			children = (
+				BC7354652CEED28000C2B35C /* MyLiveCourseGroupListCell.h */,
+				BC7354662CEED28000C2B35C /* MyLiveCourseGroupListCell.m */,
+				BC7354672CEED28000C2B35C /* MyLiveCourseGroupListCell.xib */,
+				BC7354682CEED28000C2B35C /* MyLiveCourseGroupView.h */,
+				BC7354692CEED28000C2B35C /* MyLiveCourseGroupView.m */,
+			);
+			path = LiveCourseGroup;
+			sourceTree = "<group>";
+		};
+		BC7354702CEED28000C2B35C /* MusicRoomCourseGroup */ = {
+			isa = PBXGroup;
+			children = (
+				BC73546B2CEED28000C2B35C /* MyMusicGroupListCell.h */,
+				BC73546C2CEED28000C2B35C /* MyMusicGroupListCell.m */,
+				BC73546D2CEED28000C2B35C /* MyMusicGroupListCell.xib */,
+				BC73546E2CEED28000C2B35C /* MyMusicRoomCourseGroupView.h */,
+				BC73546F2CEED28000C2B35C /* MyMusicRoomCourseGroupView.m */,
+			);
+			path = MusicRoomCourseGroup;
+			sourceTree = "<group>";
+		};
+		BC7354742CEED28000C2B35C /* MyCourseSortView */ = {
+			isa = PBXGroup;
+			children = (
+				BC7354712CEED28000C2B35C /* MyCourseSearchView.h */,
+				BC7354722CEED28000C2B35C /* MyCourseSearchView.m */,
+				BC7354732CEED28000C2B35C /* MyCourseSearchView.xib */,
+				BC206EE02CEF29A6001F2B85 /* MyCourseRankSortView.h */,
+				BC206EE12CEF29A6001F2B85 /* MyCourseRankSortView.m */,
+				BC206EE22CEF29A6001F2B85 /* MyCourseRankSortView.xib */,
+			);
+			path = MyCourseSortView;
+			sourceTree = "<group>";
+		};
+		BC73547A2CEED28000C2B35C /* VideoCourseGroup */ = {
+			isa = PBXGroup;
+			children = (
+				BC7354752CEED28000C2B35C /* MyVideoCourseGroupView.h */,
+				BC7354762CEED28000C2B35C /* MyVideoCourseGroupView.m */,
+				BC7354772CEED28000C2B35C /* MyVideoGroupListCell.h */,
+				BC7354782CEED28000C2B35C /* MyVideoGroupListCell.m */,
+				BC7354792CEED28000C2B35C /* MyVideoGroupListCell.xib */,
+			);
+			path = VideoCourseGroup;
+			sourceTree = "<group>";
+		};
+		BC7354802CEED28000C2B35C /* VIPCourseGroup */ = {
+			isa = PBXGroup;
+			children = (
+				BC73547B2CEED28000C2B35C /* MyProgramCourseGroupCell.h */,
+				BC73547C2CEED28000C2B35C /* MyProgramCourseGroupCell.m */,
+				BC73547D2CEED28000C2B35C /* MyProgramCourseGroupCell.xib */,
+				BC73547E2CEED28000C2B35C /* MyVipCourseGroupView.h */,
+				BC73547F2CEED28000C2B35C /* MyVipCourseGroupView.m */,
+			);
+			path = VIPCourseGroup;
+			sourceTree = "<group>";
+		};
 		BC802D9F28BC5F650079E350 /* HotMusic */ = {
 			isa = PBXGroup;
 			children = (
@@ -6372,6 +6506,7 @@
 				BCCE95DE2AB0490D00AB6385 /* TenantHomeSubjectListCell.xib in Resources */,
 				BCC583CB28A9EC6400BAB4CF /* cloud_animation_7.png in Resources */,
 				BC71D1052881A2420010F14B /* TencentOpenApi_IOS_Bundle.bundle in Resources */,
+				BC206EE42CEF29A6001F2B85 /* MyCourseRankSortView.xib in Resources */,
 				BC2C1BBF2CEB57A400EDEB97 /* HomeArrangeSortView.xib in Resources */,
 				BC802DBF28BC8E350079E350 /* HomeHotLiveCourseView.xib in Resources */,
 				BC38C45C2AFA095D00ABFCC2 /* MineWorksNavView.xib in Resources */,
@@ -6471,6 +6606,7 @@
 				BCC583C028A9EC6400BAB4CF /* cloud_animation_15.png in Resources */,
 				BC119280280FB10900A716F7 /* AccompanyRemarkCell.xib in Resources */,
 				BCC409012AFCE6B500C60249 /* MusicPublicContentView.xib in Resources */,
+				BC7354992CEED2EB00C2B35C /* MyCourseGroupNavView.xib in Resources */,
 				BC71D271288804CD0010F14B /* img_26.png in Resources */,
 				BC12639F28FF8E7400509E90 /* HomeRecommendMusicView.xib in Resources */,
 				2723B63527F157D500E0B90B /* GroupApplyChooseCell.xib in Resources */,
@@ -6678,6 +6814,11 @@
 				BCECE24C2B3D670500C0D555 /* CourseFileDisplayView.xib in Resources */,
 				BC71D24E288804CD0010F14B /* img_16.png in Resources */,
 				27F9033727E87C8B00C08A19 /* MineNavView.xib in Resources */,
+				BC7354812CEED28000C2B35C /* MyMusicGroupListCell.xib in Resources */,
+				BC7354822CEED28000C2B35C /* MyVideoGroupListCell.xib in Resources */,
+				BC7354832CEED28000C2B35C /* MyLiveCourseGroupListCell.xib in Resources */,
+				BC7354842CEED28000C2B35C /* MyCourseSearchView.xib in Resources */,
+				BC7354852CEED28000C2B35C /* MyProgramCourseGroupCell.xib in Resources */,
 				BC38C4A32AFA4F6C00ABFCC2 /* TenantMineFunctionView.xib in Resources */,
 				BCC0F6B32A8CDD4000C4EFA4 /* low_staff.png in Resources */,
 				BCB9FA47286EDCD7005D766B /* KSTipsAlert.xib in Resources */,
@@ -6906,6 +7047,7 @@
 				BC0D1F752810165500C5D9E5 /* VideoCourseModel.m in Sources */,
 				BC802D9D28BC546B0079E350 /* HomeHotMusicCollectionCell.m in Sources */,
 				BC119276280FB01100A716F7 /* AccompanyHomeworkCell.m in Sources */,
+				BC73549A2CEED2EB00C2B35C /* MyCourseGroupNavView.m in Sources */,
 				BC106C192A933829000759A9 /* TXLiveMessageDownSeat.m in Sources */,
 				BC106C122A933829000759A9 /* TXLiveMessagePauseLive.m in Sources */,
 				BC31BF102B21925700F7D538 /* MetronomeManager.m in Sources */,
@@ -7149,6 +7291,8 @@
 				2779354D27E324A70010E277 /* KSGifRefreshFooter.m in Sources */,
 				BC3300182BBAB623003D4921 /* CoursewareDownloadManager.m in Sources */,
 				BC119288280FB3B100A716F7 /* KSStarView.m in Sources */,
+				BC7354942CEED2AE00C2B35C /* ProgramCourseGroupModel.m in Sources */,
+				BC7354952CEED2AE00C2B35C /* LiveLessonModel.m in Sources */,
 				275FA22F27E7356B00CFEA2E /* ShopMallViewController.m in Sources */,
 				BCB6347227F6D29600ACFDCF /* KSChatInputView.m in Sources */,
 				275E8AAA27E18F8800DD3F6E /* AppDelegate.m in Sources */,
@@ -7158,7 +7302,6 @@
 				BC106C002A933829000759A9 /* TXLiveMessageLike.m in Sources */,
 				2723B5CF27F157BE00E0B90B /* GroupMemberModel.m in Sources */,
 				2723B62A27F157D500E0B90B /* GroupSettingViewController.m in Sources */,
-				BC119222280ED6F500A716F7 /* LiveLessonModel.m in Sources */,
 				BCC0F60C2A8CD86C00C4EFA4 /* TXNodePlayMessage.m in Sources */,
 				2723B63C27F159BA00E0B90B /* KSBaseTableViewController.m in Sources */,
 				BCB9FA2B286D79A4005D766B /* ScanNavView.m in Sources */,
@@ -7312,6 +7455,7 @@
 				BCC0F6062A8CD86C00C4EFA4 /* TXClassroomDisplayMsg.m in Sources */,
 				BC2888752A8101C80064B773 /* KSSearchResultListController.m in Sources */,
 				2723B66D27F15CFC00E0B90B /* ModifyNameBodyView.m in Sources */,
+				BC206EE32CEF29A6001F2B85 /* MyCourseRankSortView.m in Sources */,
 				BC0D95262AC2AA0900E54D3F /* NewPwdModifyViewController.m in Sources */,
 				BC31BF242B21925700F7D538 /* WMGaugeViewStyleFlatThin.m in Sources */,
 				BC9AA0BA2ABC288000CD954D /* ChatComplainBottomView.m in Sources */,
@@ -7352,6 +7496,16 @@
 				2779356927E324A70010E277 /* YKMultiLevelTableView.m in Sources */,
 				BCC0F6522A8CD8F500C4EFA4 /* TXClassroomVideoListCell.m in Sources */,
 				27F9032F27E87C2E00C08A19 /* AudioPlayManager.m in Sources */,
+				BC7354862CEED28000C2B35C /* MyVipCourseGroupView.m in Sources */,
+				BC7354872CEED28000C2B35C /* MyCourseSearchView.m in Sources */,
+				BC7354882CEED28000C2B35C /* MyVideoCourseGroupView.m in Sources */,
+				BC7354892CEED28000C2B35C /* MyLiveCourseGroupListCell.m in Sources */,
+				BC73548A2CEED28000C2B35C /* MyAccompanyCourseGroupView.m in Sources */,
+				BC73548B2CEED28000C2B35C /* MyLiveCourseGroupView.m in Sources */,
+				BC73548C2CEED28000C2B35C /* MyMusicGroupListCell.m in Sources */,
+				BC73548D2CEED28000C2B35C /* MyProgramCourseGroupCell.m in Sources */,
+				BC73548E2CEED28000C2B35C /* MyVideoGroupListCell.m in Sources */,
+				BC73548F2CEED28000C2B35C /* MyMusicRoomCourseGroupView.m in Sources */,
 				BCC0F66A2A8CD8F500C4EFA4 /* TXDanMuView.m in Sources */,
 				BC28885C2A80F9880064B773 /* AppDelegate+AppService.m in Sources */,
 				BC42CAA62BEC8272001F076E /* RhythmChooseView.m in Sources */,

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@3x.png


+ 6 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/live_courseGroup_icon.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "live_courseGroup_icon@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "live_courseGroup_icon@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/live_courseGroup_icon.imageset/live_courseGroup_icon@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/live_courseGroup_icon.imageset/live_courseGroup_icon@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/mine_page_live_tag.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "mine_page_live_tag@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "mine_page_live_tag@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/mine_page_live_tag.imageset/mine_page_live_tag@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/mine_page_live_tag.imageset/mine_page_live_tag@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/myCourse_bg.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "myCourse_bg@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "myCourse_bg@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/myCourse_bg.imageset/myCourse_bg@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/MyCourse/myCourse_bg.imageset/myCourse_bg@3x.png


+ 14 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.h

@@ -1102,6 +1102,20 @@ NS_ASSUME_NONNULL_BEGIN
 /// @param success 成功
 /// @param faliure 失败
 + (void)queryLiveCourseGroupRequest:(NSString *)post search:(NSString *)search subjectId:(NSString *)subjectId page:(NSInteger)page rows:(NSInteger)rows success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
+#pragma mark ---- 我的课程组
+
+// courseGroup/myCourseGroup
+
+/// 我的课程组
+/// @param post post
+/// @param courseType 课程类型 VIP、PRACTICE
+/// @param search 搜索关键字
+/// @param subjectId 声部ID
+/// @param status 课程组状态
+/// @param success 成功
+/// @param faliure 失败
++ (void)myCourseGroupRequest:(NSString *)post courseType:(NSString *)courseType search:(NSString *)search subjectId:(NSString *)subjectId status:(NSString *)status success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
 @end
 
 NS_ASSUME_NONNULL_END

+ 23 - 0
KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.m

@@ -2106,4 +2106,27 @@
     [parm setValue:@(NO) forKey:@"myself"];
     [self request:post andWithUrl:url and:parm success:success faliure:faliure];
 }
+
+#pragma mark ---- 我的课程组
+
+// courseGroup/myCourseGroup
+
+/// 我的课程组
+/// @param post post
+/// @param courseType 课程类型 VIP、PRACTICE
+/// @param search 搜索关键字
+/// @param subjectId 声部ID
+/// @param status 课程组状态
+/// @param success 成功
+/// @param faliure 失败
++ (void)myCourseGroupRequest:(NSString *)post courseType:(NSString *)courseType search:(NSString *)search subjectId:(NSString *)subjectId status:(NSString *)status success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    [self configRequestMethodJSON];
+    NSString *url = [NSString stringWithFormat:@"%@%@",hostURL, @"/api-student/courseGroup/myCourseGroup"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:courseType forKey:@"courseType"];
+    [parm setValue:search forKey:@"search"];
+    [parm setValue:subjectId forKey:@"subjectId"];
+    [parm setValue:status forKey:@"status"];
+    [self request:post andWithUrl:url and:parm success:success faliure:faliure];
+}
 @end

+ 6 - 6
KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -87,9 +87,9 @@
                                 </userDefinedRuntimeAttributes>
                             </view>
                             <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="course_musicRoom" translatesAutoresizingMaskIntoConstraints="NO" id="qgw-qJ-GKe">
-                                <rect key="frame" x="11" y="53" width="47" height="51"/>
+                                <rect key="frame" x="11" y="53" width="47" height="47"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="51" id="6Lb-fR-aUr"/>
+                                    <constraint firstAttribute="height" constant="47" id="6Lb-fR-aUr"/>
                                     <constraint firstAttribute="width" constant="47" id="eIR-Ch-GVU"/>
                                 </constraints>
                             </imageView>
@@ -131,7 +131,7 @@
                             <constraint firstItem="NaF-iy-iW5" firstAttribute="top" secondItem="lZc-0i-RlV" secondAttribute="top" constant="12" id="MOg-56-mCo"/>
                             <constraint firstItem="DZc-wF-kiD" firstAttribute="centerY" secondItem="NaF-iy-iW5" secondAttribute="centerY" id="MWw-Pm-PJF"/>
                             <constraint firstItem="Jid-Tm-C6f" firstAttribute="leading" secondItem="Nc9-wd-2bK" secondAttribute="trailing" constant="8" id="NCl-z1-WpE"/>
-                            <constraint firstAttribute="bottom" secondItem="qgw-qJ-GKe" secondAttribute="bottom" constant="22" id="SSA-Vy-TQu"/>
+                            <constraint firstAttribute="bottom" secondItem="qgw-qJ-GKe" secondAttribute="bottom" constant="26" id="SSA-Vy-TQu"/>
                             <constraint firstItem="09N-Zc-juN" firstAttribute="leading" secondItem="qgw-qJ-GKe" secondAttribute="trailing" constant="10" id="T34-Yi-fep"/>
                             <constraint firstItem="WC4-RO-cvp" firstAttribute="leading" secondItem="09N-Zc-juN" secondAttribute="trailing" id="U8W-aJ-XUT"/>
                             <constraint firstItem="WC4-RO-cvp" firstAttribute="centerY" secondItem="09N-Zc-juN" secondAttribute="centerY" id="Zg5-sn-kjb"/>
@@ -178,7 +178,7 @@
     </objects>
     <resources>
         <image name="course_chat" width="19" height="18"/>
-        <image name="course_musicRoom" width="47" height="51"/>
+        <image name="course_musicRoom" width="40" height="40"/>
         <image name="course_time" width="16" height="16"/>
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>

+ 5 - 5
KulexiuForStudent/KulexiuForStudent/Module/Course/View/MusicRoomCourseCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -100,9 +100,9 @@
                                 </userDefinedRuntimeAttributes>
                             </button>
                             <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="course_musicRoom" translatesAutoresizingMaskIntoConstraints="NO" id="KUE-40-5Jn">
-                                <rect key="frame" x="11" y="55" width="47" height="51"/>
+                                <rect key="frame" x="11" y="55" width="47" height="47"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="51" id="S6z-NU-xg3"/>
+                                    <constraint firstAttribute="height" constant="47" id="S6z-NU-xg3"/>
                                     <constraint firstAttribute="width" constant="47" id="c6q-Yc-a17"/>
                                 </constraints>
                             </imageView>
@@ -200,7 +200,7 @@
     </objects>
     <resources>
         <image name="course_chat" width="19" height="18"/>
-        <image name="course_musicRoom" width="47" height="51"/>
+        <image name="course_musicRoom" width="40" height="40"/>
         <image name="course_time" width="16" height="16"/>
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/Controller/HomeArrangeCourseController.m

@@ -105,7 +105,7 @@
 }
 
 - (void)requestSubjectList {
-    [KSNetworkingManager querySubjectItemRequest:KS_POST success:^(NSDictionary * _Nonnull dic) {
+    [KSNetworkingManager subjectQueryPageRequest:KS_GET success:^(NSDictionary * _Nonnull dic) {
         if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
             NSArray *subjectArray = [dic ks_arrayValueForKey:@"data"];
             NSMutableArray *subjectParmArray = [NSMutableArray array];

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/CourseTeacherDescCell.m

@@ -39,7 +39,7 @@
 
 
 - (void)configWithSource:(ArrangeTeacherModel *)model {
-    self.teacherName.text = [NSString returnNoNullStringWithString:model.realName];
+    self.teacherName.text = [NSString returnNoNullStringWithString:model.userName];
     [self.teacherAvatar sd_setImageWithURL:[NSURL URLWithString:[model.avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:TEACHER_AVATAR]];
     self.teacherDesc.text = [NSString stringWithFormat:@"%@·%@",[NSString returnNoNullStringWithString:model.school], [NSString returnNoNullStringWithString:model.schoolSubject]];
     double starNum = [model.starGrade doubleValue];

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/HomeArrangeAccompanyCourseView.m

@@ -277,6 +277,7 @@
 - (HomeArrangeRankView *)rankView {
     if (!_rankView) {
         _rankView = [HomeArrangeRankView sharedInstance];
+        _rankView.hidePriceSort = YES;
         [_rankView configUI];
         MJWeakSelf;
         [_rankView sortAction:^(BOOL recentFree, NSString * _Nullable sortField, NSString * _Nullable sortRole) {

+ 2 - 0
KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/HomeArrangeRankView.h

@@ -13,6 +13,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 @interface HomeArrangeRankView : UIView
 
+@property (nonatomic, assign) BOOL hidePriceSort;
+
 + (instancetype)sharedInstance;
 
 - (void)configUI;

+ 25 - 16
KulexiuForStudent/KulexiuForStudent/Module/Home/ArrangeCourse/View/HomeArrangeRankView.m

@@ -48,8 +48,9 @@ typedef NS_ENUM(NSInteger, RANK_BUTTON_TYPE) {
 }
 
 - (void)configUI {
-    CGFloat phoneSpace = (KPortraitWidth - 111 - 74 * 2 - 58 - ARR_LEFT_SPACE * 2) / 3.0f;
-    CGFloat space = IS_IPAD ? ARR_BUTTON_SPACE : phoneSpace;
+//    CGFloat phoneSpace = (KPortraitWidth - 111 - 74 * 2 - 58 - ARR_LEFT_SPACE * 2) / 3.0f;
+//    CGFloat space = IS_IPAD ? ARR_BUTTON_SPACE : phoneSpace;
+    CGFloat space = ARR_BUTTON_SPACE;
     [self.buttonContainer addSubview:self.recentButton];
     [self.recentButton mas_makeConstraints:^(MASConstraintMaker *make) {
         make.left.mas_equalTo(self.buttonContainer.mas_left).offset(ARR_LEFT_SPACE);
@@ -63,20 +64,28 @@ typedef NS_ENUM(NSInteger, RANK_BUTTON_TYPE) {
         make.top.bottom.mas_equalTo(self.buttonContainer);
         make.width.mas_equalTo(74.0f);
     }];
-    
-    [self.buttonContainer addSubview:self.priceButton];
-    [self.priceButton mas_makeConstraints:^(MASConstraintMaker *make) {
-        make.left.mas_equalTo(self.finishButton.mas_right).offset(space);
-        make.top.bottom.mas_equalTo(self.buttonContainer);
-        make.width.mas_equalTo(74.0f);
-    }];
-    
-    [self.buttonContainer addSubview:self.scoreButton];
-    [self.scoreButton mas_makeConstraints:^(MASConstraintMaker *make) {
-        make.left.mas_equalTo(self.priceButton.mas_right).offset(space);
-        make.top.bottom.mas_equalTo(self.buttonContainer);
-        make.width.mas_equalTo(58.0f);
-    }];
+    if (self.hidePriceSort == NO) {
+        [self.buttonContainer addSubview:self.priceButton];
+        [self.priceButton mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.mas_equalTo(self.finishButton.mas_right).offset(space);
+            make.top.bottom.mas_equalTo(self.buttonContainer);
+            make.width.mas_equalTo(74.0f);
+        }];
+        [self.buttonContainer addSubview:self.scoreButton];
+        [self.scoreButton mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.mas_equalTo(self.priceButton.mas_right).offset(space);
+            make.top.bottom.mas_equalTo(self.buttonContainer);
+            make.width.mas_equalTo(58.0f);
+        }];
+    }
+    else {
+        [self.buttonContainer addSubview:self.scoreButton];
+        [self.scoreButton mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.mas_equalTo(self.finishButton.mas_right).offset(space);
+            make.top.bottom.mas_equalTo(self.buttonContainer);
+            make.width.mas_equalTo(58.0f);
+        }];
+    }
 }
 
 - (void)sortAction:(ArrangeRankCallback)callback {

+ 2 - 1
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Controller/MyCourseViewController.h

@@ -11,7 +11,8 @@
 
 
 typedef NS_ENUM(NSInteger, DISPLAY_INDEX) {
-    DISPLAY_INDEX_FIRST = 0,  // 陪练课
+    DISPLAY_INDEX_VIP = 0,    // VIP定制
+    DISPLAY_INDEX_FIRST,  // 陪练课
     DISPLAY_INDEX_LIVE,       // 直播课
     DISPLAY_INDEX_VIEO,       // 视频课
     DISPLAY_INDEX_MUSIC,      // 琴房课

+ 149 - 37
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Controller/MyCourseViewController.m

@@ -6,16 +6,27 @@
 //
 
 #import "MyCourseViewController.h"
-#import "MyLessonBodyView.h"
-#import "MyVideoCourseBodyView.h"
+
 #import "JXCategoryView.h"
 #import "JXPagerListRefreshView.h"
 #import "UserInfoManager.h"
 
-#define HEADER_HEIGHT (50)
+#import "MyCourseGroupNavView.h"
+
+#import "MyVipCourseGroupView.h"
+#import "MyAccompanyCourseGroupView.h"
+#import "MyLiveCourseGroupView.h"
+#import "MyVideoCourseGroupView.h"
+#import "MyMusicRoomCourseGroupView.h"
+
+#import "CourseDescAlertView.h"
+
+#define HEADER_HEIGHT (44)
 
 @interface MyCourseViewController ()<JXPagerViewDelegate, JXPagerMainTableViewGestureDelegate,JXCategoryViewDelegate>
 
+@property (nonatomic, strong) MyCourseGroupNavView *navView;
+
 @property (nonatomic, assign) NSInteger selectedIndex;
 
 @property (nonatomic, strong) NSMutableArray *listViewArray;
@@ -24,6 +35,8 @@
 
 @property (nonatomic, assign) DISPLAY_INDEX displayIndex;
 
+@property (nonatomic, strong) CourseDescAlertView *tipsAlert;
+
 @end
 
 @implementation MyCourseViewController
@@ -31,8 +44,8 @@
 - (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
-    [self allocTitle:@"我的课程"];
-    self.titles = @[@"陪练课",@"直播课",@"视频课",@"琴房课"];
+    self.ks_prefersNavigationBarHidden = YES;
+    
     [self configUI];
     [self countUMEvent];
 }
@@ -44,25 +57,42 @@
 - (void)configUI {
     [self.scrollView removeFromSuperview];
     self.view.backgroundColor = HexRGB(0xf6f8f9);
+    UIImage *bgImage = [UIImage imageNamed:@"myCourse_bg"];
+    NSInteger height = (NSInteger)(bgImage.size.height / bgImage.size.width * KPortraitWidth);
+    UIImageView *imageView = [[UIImageView alloc] initWithImage:bgImage];
+    imageView.frame = CGRectMake(0, 0, KPortraitWidth, height);
+    [self.view addSubview:imageView];
     
-    _categoryView = [[JXCategoryTitleView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, HEADER_HEIGHT)];
+    [self.view addSubview:self.navView];
+    CGFloat navHeight = [MyCourseGroupNavView getViewHeight];
+    [self.navView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.mas_equalTo(self.view);
+        make.height.mas_equalTo(navHeight);
+    }];
+    
+    self.titles = @[@"VIP定制课", @"趣纠课", @"直播课",@"视频课",@"琴房课"];
+    [self configCategoryView:navHeight];
+}
+
+- (void)configCategoryView:(NSInteger)topHeight {
+    
+    _categoryView = [[JXCategoryTitleView alloc] initWithFrame:CGRectMake(0, topHeight, KPortraitWidth, HEADER_HEIGHT)];
     self.categoryView.titles = self.titles;
     self.categoryView.delegate = self;
-    self.categoryView.titleFont = [UIFont systemFontOfSize:17.0f];
-    self.categoryView.titleSelectedFont = [UIFont systemFontOfSize:17.0f weight:UIFontWeightMedium];
+    self.categoryView.titleFont = [UIFont systemFontOfSize:16.0f];
+    self.categoryView.titleSelectedFont = [UIFont systemFontOfSize:16.0f weight:UIFontWeightSemibold];
     self.categoryView.titleSelectedColor = HexRGB(0x333333);
     self.categoryView.titleColor = HexRGB(0x666666);
     self.categoryView.titleColorGradientEnabled = YES;
-    self.categoryView.backgroundColor = [UIColor whiteColor];
     
     JXCategoryIndicatorLineView *lineView = [[JXCategoryIndicatorLineView alloc] init];
-    lineView.indicatorColor = THEMECOLOR;
     lineView.indicatorHeight = 4.0f;
-    lineView.indicatorWidth = 28;
+    lineView.indicatorColor = THEMECOLOR;
+    lineView.indicatorWidth = 16;
     self.categoryView.indicators = @[lineView];
     
     _pagerView = [self preferredPagingView];
-    self.pagerView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight - kNaviBarHeight - iPhoneXSafeBottomMargin);
+    self.pagerView.frame = CGRectMake(0, topHeight, KPortraitWidth, KPortraitHeight - topHeight);
     self.pagerView.backgroundColor = [UIColor clearColor];
     self.pagerView.mainTableView.backgroundColor = [UIColor clearColor];
     self.pagerView.listContainerView.backgroundColor = [UIColor clearColor];
@@ -83,17 +113,6 @@
     [super viewWillAppear:animated];
     self.navigationController.interactivePopGestureRecognizer.enabled = YES;
     [self requestSubjectList];
-    if (self.listViewArray.count > self.categoryView.selectedIndex) {
-        id value = self.listViewArray[self.categoryView.selectedIndex];
-        if ([value isKindOfClass:[MyVideoCourseBodyView class]]) {
-            MyVideoCourseBodyView *listView = (MyVideoCourseBodyView *)value;
-            [listView beginFirstRefresh];
-        }
-        else if ([value isKindOfClass:[MyLessonBodyView class]]) {
-            MyLessonBodyView *listView = (MyLessonBodyView *)value;
-            [listView beginFirstRefresh];
-        }
-    }
 }
 
 - (void)requestSubjectList {
@@ -104,8 +123,8 @@
             NSMutableArray *subjectArray = [NSMutableArray array];
             for (NSDictionary *parm in dataArray) {
                 NSMutableDictionary *subjectSource = [NSMutableDictionary dictionary];
-                [subjectSource setValue:[parm ks_stringValueForKey:@"id"] forKey:@"subjectId"];
-                [subjectSource setValue:[parm ks_stringValueForKey:@"name"] forKey:@"subjectName"];
+                [subjectSource setValue:[parm ks_stringValueForKey:@"id"] forKey:@"id"];
+                [subjectSource setValue:[parm ks_stringValueForKey:@"name"] forKey:@"name"];
                 [subjectArray addObject:subjectSource];
             }
             self.subjectList = [subjectArray mutableCopy];
@@ -122,13 +141,25 @@
 - (void)refreshSubjectMessage {
     for (NSInteger index = 0; index < self.listViewArray.count; index++) {
         id view = self.listViewArray[index];
-        if ([view isKindOfClass:[MyLessonBodyView class]]) {
-            MyLessonBodyView *courseView = (MyLessonBodyView *)view;
-            courseView.subjectList = [self.subjectList mutableCopy];
+        if ([view isKindOfClass:[MyVipCourseGroupView class]]) {
+            MyVipCourseGroupView *pageView = (MyVipCourseGroupView *)view;
+            pageView.subjectList = [self.subjectList mutableCopy];
         }
-        else if ([view isKindOfClass:[MyVideoCourseBodyView class]]) {
-            MyVideoCourseBodyView *videoCourseView = (MyVideoCourseBodyView *)view;
-            videoCourseView.subjectList = [self.subjectList mutableCopy];
+        else if ([view isKindOfClass:[MyAccompanyCourseGroupView class]]) {
+            MyAccompanyCourseGroupView *pageView = (MyAccompanyCourseGroupView *)view;
+            pageView.subjectList = [self.subjectList mutableCopy];
+        }
+        else if ([view isKindOfClass:[MyLiveCourseGroupView class]]) {
+            MyLiveCourseGroupView *pageView = (MyLiveCourseGroupView *)view;
+            pageView.subjectList = [self.subjectList mutableCopy];
+        }
+        else if ([view isKindOfClass:[MyVideoCourseGroupView class]]) {
+            MyVideoCourseGroupView *pageView = (MyVideoCourseGroupView *)view;
+            pageView.subjectList = [self.subjectList mutableCopy];
+        }
+        else if ([view isKindOfClass:[MyMusicRoomCourseGroupView class]]) {
+            MyMusicRoomCourseGroupView *pageView = (MyMusicRoomCourseGroupView *)view;
+            pageView.subjectList = [self.subjectList mutableCopy];
         }
     }
 }
@@ -166,8 +197,8 @@
 }
 
 - (id<JXPagerViewListViewDelegate>)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index {
-    if (index == 2) {
-        MyVideoCourseBodyView *listView = [[MyVideoCourseBodyView alloc] init];
+    if (index == 0) {
+        MyVipCourseGroupView *listView = [[MyVipCourseGroupView alloc] init];
         listView.naviController = self.navigationController;
         [self.listViewArray replaceObjectAtIndex:index withObject:listView];
         self.listViewArray[index] = listView;
@@ -178,8 +209,44 @@
         [listView beginFirstRefresh];
         return listView;
     }
-    else {
-        MyLessonBodyView *listView = [[MyLessonBodyView alloc] init];
+    else if (index == 1) {
+        MyAccompanyCourseGroupView *listView = [[MyAccompanyCourseGroupView alloc] init];
+        listView.naviController = self.navigationController;
+        [self.listViewArray replaceObjectAtIndex:index withObject:listView];
+        self.listViewArray[index] = listView;
+        listView.selectIndex = index;
+        if (self.subjectList) {
+            listView.subjectList = [self.subjectList mutableCopy];
+        }
+        [listView beginFirstRefresh];
+        return listView;
+    }
+    else if (index == 2) {
+        MyLiveCourseGroupView *listView = [[MyLiveCourseGroupView alloc] init];
+        listView.naviController = self.navigationController;
+        [self.listViewArray replaceObjectAtIndex:index withObject:listView];
+        self.listViewArray[index] = listView;
+        listView.selectIndex = index;
+        if (self.subjectList) {
+            listView.subjectList = [self.subjectList mutableCopy];
+        }
+        [listView beginFirstRefresh];
+        return listView;
+    }
+    else if (index == 3) {
+        MyVideoCourseGroupView *listView = [[MyVideoCourseGroupView alloc] init];
+        listView.naviController = self.navigationController;
+        [self.listViewArray replaceObjectAtIndex:index withObject:listView];
+        self.listViewArray[index] = listView;
+        listView.selectIndex = index;
+        if (self.subjectList) {
+            listView.subjectList = [self.subjectList mutableCopy];
+        }
+        [listView beginFirstRefresh];
+        return listView;
+    }
+    else { // 琴房课
+        MyMusicRoomCourseGroupView *listView = [[MyMusicRoomCourseGroupView alloc] init];
         listView.naviController = self.navigationController;
         [self.listViewArray replaceObjectAtIndex:index withObject:listView];
         self.listViewArray[index] = listView;
@@ -190,12 +257,22 @@
         [listView beginFirstRefresh];
         return listView;
     }
-    
 }
 
 #pragma mark - JXCategoryViewDelegate
 - (void)categoryView:(JXCategoryBaseView *)categoryView didSelectedItemAtIndex:(NSInteger)index {
     self.navigationController.interactivePopGestureRecognizer.enabled = (index == 0);
+    if (self.listViewArray.count > index) {
+        id value = self.listViewArray[index];
+        if ([value isKindOfClass:[KSJXBodyView class]]) {
+            KSJXBodyView *listView = (KSJXBodyView *)value;
+            [listView beginFirstRefresh];
+        }
+        else if ([value isKindOfClass:[kSJXCollectionView class]]) {
+            kSJXCollectionView *listView = (kSJXCollectionView *)value;
+            [listView beginFirstRefresh];
+        }
+    }
 }
 
 
@@ -210,9 +287,44 @@
 }
 
 
+#pragma mark ----- lazying
+- (MyCourseGroupNavView *)navView {
+    if (!_navView) {
+        _navView = [MyCourseGroupNavView sharedInstance];
+        MJWeakSelf;
+        [_navView navAction:^(BOOL isBack) {
+            [weakSelf myNavAction:isBack];
+        }];
+
+    }
+    return _navView;
+}
+
+- (void)myNavAction:(BOOL)isBack {
+    if (isBack) {
+        [self backAction];
+    }
+    else {
+        [self showTipsAlert:self.categoryView.selectedIndex];
+    }
+}
+
+- (void)showTipsAlert:(NSInteger)displayIndex {
+    [self.tipsAlert displayCourseTypeIndex:displayIndex];
+    [self.tipsAlert showInView:[NSObject getKeyWindow]];
+}
+
+- (CourseDescAlertView *)tipsAlert {
+    if (!_tipsAlert) {
+        _tipsAlert = [CourseDescAlertView sharedInstance];
+        [_tipsAlert refreshView];
+    }
+    return _tipsAlert;
+}
+
 - (NSMutableArray *)listViewArray {
     if (!_listViewArray) {
-        _listViewArray = [NSMutableArray arrayWithArray:@[@"",@"",@"",@""]];
+        _listViewArray = [NSMutableArray arrayWithArray:@[@"",@"",@"",@"",@""]];
     }
     return _listViewArray;
 }

+ 19 - 12
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/LiveLessonModel.h

@@ -1,8 +1,8 @@
 //
 //  LiveLessonModel.h
 //
-//  Created by Steven  on 2022/5/10
-//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//  Created by Steven  on 2024/11/21
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
 //
 
 #import <Foundation/Foundation.h>
@@ -11,22 +11,29 @@
 
 @interface LiveLessonModel : NSObject <NSCoding, NSCopying>
 
-@property (nonatomic, strong) NSString *classDate;
-@property (nonatomic, strong) NSString *name;
+@property (nonatomic, strong) NSString *payCount;
+@property (nonatomic, strong) NSString *courseIntroduce;
+@property (nonatomic, strong) NSString *status;
+@property (nonatomic, strong) NSString *imUserId;
+@property (nonatomic, strong) NSString *courseGoupId;
 @property (nonatomic, strong) NSString *realName;
+@property (nonatomic, strong) NSString *endTime;
+@property (nonatomic, strong) NSString *cover;
+@property (nonatomic, assign) double studentReplied;
+@property (nonatomic, assign) double teacherReplied;
 @property (nonatomic, strong) NSString *imGroupId;
+@property (nonatomic, strong) NSString *subjectName;
+@property (nonatomic, strong) NSString *name;
+@property (nonatomic, strong) NSString *courseName;
+@property (nonatomic, strong) NSString *courseType;
 @property (nonatomic, strong) NSString *subjectId;
 @property (nonatomic, strong) NSString *courseId;
-@property (nonatomic, strong) NSString *userId;
 @property (nonatomic, strong) NSString *avatar;
-@property (nonatomic, strong) NSString *endTime;
-@property (nonatomic, strong) NSString *subjectName;
-@property (nonatomic, strong) NSString *cover;
-@property (nonatomic, strong) NSString *courseGoupId;
-@property (nonatomic, strong) NSString *payCount;
+@property (nonatomic, strong) NSString *classDate;
 @property (nonatomic, strong) NSString *startTime;
-@property (nonatomic, strong) NSString *status;
-@property (nonatomic, strong) NSString *courseType;
+@property (nonatomic, strong) NSString *userId;
+@property (nonatomic, assign) NSInteger courseNum;
+@property (nonatomic, assign) NSInteger completeCourseNum;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
 - (instancetype)initWithDictionary:(NSDictionary *)dict;

+ 121 - 75
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/LiveLessonModel.m

@@ -1,30 +1,36 @@
 //
 //  LiveLessonModel.m
 //
-//  Created by Steven  on 2022/5/10
-//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//  Created by Steven  on 2024/11/21
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
 //
 
 #import "LiveLessonModel.h"
 
 
-NSString *const kLiveLessonModelClassDate = @"classDate";
-NSString *const kLiveLessonModelName = @"name";
+NSString *const kLiveLessonModelPayCount = @"payCount";
+NSString *const kLiveLessonModelCourseIntroduce = @"courseIntroduce";
+NSString *const kLiveLessonModelStatus = @"status";
+NSString *const kLiveLessonModelImUserId = @"imUserId";
+NSString *const kLiveLessonModelCourseGoupId = @"courseGoupId";
 NSString *const kLiveLessonModelRealName = @"realName";
+NSString *const kLiveLessonModelEndTime = @"endTime";
+NSString *const kLiveLessonModelCover = @"cover";
+NSString *const kLiveLessonModelStudentReplied = @"studentReplied";
+NSString *const kLiveLessonModelTeacherReplied = @"teacherReplied";
 NSString *const kLiveLessonModelImGroupId = @"imGroupId";
+NSString *const kLiveLessonModelSubjectName = @"subjectName";
+NSString *const kLiveLessonModelName = @"name";
+NSString *const kLiveLessonModelCourseName = @"courseName";
+NSString *const kLiveLessonModelCourseType = @"courseType";
 NSString *const kLiveLessonModelSubjectId = @"subjectId";
 NSString *const kLiveLessonModelCourseId = @"courseId";
-NSString *const kLiveLessonModelUserId = @"userId";
 NSString *const kLiveLessonModelAvatar = @"avatar";
-NSString *const kLiveLessonModelEndTime = @"endTime";
-NSString *const kLiveLessonModelSubjectName = @"subjectName";
-NSString *const kLiveLessonModelCover = @"cover";
-NSString *const kLiveLessonModelCourseGoupId = @"courseGoupId";
-NSString *const kLiveLessonModelPayCount = @"payCount";
+NSString *const kLiveLessonModelClassDate = @"classDate";
 NSString *const kLiveLessonModelStartTime = @"startTime";
-NSString *const kLiveLessonModelStatus = @"status";
-NSString *const kLiveLessonModelCourseType = @"courseType";
-
+NSString *const kLiveLessonModelUserId = @"userId";
+NSString *const kLiveLessonModelCourseNum = @"courseNum";
+NSString *const kLiveLessonModelCompleteCourseNum = @"completeCourseNum";
 
 @interface LiveLessonModel ()
 
@@ -34,23 +40,29 @@ NSString *const kLiveLessonModelCourseType = @"courseType";
 
 @implementation LiveLessonModel
 
-@synthesize classDate = _classDate;
-@synthesize name = _name;
+@synthesize payCount = _payCount;
+@synthesize courseIntroduce = _courseIntroduce;
+@synthesize status = _status;
+@synthesize imUserId = _imUserId;
+@synthesize courseGoupId = _courseGoupId;
 @synthesize realName = _realName;
+@synthesize endTime = _endTime;
+@synthesize cover = _cover;
+@synthesize studentReplied = _studentReplied;
+@synthesize teacherReplied = _teacherReplied;
 @synthesize imGroupId = _imGroupId;
+@synthesize subjectName = _subjectName;
+@synthesize name = _name;
+@synthesize courseName = _courseName;
+@synthesize courseType = _courseType;
 @synthesize subjectId = _subjectId;
 @synthesize courseId = _courseId;
-@synthesize userId = _userId;
 @synthesize avatar = _avatar;
-@synthesize endTime = _endTime;
-@synthesize subjectName = _subjectName;
-@synthesize cover = _cover;
-@synthesize courseGoupId = _courseGoupId;
-@synthesize payCount = _payCount;
+@synthesize classDate = _classDate;
 @synthesize startTime = _startTime;
-@synthesize status = _status;
-@synthesize courseType = _courseType;
-
+@synthesize userId = _userId;
+@synthesize courseNum = _courseNum;
+@synthesize completeCourseNum = _completeCourseNum;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
 {
@@ -64,22 +76,29 @@ NSString *const kLiveLessonModelCourseType = @"courseType";
     // This check serves to make sure that a non-NSDictionary object
     // passed into the model class doesn't break the parsing.
     if(self && [dict isKindOfClass:[NSDictionary class]]) {
-            self.classDate = [self objectOrNilForKey:kLiveLessonModelClassDate fromDictionary:dict];
-            self.name = [self objectOrNilForKey:kLiveLessonModelName fromDictionary:dict];
+            self.payCount = [self objectOrNilForKey:kLiveLessonModelPayCount fromDictionary:dict];
+            self.courseIntroduce = [self objectOrNilForKey:kLiveLessonModelCourseIntroduce fromDictionary:dict];
+            self.status = [self objectOrNilForKey:kLiveLessonModelStatus fromDictionary:dict];
+            self.imUserId = [self objectOrNilForKey:kLiveLessonModelImUserId fromDictionary:dict];
+            self.courseGoupId = [self objectOrNilForKey:kLiveLessonModelCourseGoupId fromDictionary:dict];
             self.realName = [self objectOrNilForKey:kLiveLessonModelRealName fromDictionary:dict];
+            self.endTime = [self objectOrNilForKey:kLiveLessonModelEndTime fromDictionary:dict];
+            self.cover = [self objectOrNilForKey:kLiveLessonModelCover fromDictionary:dict];
+            self.studentReplied = [[self objectOrNilForKey:kLiveLessonModelStudentReplied fromDictionary:dict] doubleValue];
+            self.teacherReplied = [[self objectOrNilForKey:kLiveLessonModelTeacherReplied fromDictionary:dict] doubleValue];
             self.imGroupId = [self objectOrNilForKey:kLiveLessonModelImGroupId fromDictionary:dict];
+            self.subjectName = [self objectOrNilForKey:kLiveLessonModelSubjectName fromDictionary:dict];
+            self.name = [self objectOrNilForKey:kLiveLessonModelName fromDictionary:dict];
+            self.courseName = [self objectOrNilForKey:kLiveLessonModelCourseName fromDictionary:dict];
+            self.courseType = [self objectOrNilForKey:kLiveLessonModelCourseType fromDictionary:dict];
             self.subjectId = [self objectOrNilForKey:kLiveLessonModelSubjectId fromDictionary:dict];
             self.courseId = [self objectOrNilForKey:kLiveLessonModelCourseId fromDictionary:dict];
-            self.userId = [self objectOrNilForKey:kLiveLessonModelUserId fromDictionary:dict];
             self.avatar = [self objectOrNilForKey:kLiveLessonModelAvatar fromDictionary:dict];
-            self.endTime = [self objectOrNilForKey:kLiveLessonModelEndTime fromDictionary:dict];
-            self.subjectName = [self objectOrNilForKey:kLiveLessonModelSubjectName fromDictionary:dict];
-            self.cover = [self objectOrNilForKey:kLiveLessonModelCover fromDictionary:dict];
-            self.courseGoupId = [self objectOrNilForKey:kLiveLessonModelCourseGoupId fromDictionary:dict];
-            self.payCount = [self objectOrNilForKey:kLiveLessonModelPayCount fromDictionary:dict];
+            self.classDate = [self objectOrNilForKey:kLiveLessonModelClassDate fromDictionary:dict];
             self.startTime = [self objectOrNilForKey:kLiveLessonModelStartTime fromDictionary:dict];
-            self.status = [self objectOrNilForKey:kLiveLessonModelStatus fromDictionary:dict];
-            self.courseType = [self objectOrNilForKey:kLiveLessonModelCourseType fromDictionary:dict];
+            self.userId = [self objectOrNilForKey:kLiveLessonModelUserId fromDictionary:dict];
+        self.courseNum = [[self objectOrNilForKey:kLiveLessonModelCourseNum fromDictionary:dict] integerValue];
+        self.completeCourseNum = [[self objectOrNilForKey:kLiveLessonModelCompleteCourseNum fromDictionary:dict] integerValue];
 
     }
     
@@ -90,23 +109,29 @@ NSString *const kLiveLessonModelCourseType = @"courseType";
 - (NSDictionary *)dictionaryRepresentation
 {
     NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
-    [mutableDict setValue:self.classDate forKey:kLiveLessonModelClassDate];
-    [mutableDict setValue:self.name forKey:kLiveLessonModelName];
+    [mutableDict setValue:self.payCount forKey:kLiveLessonModelPayCount];
+    [mutableDict setValue:self.courseIntroduce forKey:kLiveLessonModelCourseIntroduce];
+    [mutableDict setValue:self.status forKey:kLiveLessonModelStatus];
+    [mutableDict setValue:self.imUserId forKey:kLiveLessonModelImUserId];
+    [mutableDict setValue:self.courseGoupId forKey:kLiveLessonModelCourseGoupId];
     [mutableDict setValue:self.realName forKey:kLiveLessonModelRealName];
+    [mutableDict setValue:self.endTime forKey:kLiveLessonModelEndTime];
+    [mutableDict setValue:self.cover forKey:kLiveLessonModelCover];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.studentReplied] forKey:kLiveLessonModelStudentReplied];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.teacherReplied] forKey:kLiveLessonModelTeacherReplied];
     [mutableDict setValue:self.imGroupId forKey:kLiveLessonModelImGroupId];
+    [mutableDict setValue:self.subjectName forKey:kLiveLessonModelSubjectName];
+    [mutableDict setValue:self.name forKey:kLiveLessonModelName];
+    [mutableDict setValue:self.courseName forKey:kLiveLessonModelCourseName];
+    [mutableDict setValue:self.courseType forKey:kLiveLessonModelCourseType];
     [mutableDict setValue:self.subjectId forKey:kLiveLessonModelSubjectId];
     [mutableDict setValue:self.courseId forKey:kLiveLessonModelCourseId];
-    [mutableDict setValue:self.userId forKey:kLiveLessonModelUserId];
     [mutableDict setValue:self.avatar forKey:kLiveLessonModelAvatar];
-    [mutableDict setValue:self.endTime forKey:kLiveLessonModelEndTime];
-    [mutableDict setValue:self.subjectName forKey:kLiveLessonModelSubjectName];
-    [mutableDict setValue:self.cover forKey:kLiveLessonModelCover];
-    [mutableDict setValue:self.courseGoupId forKey:kLiveLessonModelCourseGoupId];
-    [mutableDict setValue:self.payCount forKey:kLiveLessonModelPayCount];
+    [mutableDict setValue:self.classDate forKey:kLiveLessonModelClassDate];
     [mutableDict setValue:self.startTime forKey:kLiveLessonModelStartTime];
-    [mutableDict setValue:self.status forKey:kLiveLessonModelStatus];
-    [mutableDict setValue:self.courseType forKey:kLiveLessonModelCourseType];
-
+    [mutableDict setValue:self.userId forKey:kLiveLessonModelUserId];
+    [mutableDict setValue:[NSNumber numberWithInteger:self.courseNum] forKey:kLiveLessonModelCourseNum];
+    [mutableDict setValue:[NSNumber numberWithInteger:self.completeCourseNum] forKey:kLiveLessonModelCompleteCourseNum];
     return [NSDictionary dictionaryWithDictionary:mutableDict];
 }
 
@@ -133,44 +158,58 @@ NSString *const kLiveLessonModelCourseType = @"courseType";
 {
     self = [super init];
 
-    self.classDate = [aDecoder decodeObjectForKey:kLiveLessonModelClassDate];
-    self.name = [aDecoder decodeObjectForKey:kLiveLessonModelName];
+    self.payCount = [aDecoder decodeObjectForKey:kLiveLessonModelPayCount];
+    self.courseIntroduce = [aDecoder decodeObjectForKey:kLiveLessonModelCourseIntroduce];
+    self.status = [aDecoder decodeObjectForKey:kLiveLessonModelStatus];
+    self.imUserId = [aDecoder decodeObjectForKey:kLiveLessonModelImUserId];
+    self.courseGoupId = [aDecoder decodeObjectForKey:kLiveLessonModelCourseGoupId];
     self.realName = [aDecoder decodeObjectForKey:kLiveLessonModelRealName];
+    self.endTime = [aDecoder decodeObjectForKey:kLiveLessonModelEndTime];
+    self.cover = [aDecoder decodeObjectForKey:kLiveLessonModelCover];
+    self.studentReplied = [aDecoder decodeDoubleForKey:kLiveLessonModelStudentReplied];
+    self.teacherReplied = [aDecoder decodeDoubleForKey:kLiveLessonModelTeacherReplied];
     self.imGroupId = [aDecoder decodeObjectForKey:kLiveLessonModelImGroupId];
+    self.subjectName = [aDecoder decodeObjectForKey:kLiveLessonModelSubjectName];
+    self.name = [aDecoder decodeObjectForKey:kLiveLessonModelName];
+    self.courseName = [aDecoder decodeObjectForKey:kLiveLessonModelCourseName];
+    self.courseType = [aDecoder decodeObjectForKey:kLiveLessonModelCourseType];
     self.subjectId = [aDecoder decodeObjectForKey:kLiveLessonModelSubjectId];
     self.courseId = [aDecoder decodeObjectForKey:kLiveLessonModelCourseId];
-    self.userId = [aDecoder decodeObjectForKey:kLiveLessonModelUserId];
     self.avatar = [aDecoder decodeObjectForKey:kLiveLessonModelAvatar];
-    self.endTime = [aDecoder decodeObjectForKey:kLiveLessonModelEndTime];
-    self.subjectName = [aDecoder decodeObjectForKey:kLiveLessonModelSubjectName];
-    self.cover = [aDecoder decodeObjectForKey:kLiveLessonModelCover];
-    self.courseGoupId = [aDecoder decodeObjectForKey:kLiveLessonModelCourseGoupId];
-    self.payCount = [aDecoder decodeObjectForKey:kLiveLessonModelPayCount];
+    self.classDate = [aDecoder decodeObjectForKey:kLiveLessonModelClassDate];
     self.startTime = [aDecoder decodeObjectForKey:kLiveLessonModelStartTime];
-    self.status = [aDecoder decodeObjectForKey:kLiveLessonModelStatus];
-    self.courseType = [aDecoder decodeObjectForKey:kLiveLessonModelCourseType];
+    self.userId = [aDecoder decodeObjectForKey:kLiveLessonModelUserId];
+    self.courseNum = [aDecoder decodeIntegerForKey:kLiveLessonModelCourseNum];
+    self.completeCourseNum = [aDecoder decodeIntegerForKey:kLiveLessonModelCompleteCourseNum];
     return self;
 }
 
 - (void)encodeWithCoder:(NSCoder *)aCoder
 {
 
-    [aCoder encodeObject:_classDate forKey:kLiveLessonModelClassDate];
-    [aCoder encodeObject:_name forKey:kLiveLessonModelName];
+    [aCoder encodeObject:_payCount forKey:kLiveLessonModelPayCount];
+    [aCoder encodeObject:_courseIntroduce forKey:kLiveLessonModelCourseIntroduce];
+    [aCoder encodeObject:_status forKey:kLiveLessonModelStatus];
+    [aCoder encodeObject:_imUserId forKey:kLiveLessonModelImUserId];
+    [aCoder encodeObject:_courseGoupId forKey:kLiveLessonModelCourseGoupId];
     [aCoder encodeObject:_realName forKey:kLiveLessonModelRealName];
+    [aCoder encodeObject:_endTime forKey:kLiveLessonModelEndTime];
+    [aCoder encodeObject:_cover forKey:kLiveLessonModelCover];
+    [aCoder encodeDouble:_studentReplied forKey:kLiveLessonModelStudentReplied];
+    [aCoder encodeDouble:_teacherReplied forKey:kLiveLessonModelTeacherReplied];
     [aCoder encodeObject:_imGroupId forKey:kLiveLessonModelImGroupId];
+    [aCoder encodeObject:_subjectName forKey:kLiveLessonModelSubjectName];
+    [aCoder encodeObject:_name forKey:kLiveLessonModelName];
+    [aCoder encodeObject:_courseName forKey:kLiveLessonModelCourseName];
+    [aCoder encodeObject:_courseType forKey:kLiveLessonModelCourseType];
     [aCoder encodeObject:_subjectId forKey:kLiveLessonModelSubjectId];
     [aCoder encodeObject:_courseId forKey:kLiveLessonModelCourseId];
-    [aCoder encodeObject:_userId forKey:kLiveLessonModelUserId];
     [aCoder encodeObject:_avatar forKey:kLiveLessonModelAvatar];
-    [aCoder encodeObject:_endTime forKey:kLiveLessonModelEndTime];
-    [aCoder encodeObject:_subjectName forKey:kLiveLessonModelSubjectName];
-    [aCoder encodeObject:_cover forKey:kLiveLessonModelCover];
-    [aCoder encodeObject:_courseGoupId forKey:kLiveLessonModelCourseGoupId];
-    [aCoder encodeObject:_payCount forKey:kLiveLessonModelPayCount];
+    [aCoder encodeObject:_classDate forKey:kLiveLessonModelClassDate];
     [aCoder encodeObject:_startTime forKey:kLiveLessonModelStartTime];
-    [aCoder encodeObject:_status forKey:kLiveLessonModelStatus];
-    [aCoder encodeObject:_courseType forKey:kLiveLessonModelCourseType];
+    [aCoder encodeObject:_userId forKey:kLiveLessonModelUserId];
+    [aCoder encodeInteger:_courseNum forKey:kLiveLessonModelCourseNum];
+    [aCoder encodeInteger:_completeCourseNum forKey:kLiveLessonModelCompleteCourseNum];
 }
 
 - (id)copyWithZone:(NSZone *)zone
@@ -179,22 +218,29 @@ NSString *const kLiveLessonModelCourseType = @"courseType";
     
     if (copy) {
 
-        copy.classDate = [self.classDate copyWithZone:zone];
-        copy.name = [self.name copyWithZone:zone];
+        copy.payCount = [self.payCount copyWithZone:zone];
+        copy.courseIntroduce = [self.courseIntroduce copyWithZone:zone];
+        copy.status = [self.status copyWithZone:zone];
+        copy.imUserId = [self.imUserId copyWithZone:zone];
+        copy.courseGoupId = [self.courseGoupId copyWithZone:zone];
         copy.realName = [self.realName copyWithZone:zone];
+        copy.endTime = [self.endTime copyWithZone:zone];
+        copy.cover = [self.cover copyWithZone:zone];
+        copy.studentReplied = self.studentReplied;
+        copy.teacherReplied = self.teacherReplied;
         copy.imGroupId = [self.imGroupId copyWithZone:zone];
+        copy.subjectName = [self.subjectName copyWithZone:zone];
+        copy.name = [self.name copyWithZone:zone];
+        copy.courseName = [self.courseName copyWithZone:zone];
+        copy.courseType = [self.courseType copyWithZone:zone];
         copy.subjectId = [self.subjectId copyWithZone:zone];
         copy.courseId = [self.courseId copyWithZone:zone];
-        copy.userId = [self.userId copyWithZone:zone];
         copy.avatar = [self.avatar copyWithZone:zone];
-        copy.endTime = [self.endTime copyWithZone:zone];
-        copy.subjectName = [self.subjectName copyWithZone:zone];
-        copy.cover = [self.cover copyWithZone:zone];
-        copy.courseGoupId = [self.courseGoupId copyWithZone:zone];
-        copy.payCount = [self.payCount copyWithZone:zone];
+        copy.classDate = [self.classDate copyWithZone:zone];
         copy.startTime = [self.startTime copyWithZone:zone];
-        copy.status = [self.status copyWithZone:zone];
-        copy.courseType = [self.courseType copyWithZone:zone];
+        copy.userId = [self.userId copyWithZone:zone];
+        copy.courseNum = self.courseNum;
+        copy.completeCourseNum = self.completeCourseNum;
     }
     
     return copy;

+ 30 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/ProgramCourseGroupModel.h

@@ -0,0 +1,30 @@
+//
+//  ProgramCourseGroupModel.h
+//
+//  Created by Steven  on 2024/11/21
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+
+@interface ProgramCourseGroupModel : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, strong) NSString *status;
+@property (nonatomic, strong) NSString *coursePlan;
+@property (nonatomic, strong) NSString *courseGroupId;
+@property (nonatomic, strong) NSString *teacherAvatar;
+@property (nonatomic, strong) NSString *teacherName;
+@property (nonatomic, assign) double completeCourseNum;
+@property (nonatomic, strong) NSString *subjectId;
+@property (nonatomic, strong) NSString *subjectName;
+@property (nonatomic, strong) NSString *teacherId;
+@property (nonatomic, strong) NSString *courseGroupName;
+@property (nonatomic, assign) double courseNum;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 169 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/ProgramCourseGroupModel.m

@@ -0,0 +1,169 @@
+//
+//  ProgramCourseGroupModel.m
+//
+//  Created by Steven  on 2024/11/21
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import "ProgramCourseGroupModel.h"
+
+
+NSString *const kProgramCourseGroupModelStatus = @"status";
+NSString *const kProgramCourseGroupModelCoursePlan = @"coursePlan";
+NSString *const kProgramCourseGroupModelCourseGroupId = @"courseGroupId";
+NSString *const kProgramCourseGroupModelTeacherAvatar = @"teacherAvatar";
+NSString *const kProgramCourseGroupModelTeacherName = @"teacherName";
+NSString *const kProgramCourseGroupModelCompleteCourseNum = @"completeCourseNum";
+NSString *const kProgramCourseGroupModelSubjectId = @"subjectId";
+NSString *const kProgramCourseGroupModelSubjectName = @"subjectName";
+NSString *const kProgramCourseGroupModelTeacherId = @"teacherId";
+NSString *const kProgramCourseGroupModelCourseGroupName = @"courseGroupName";
+NSString *const kProgramCourseGroupModelCourseNum = @"courseNum";
+
+
+@interface ProgramCourseGroupModel ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation ProgramCourseGroupModel
+
+@synthesize status = _status;
+@synthesize coursePlan = _coursePlan;
+@synthesize courseGroupId = _courseGroupId;
+@synthesize teacherAvatar = _teacherAvatar;
+@synthesize teacherName = _teacherName;
+@synthesize completeCourseNum = _completeCourseNum;
+@synthesize subjectId = _subjectId;
+@synthesize subjectName = _subjectName;
+@synthesize teacherId = _teacherId;
+@synthesize courseGroupName = _courseGroupName;
+@synthesize courseNum = _courseNum;
+
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
+{
+    return [[self alloc] initWithDictionary:dict];
+}
+
+- (instancetype)initWithDictionary:(NSDictionary *)dict
+{
+    self = [super init];
+    
+    // This check serves to make sure that a non-NSDictionary object
+    // passed into the model class doesn't break the parsing.
+    if(self && [dict isKindOfClass:[NSDictionary class]]) {
+            self.status = [self objectOrNilForKey:kProgramCourseGroupModelStatus fromDictionary:dict];
+            self.coursePlan = [self objectOrNilForKey:kProgramCourseGroupModelCoursePlan fromDictionary:dict];
+            self.courseGroupId = [self objectOrNilForKey:kProgramCourseGroupModelCourseGroupId fromDictionary:dict];
+            self.teacherAvatar = [self objectOrNilForKey:kProgramCourseGroupModelTeacherAvatar fromDictionary:dict];
+            self.teacherName = [self objectOrNilForKey:kProgramCourseGroupModelTeacherName fromDictionary:dict];
+            self.completeCourseNum = [[self objectOrNilForKey:kProgramCourseGroupModelCompleteCourseNum fromDictionary:dict] doubleValue];
+            self.subjectId = [self objectOrNilForKey:kProgramCourseGroupModelSubjectId fromDictionary:dict];
+            self.subjectName = [self objectOrNilForKey:kProgramCourseGroupModelSubjectName fromDictionary:dict];
+            self.teacherId = [self objectOrNilForKey:kProgramCourseGroupModelTeacherId fromDictionary:dict];
+            self.courseGroupName = [self objectOrNilForKey:kProgramCourseGroupModelCourseGroupName fromDictionary:dict];
+            self.courseNum = [[self objectOrNilForKey:kProgramCourseGroupModelCourseNum fromDictionary:dict] doubleValue];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.status forKey:kProgramCourseGroupModelStatus];
+    [mutableDict setValue:self.coursePlan forKey:kProgramCourseGroupModelCoursePlan];
+    [mutableDict setValue:self.courseGroupId forKey:kProgramCourseGroupModelCourseGroupId];
+    [mutableDict setValue:self.teacherAvatar forKey:kProgramCourseGroupModelTeacherAvatar];
+    [mutableDict setValue:self.teacherName forKey:kProgramCourseGroupModelTeacherName];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.completeCourseNum] forKey:kProgramCourseGroupModelCompleteCourseNum];
+    [mutableDict setValue:self.subjectId forKey:kProgramCourseGroupModelSubjectId];
+    [mutableDict setValue:self.subjectName forKey:kProgramCourseGroupModelSubjectName];
+    [mutableDict setValue:self.teacherId forKey:kProgramCourseGroupModelTeacherId];
+    [mutableDict setValue:self.courseGroupName forKey:kProgramCourseGroupModelCourseGroupName];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.courseNum] forKey:kProgramCourseGroupModelCourseNum];
+
+    return [NSDictionary dictionaryWithDictionary:mutableDict];
+}
+
+- (NSString *)description 
+{
+    return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
+}
+
+#pragma mark - Helper Method
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict
+{
+    id object = [dict objectForKey:aKey];
+    if ([object isKindOfClass:[NSNumber class]]) {
+        NSNumber *number = object;
+        object = [number stringValue];
+    }
+    return [object isEqual:[NSNull null]] ? nil : object;
+}
+
+
+#pragma mark - NSCoding Methods
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super init];
+
+    self.status = [aDecoder decodeObjectForKey:kProgramCourseGroupModelStatus];
+    self.coursePlan = [aDecoder decodeObjectForKey:kProgramCourseGroupModelCoursePlan];
+    self.courseGroupId = [aDecoder decodeObjectForKey:kProgramCourseGroupModelCourseGroupId];
+    self.teacherAvatar = [aDecoder decodeObjectForKey:kProgramCourseGroupModelTeacherAvatar];
+    self.teacherName = [aDecoder decodeObjectForKey:kProgramCourseGroupModelTeacherName];
+    self.completeCourseNum = [aDecoder decodeDoubleForKey:kProgramCourseGroupModelCompleteCourseNum];
+    self.subjectId = [aDecoder decodeObjectForKey:kProgramCourseGroupModelSubjectId];
+    self.subjectName = [aDecoder decodeObjectForKey:kProgramCourseGroupModelSubjectName];
+    self.teacherId = [aDecoder decodeObjectForKey:kProgramCourseGroupModelTeacherId];
+    self.courseGroupName = [aDecoder decodeObjectForKey:kProgramCourseGroupModelCourseGroupName];
+    self.courseNum = [aDecoder decodeDoubleForKey:kProgramCourseGroupModelCourseNum];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_status forKey:kProgramCourseGroupModelStatus];
+    [aCoder encodeObject:_coursePlan forKey:kProgramCourseGroupModelCoursePlan];
+    [aCoder encodeObject:_courseGroupId forKey:kProgramCourseGroupModelCourseGroupId];
+    [aCoder encodeObject:_teacherAvatar forKey:kProgramCourseGroupModelTeacherAvatar];
+    [aCoder encodeObject:_teacherName forKey:kProgramCourseGroupModelTeacherName];
+    [aCoder encodeDouble:_completeCourseNum forKey:kProgramCourseGroupModelCompleteCourseNum];
+    [aCoder encodeObject:_subjectId forKey:kProgramCourseGroupModelSubjectId];
+    [aCoder encodeObject:_subjectName forKey:kProgramCourseGroupModelSubjectName];
+    [aCoder encodeObject:_teacherId forKey:kProgramCourseGroupModelTeacherId];
+    [aCoder encodeObject:_courseGroupName forKey:kProgramCourseGroupModelCourseGroupName];
+    [aCoder encodeDouble:_courseNum forKey:kProgramCourseGroupModelCourseNum];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    ProgramCourseGroupModel *copy = [[ProgramCourseGroupModel alloc] init];
+    
+    if (copy) {
+
+        copy.status = [self.status copyWithZone:zone];
+        copy.coursePlan = [self.coursePlan copyWithZone:zone];
+        copy.courseGroupId = [self.courseGroupId copyWithZone:zone];
+        copy.teacherAvatar = [self.teacherAvatar copyWithZone:zone];
+        copy.teacherName = [self.teacherName copyWithZone:zone];
+        copy.completeCourseNum = self.completeCourseNum;
+        copy.subjectId = [self.subjectId copyWithZone:zone];
+        copy.subjectName = [self.subjectName copyWithZone:zone];
+        copy.teacherId = [self.teacherId copyWithZone:zone];
+        copy.courseGroupName = [self.courseGroupName copyWithZone:zone];
+        copy.courseNum = self.courseNum;
+    }
+    
+    return copy;
+}
+
+
+@end

+ 10 - 12
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/VideoCourseModel.h

@@ -1,8 +1,8 @@
 //
 //  VideoCourseModel.h
 //
-//  Created by   on 2022/3/29
-//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//  Created by Steven  on 2024/11/21
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
 //
 
 #import <Foundation/Foundation.h>
@@ -13,24 +13,22 @@
 
 @property (nonatomic, strong) NSString *internalBaseClassIdentifier;
 @property (nonatomic, strong) NSString *lessonCoverUrl;
+@property (nonatomic, strong) NSString *realName;
 @property (nonatomic, assign) double lessonCount;
+@property (nonatomic, assign) NSInteger musicNum;
+@property (nonatomic, strong) NSString *auditVersion;
+@property (nonatomic, strong) NSString *lessonSubjectName;
 @property (nonatomic, strong) NSString *lessonDesc;
 @property (nonatomic, assign) double lessonPrice;
 @property (nonatomic, assign) double countStudent;
 @property (nonatomic, strong) NSString *lessonName;
 @property (nonatomic, strong) NSString *avatar;
 @property (nonatomic, strong) NSString *lessonSubject;
-@property (nonatomic, assign) double teacherId;
-@property (nonatomic, assign) double hotFlag;
-@property (nonatomic, strong) NSString *username;
-@property (nonatomic, strong) NSString *createTime;
-@property (nonatomic, assign) double auditStatus;
-@property (nonatomic, assign) double sortNumber;
-@property (nonatomic, strong) NSString *lessonTag;
-@property (nonatomic, assign) double topFlag;
-@property (nonatomic, strong) NSString *updateTime;
-@property (nonatomic, strong) NSString *lessonSubjectName;
 @property (nonatomic, strong) NSString *payType;
+@property (nonatomic, strong) NSString *teacherId;
+@property (nonatomic, strong) NSString *relationType;
+@property (nonatomic, strong) NSString *userName;
+@property (nonatomic, assign) double virtualNumber;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
 - (instancetype)initWithDictionary:(NSDictionary *)dict;

+ 64 - 75
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/VideoCourseModel.m

@@ -1,8 +1,8 @@
 //
 //  VideoCourseModel.m
 //
-//  Created by Steven  on 2022/4/2
-//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//  Created by Steven  on 2024/11/21
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
 //
 
 #import "VideoCourseModel.h"
@@ -10,24 +10,23 @@
 
 NSString *const kVideoCourseModelId = @"id";
 NSString *const kVideoCourseModelLessonCoverUrl = @"lessonCoverUrl";
+NSString *const kVideoCourseModelRealName = @"realName";
 NSString *const kVideoCourseModelLessonCount = @"lessonCount";
+NSString *const kVideoCourseModelMusicNum = @"musicNum";
+NSString *const kVideoCourseModelAuditVersion = @"auditVersion";
+NSString *const kVideoCourseModelLessonSubjectName = @"lessonSubjectName";
 NSString *const kVideoCourseModelLessonDesc = @"lessonDesc";
 NSString *const kVideoCourseModelLessonPrice = @"lessonPrice";
 NSString *const kVideoCourseModelCountStudent = @"countStudent";
 NSString *const kVideoCourseModelLessonName = @"lessonName";
 NSString *const kVideoCourseModelAvatar = @"avatar";
 NSString *const kVideoCourseModelLessonSubject = @"lessonSubject";
-NSString *const kVideoCourseModelTeacherId = @"teacherId";
-NSString *const kVideoCourseModelHotFlag = @"hotFlag";
-NSString *const kVideoCourseModelUsername = @"userName";
-NSString *const kVideoCourseModelCreateTime = @"createTime";
-NSString *const kVideoCourseModelAuditStatus = @"auditStatus";
-NSString *const kVideoCourseModelSortNumber = @"sortNumber";
-NSString *const kVideoCourseModelLessonTag = @"lessonTag";
-NSString *const kVideoCourseModelTopFlag = @"topFlag";
-NSString *const kVideoCourseModelUpdateTime = @"updateTime";
-NSString *const kVideoCourseModelLessonSubjectName = @"lessonSubjectName";
 NSString *const kVideoCourseModelPayType = @"payType";
+NSString *const kVideoCourseModelTeacherId = @"teacherId";
+NSString *const kVideoCourseModelRelationType = @"relationType";
+NSString *const kVideoCourseModelUserName = @"userName";
+NSString *const kVideoCourseModelVirtualNumber = @"virtualNumber";
+
 
 @interface VideoCourseModel ()
 
@@ -39,24 +38,23 @@ NSString *const kVideoCourseModelPayType = @"payType";
 
 @synthesize internalBaseClassIdentifier = _internalBaseClassIdentifier;
 @synthesize lessonCoverUrl = _lessonCoverUrl;
+@synthesize realName = _realName;
 @synthesize lessonCount = _lessonCount;
+@synthesize musicNum = _musicNum;
+@synthesize auditVersion = _auditVersion;
+@synthesize lessonSubjectName = _lessonSubjectName;
 @synthesize lessonDesc = _lessonDesc;
 @synthesize lessonPrice = _lessonPrice;
 @synthesize countStudent = _countStudent;
 @synthesize lessonName = _lessonName;
 @synthesize avatar = _avatar;
 @synthesize lessonSubject = _lessonSubject;
-@synthesize teacherId = _teacherId;
-@synthesize hotFlag = _hotFlag;
-@synthesize username = _username;
-@synthesize createTime = _createTime;
-@synthesize auditStatus = _auditStatus;
-@synthesize sortNumber = _sortNumber;
-@synthesize lessonTag = _lessonTag;
-@synthesize topFlag = _topFlag;
-@synthesize updateTime = _updateTime;
-@synthesize lessonSubjectName = _lessonSubjectName;
 @synthesize payType = _payType;
+@synthesize teacherId = _teacherId;
+@synthesize relationType = _relationType;
+@synthesize userName = _userName;
+@synthesize virtualNumber = _virtualNumber;
+
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
 {
@@ -72,24 +70,23 @@ NSString *const kVideoCourseModelPayType = @"payType";
     if(self && [dict isKindOfClass:[NSDictionary class]]) {
             self.internalBaseClassIdentifier = [self objectOrNilForKey:kVideoCourseModelId fromDictionary:dict];
             self.lessonCoverUrl = [self objectOrNilForKey:kVideoCourseModelLessonCoverUrl fromDictionary:dict];
+            self.realName = [self objectOrNilForKey:kVideoCourseModelRealName fromDictionary:dict];
             self.lessonCount = [[self objectOrNilForKey:kVideoCourseModelLessonCount fromDictionary:dict] doubleValue];
+        self.musicNum = [[self objectOrNilForKey:kVideoCourseModelMusicNum fromDictionary:dict] integerValue];
+            self.auditVersion = [self objectOrNilForKey:kVideoCourseModelAuditVersion fromDictionary:dict];
+            self.lessonSubjectName = [self objectOrNilForKey:kVideoCourseModelLessonSubjectName fromDictionary:dict];
             self.lessonDesc = [self objectOrNilForKey:kVideoCourseModelLessonDesc fromDictionary:dict];
             self.lessonPrice = [[self objectOrNilForKey:kVideoCourseModelLessonPrice fromDictionary:dict] doubleValue];
             self.countStudent = [[self objectOrNilForKey:kVideoCourseModelCountStudent fromDictionary:dict] doubleValue];
             self.lessonName = [self objectOrNilForKey:kVideoCourseModelLessonName fromDictionary:dict];
             self.avatar = [self objectOrNilForKey:kVideoCourseModelAvatar fromDictionary:dict];
             self.lessonSubject = [self objectOrNilForKey:kVideoCourseModelLessonSubject fromDictionary:dict];
-            self.teacherId = [[self objectOrNilForKey:kVideoCourseModelTeacherId fromDictionary:dict] doubleValue];
-            self.hotFlag = [[self objectOrNilForKey:kVideoCourseModelHotFlag fromDictionary:dict] doubleValue];
-            self.username = [self objectOrNilForKey:kVideoCourseModelUsername fromDictionary:dict];
-            self.createTime = [self objectOrNilForKey:kVideoCourseModelCreateTime fromDictionary:dict];
-            self.auditStatus = [[self objectOrNilForKey:kVideoCourseModelAuditStatus fromDictionary:dict] doubleValue];
-            self.sortNumber = [[self objectOrNilForKey:kVideoCourseModelSortNumber fromDictionary:dict] doubleValue];
-            self.lessonTag = [self objectOrNilForKey:kVideoCourseModelLessonTag fromDictionary:dict];
-            self.topFlag = [[self objectOrNilForKey:kVideoCourseModelTopFlag fromDictionary:dict] doubleValue];
-            self.updateTime = [self objectOrNilForKey:kVideoCourseModelUpdateTime fromDictionary:dict];
-        self.lessonSubjectName = [self objectOrNilForKey:kVideoCourseModelLessonSubjectName fromDictionary:dict];
-        self.payType = [self objectOrNilForKey:kVideoCourseModelPayType fromDictionary:dict];
+            self.payType = [self objectOrNilForKey:kVideoCourseModelPayType fromDictionary:dict];
+            self.teacherId = [self objectOrNilForKey:kVideoCourseModelTeacherId fromDictionary:dict];
+            self.relationType = [self objectOrNilForKey:kVideoCourseModelRelationType fromDictionary:dict];
+            self.userName = [self objectOrNilForKey:kVideoCourseModelUserName fromDictionary:dict];
+            self.virtualNumber = [[self objectOrNilForKey:kVideoCourseModelVirtualNumber fromDictionary:dict] doubleValue];
+
     }
     
     return self;
@@ -101,28 +98,27 @@ NSString *const kVideoCourseModelPayType = @"payType";
     NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
     [mutableDict setValue:self.internalBaseClassIdentifier forKey:kVideoCourseModelId];
     [mutableDict setValue:self.lessonCoverUrl forKey:kVideoCourseModelLessonCoverUrl];
+    [mutableDict setValue:self.realName forKey:kVideoCourseModelRealName];
     [mutableDict setValue:[NSNumber numberWithDouble:self.lessonCount] forKey:kVideoCourseModelLessonCount];
+    [mutableDict setValue:[NSNumber numberWithInteger:self.musicNum] forKey:kVideoCourseModelMusicNum];
+    [mutableDict setValue:self.auditVersion forKey:kVideoCourseModelAuditVersion];
+    [mutableDict setValue:self.lessonSubjectName forKey:kVideoCourseModelLessonSubjectName];
     [mutableDict setValue:self.lessonDesc forKey:kVideoCourseModelLessonDesc];
     [mutableDict setValue:[NSNumber numberWithDouble:self.lessonPrice] forKey:kVideoCourseModelLessonPrice];
     [mutableDict setValue:[NSNumber numberWithDouble:self.countStudent] forKey:kVideoCourseModelCountStudent];
     [mutableDict setValue:self.lessonName forKey:kVideoCourseModelLessonName];
     [mutableDict setValue:self.avatar forKey:kVideoCourseModelAvatar];
     [mutableDict setValue:self.lessonSubject forKey:kVideoCourseModelLessonSubject];
-    [mutableDict setValue:[NSNumber numberWithDouble:self.teacherId] forKey:kVideoCourseModelTeacherId];
-    [mutableDict setValue:[NSNumber numberWithDouble:self.hotFlag] forKey:kVideoCourseModelHotFlag];
-    [mutableDict setValue:self.username forKey:kVideoCourseModelUsername];
-    [mutableDict setValue:self.createTime forKey:kVideoCourseModelCreateTime];
-    [mutableDict setValue:[NSNumber numberWithDouble:self.auditStatus] forKey:kVideoCourseModelAuditStatus];
-    [mutableDict setValue:[NSNumber numberWithDouble:self.sortNumber] forKey:kVideoCourseModelSortNumber];
-    [mutableDict setValue:self.lessonTag forKey:kVideoCourseModelLessonTag];
-    [mutableDict setValue:[NSNumber numberWithDouble:self.topFlag] forKey:kVideoCourseModelTopFlag];
-    [mutableDict setValue:self.updateTime forKey:kVideoCourseModelUpdateTime];
-    [mutableDict setValue:self.lessonSubjectName forKey:kVideoCourseModelLessonSubjectName];
     [mutableDict setValue:self.payType forKey:kVideoCourseModelPayType];
+    [mutableDict setValue:self.teacherId forKey:kVideoCourseModelTeacherId];
+    [mutableDict setValue:self.relationType forKey:kVideoCourseModelRelationType];
+    [mutableDict setValue:self.userName forKey:kVideoCourseModelUserName];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.virtualNumber] forKey:kVideoCourseModelVirtualNumber];
+
     return [NSDictionary dictionaryWithDictionary:mutableDict];
 }
 
-- (NSString *)description
+- (NSString *)description 
 {
     return [NSString stringWithFormat:@"%@", [self dictionaryRepresentation]];
 }
@@ -147,25 +143,22 @@ NSString *const kVideoCourseModelPayType = @"payType";
 
     self.internalBaseClassIdentifier = [aDecoder decodeObjectForKey:kVideoCourseModelId];
     self.lessonCoverUrl = [aDecoder decodeObjectForKey:kVideoCourseModelLessonCoverUrl];
+    self.realName = [aDecoder decodeObjectForKey:kVideoCourseModelRealName];
     self.lessonCount = [aDecoder decodeDoubleForKey:kVideoCourseModelLessonCount];
+    self.musicNum = [aDecoder decodeIntegerForKey:kVideoCourseModelMusicNum];
+    self.auditVersion = [aDecoder decodeObjectForKey:kVideoCourseModelAuditVersion];
+    self.lessonSubjectName = [aDecoder decodeObjectForKey:kVideoCourseModelLessonSubjectName];
     self.lessonDesc = [aDecoder decodeObjectForKey:kVideoCourseModelLessonDesc];
     self.lessonPrice = [aDecoder decodeDoubleForKey:kVideoCourseModelLessonPrice];
     self.countStudent = [aDecoder decodeDoubleForKey:kVideoCourseModelCountStudent];
     self.lessonName = [aDecoder decodeObjectForKey:kVideoCourseModelLessonName];
     self.avatar = [aDecoder decodeObjectForKey:kVideoCourseModelAvatar];
     self.lessonSubject = [aDecoder decodeObjectForKey:kVideoCourseModelLessonSubject];
-    self.teacherId = [aDecoder decodeDoubleForKey:kVideoCourseModelTeacherId];
-    self.hotFlag = [aDecoder decodeDoubleForKey:kVideoCourseModelHotFlag];
-    self.username = [aDecoder decodeObjectForKey:kVideoCourseModelUsername];
-    self.createTime = [aDecoder decodeObjectForKey:kVideoCourseModelCreateTime];
-    self.auditStatus = [aDecoder decodeDoubleForKey:kVideoCourseModelAuditStatus];
-    self.sortNumber = [aDecoder decodeDoubleForKey:kVideoCourseModelSortNumber];
-    self.lessonTag = [aDecoder decodeObjectForKey:kVideoCourseModelLessonTag];
-    self.topFlag = [aDecoder decodeDoubleForKey:kVideoCourseModelTopFlag];
-    self.updateTime = [aDecoder decodeObjectForKey:kVideoCourseModelUpdateTime];
-    self.lessonSubjectName = [aDecoder decodeObjectForKey:kVideoCourseModelLessonSubjectName];
     self.payType = [aDecoder decodeObjectForKey:kVideoCourseModelPayType];
-    
+    self.teacherId = [aDecoder decodeObjectForKey:kVideoCourseModelTeacherId];
+    self.relationType = [aDecoder decodeObjectForKey:kVideoCourseModelRelationType];
+    self.userName = [aDecoder decodeObjectForKey:kVideoCourseModelUserName];
+    self.virtualNumber = [aDecoder decodeDoubleForKey:kVideoCourseModelVirtualNumber];
     return self;
 }
 
@@ -174,24 +167,22 @@ NSString *const kVideoCourseModelPayType = @"payType";
 
     [aCoder encodeObject:_internalBaseClassIdentifier forKey:kVideoCourseModelId];
     [aCoder encodeObject:_lessonCoverUrl forKey:kVideoCourseModelLessonCoverUrl];
+    [aCoder encodeObject:_realName forKey:kVideoCourseModelRealName];
     [aCoder encodeDouble:_lessonCount forKey:kVideoCourseModelLessonCount];
+    [aCoder encodeInteger:_musicNum forKey:kVideoCourseModelMusicNum];
+    [aCoder encodeObject:_auditVersion forKey:kVideoCourseModelAuditVersion];
+    [aCoder encodeObject:_lessonSubjectName forKey:kVideoCourseModelLessonSubjectName];
     [aCoder encodeObject:_lessonDesc forKey:kVideoCourseModelLessonDesc];
     [aCoder encodeDouble:_lessonPrice forKey:kVideoCourseModelLessonPrice];
     [aCoder encodeDouble:_countStudent forKey:kVideoCourseModelCountStudent];
     [aCoder encodeObject:_lessonName forKey:kVideoCourseModelLessonName];
     [aCoder encodeObject:_avatar forKey:kVideoCourseModelAvatar];
     [aCoder encodeObject:_lessonSubject forKey:kVideoCourseModelLessonSubject];
-    [aCoder encodeDouble:_teacherId forKey:kVideoCourseModelTeacherId];
-    [aCoder encodeDouble:_hotFlag forKey:kVideoCourseModelHotFlag];
-    [aCoder encodeObject:_username forKey:kVideoCourseModelUsername];
-    [aCoder encodeObject:_createTime forKey:kVideoCourseModelCreateTime];
-    [aCoder encodeDouble:_auditStatus forKey:kVideoCourseModelAuditStatus];
-    [aCoder encodeDouble:_sortNumber forKey:kVideoCourseModelSortNumber];
-    [aCoder encodeObject:_lessonTag forKey:kVideoCourseModelLessonTag];
-    [aCoder encodeDouble:_topFlag forKey:kVideoCourseModelTopFlag];
-    [aCoder encodeObject:_updateTime forKey:kVideoCourseModelUpdateTime];
-    [aCoder encodeObject:_lessonSubjectName forKey:kVideoCourseModelLessonSubjectName];
     [aCoder encodeObject:_payType forKey:kVideoCourseModelPayType];
+    [aCoder encodeObject:_teacherId forKey:kVideoCourseModelTeacherId];
+    [aCoder encodeObject:_relationType forKey:kVideoCourseModelRelationType];
+    [aCoder encodeObject:_userName forKey:kVideoCourseModelUserName];
+    [aCoder encodeDouble:_virtualNumber forKey:kVideoCourseModelVirtualNumber];
 }
 
 - (id)copyWithZone:(NSZone *)zone
@@ -202,24 +193,22 @@ NSString *const kVideoCourseModelPayType = @"payType";
 
         copy.internalBaseClassIdentifier = [self.internalBaseClassIdentifier copyWithZone:zone];
         copy.lessonCoverUrl = [self.lessonCoverUrl copyWithZone:zone];
+        copy.realName = [self.realName copyWithZone:zone];
         copy.lessonCount = self.lessonCount;
+        copy.musicNum = self.musicNum;
+        copy.auditVersion = [self.auditVersion copyWithZone:zone];
+        copy.lessonSubjectName = [self.lessonSubjectName copyWithZone:zone];
         copy.lessonDesc = [self.lessonDesc copyWithZone:zone];
         copy.lessonPrice = self.lessonPrice;
         copy.countStudent = self.countStudent;
         copy.lessonName = [self.lessonName copyWithZone:zone];
         copy.avatar = [self.avatar copyWithZone:zone];
         copy.lessonSubject = [self.lessonSubject copyWithZone:zone];
-        copy.teacherId = self.teacherId;
-        copy.hotFlag = self.hotFlag;
-        copy.username = [self.username copyWithZone:zone];
-        copy.createTime = [self.createTime copyWithZone:zone];
-        copy.auditStatus = self.auditStatus;
-        copy.sortNumber = self.sortNumber;
-        copy.lessonTag = [self.lessonTag copyWithZone:zone];
-        copy.topFlag = self.topFlag;
-        copy.updateTime = [self.updateTime copyWithZone:zone];
-        copy.lessonSubjectName = [self.lessonSubjectName copyWithZone:zone];
         copy.payType = [self.payType copyWithZone:zone];
+        copy.teacherId = [self.teacherId copyWithZone:zone];
+        copy.relationType = [self.relationType copyWithZone:zone];
+        copy.userName = [self.userName copyWithZone:zone];
+        copy.virtualNumber = self.virtualNumber;
     }
     
     return copy;

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/AccompanyCourseGroup/MyAccompanyCourseGroupView.h

@@ -0,0 +1,18 @@
+//
+//  MyAccompanyCourseGroupView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "KSJXBodyView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyAccompanyCourseGroupView : KSJXBodyView
+
+@property (nonatomic, strong) NSMutableArray *subjectList;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 355 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/AccompanyCourseGroup/MyAccompanyCourseGroupView.m

@@ -0,0 +1,355 @@
+//
+//  MyAccompanyCourseGroupView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyAccompanyCourseGroupView.h"
+#import "MyProgramCourseGroupCell.h"
+#import "MyCourseSearchView.h"
+#import "StateView.h"
+#import "Reachability.h"
+#import "ProgramCourseGroupModel.h"
+#import "MyCourseRankSortView.h"
+
+@interface MyAccompanyCourseGroupView ()<UITableViewDelegate,UITableViewDataSource>
+
+@property (nonatomic, assign) BOOL isLoadMore;
+@property (nonatomic, assign) NSInteger rows;
+@property (nonatomic, assign) NSInteger pages;
+
+@property (nonatomic, strong) NSMutableArray *dataArray;
+
+@property (nonatomic, strong) StateView *promptView;
+@property (nonatomic, strong) UIView *promptPlaceView;
+
+@property (nonatomic, assign) BOOL networkAvaiable; // 网络是否可用
+
+@property (nonatomic, strong) MyCourseSearchView *searchView;
+
+@property (nonatomic, strong) NSString *searchKey;
+
+@property (nonatomic, strong) NSString *subjectId;
+
+@property (nonatomic, assign) NSInteger subjectChooseIndex;
+
+@property (nonatomic, strong) NSString *status;
+
+@property (nonatomic, assign) NSInteger statusChooseIndex;
+@property (nonatomic, strong) MyCourseRankSortView *sortView;
+
+@property (nonatomic, strong) NSMutableArray *statusArray;
+
+@end
+
+
+
+@implementation MyAccompanyCourseGroupView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) style:UITableViewStylePlain];
+        self.tableView.backgroundColor = [UIColor clearColor];
+        self.tableView.showsVerticalScrollIndicator = NO;
+        
+        self.tableView.dataSource = self;
+        self.tableView.delegate = self;
+        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+        [self addSubview:self.tableView];
+        self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        [self.tableView registerNib:[UINib nibWithNibName:@"MyProgramCourseGroupCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MyProgramCourseGroupCell"];
+
+        UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, iPhoneXSafeBottomMargin)];
+        bottomView.backgroundColor = [UIColor clearColor];
+        self.tableView.tableFooterView = bottomView;
+        
+        MJWeakSelf;
+        self.tableView.mj_header = [KSGifRefreshHeader headerWithRefreshingBlock:^{
+            [weakSelf resetParamenter];
+            [weakSelf requestData];
+        }];
+        self.tableView.mj_footer = [KSGifRefreshFooter footerWithRefreshingBlock:^{
+            if (weakSelf.isLoadMore) {
+                weakSelf.pages += 1;
+                [weakSelf requestData];
+            }
+            else {
+                [weakSelf.tableView.mj_footer endRefreshingWithNoMoreData];
+            }
+        }];
+    }
+    return self;
+}
+
+- (void)refreshAndRequestData {
+    [self resetParamenter];
+    [self requestData];
+}
+
+- (void)resetParamenter {
+    self.isLoadMore = YES;
+    self.pages = 1;
+    self.rows = 10;
+    
+    self.dataArray = [NSMutableArray array];
+    [self.tableView.mj_footer resetNoMoreData];
+    [self setPromptString:@"暂无内容" imageName:@"empty_course" inView:self.tableView];
+    [self.tableView reloadData];
+}
+
+- (void)endRefresh {
+    @weakObj(self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        @strongObj(self);
+        [self.tableView.mj_header endRefreshing];
+        [self.tableView.mj_footer endRefreshing];
+    });
+}
+
+
+- (void)requestData {
+    [KSNetworkingManager myCourseGroupRequest:KS_POST courseType:@"PRACTICE" search:self.searchKey subjectId:self.subjectId status:self.status success:^(NSDictionary * _Nonnull dic) {
+        [self endRefresh];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [[dic ks_dictionaryValueForKey:@"data"] ks_arrayValueForKey:@"rows"];
+            for (NSDictionary *parm in sourceArray) {
+                ProgramCourseGroupModel *model = [[ProgramCourseGroupModel alloc] initWithDictionary:parm];
+                [self.dataArray addObject:model];
+            }
+            if (sourceArray.count < self.rows) {
+                self.isLoadMore = NO;
+            }
+        }
+        else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
+        }
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    } faliure:^(NSError * _Nonnull error) {
+        [self endRefresh];
+        if (self.networkAvaiable == NO) {
+            [self setPromptString:@"暂无网络" imageName:@"no_networking" inView:self.tableView];
+        }
+        [self.dataArray removeAllObjects];
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    }];
+}
+
+- (void)beginRefreshImmediately {
+    [self.tableView.mj_header beginRefreshing];
+}
+
+- (void)beginFirstRefresh {
+    if (!self.isHeaderRefreshed) {
+        [self beginRefreshImmediately];
+    }
+}
+- (void)selectCellAtIndexPath:(NSIndexPath *)indexPath {
+    
+    if (self.lastSelectedIndexPath == indexPath) {
+        return;
+    }
+    if (self.lastSelectedIndexPath != nil) {
+        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.lastSelectedIndexPath];
+        [cell setSelected:NO animated:NO];
+    }
+    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+    [cell setSelected:YES animated:NO];
+    self.lastSelectedIndexPath = indexPath;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat searchViewHeight = [MyCourseSearchView getViewHeight];
+
+    if (![self.subviews containsObject:self.searchView]) {
+        [self addSubview:self.searchView];
+        [self.searchView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.mas_equalTo(self);
+            make.height.mas_equalTo(searchViewHeight);
+        }];
+    }
+
+    [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.bottom.mas_equalTo(self);
+        make.top.mas_equalTo(self.searchView.mas_bottom);
+    }];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 106.0f;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    ProgramCourseGroupModel *model = self.dataArray[indexPath.row];
+    MyProgramCourseGroupCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyProgramCourseGroupCell"];
+    [cell configWithSource:model isVipCourse:NO];
+    return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    // 课程详情
+    
+}
+
+#pragma mark ------ lazying
+- (MyCourseSearchView *)searchView {
+    if (!_searchView) {
+        _searchView = [MyCourseSearchView sharedInstance];
+        MJWeakSelf;
+        [_searchView searchActionCallback:^(MY_COURSE_SORT type, NSString * _Nullable searchKey) {
+            [weakSelf searchAction:type searchKey:searchKey];
+        }];
+    }
+    return _searchView;
+}
+
+- (void)searchAction:(MY_COURSE_SORT)type searchKey:(NSString *)searchKey {
+    switch (type) {
+        case MY_COURSE_SORT_RANK:
+        {
+            [self showSortView];
+        }
+            break;
+        case MY_COURSE_SORT_SEARCH:
+        {
+            [self evaluateSource:searchKey];
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)showSortView {
+    self.searchView.arrowUp = YES;
+    [self.sortView refreshUI:self.statusChooseIndex subjectId:self.subjectChooseIndex];
+    [self.sortView showInView:[NSObject getKeyWindow]];
+}
+
+- (void)evaluateSource:(NSString *)searchKey {
+    self.searchKey = searchKey;
+    [self refreshAndRequestData];
+}
+
+/**
+ 设置没有数据时的显示
+ 
+ @param promptString 提示语
+ @param imgName 图片名称
+ @param view 显示在什么地方
+ */
+- (void)setPromptString:(NSString *)promptString imageName:(NSString *)imgName inView:(UIView *)view {
+    if (self.promptView != nil) {
+        [self.promptView removeFromSuperview];
+    }
+    else {
+        self.promptView = [[StateView alloc]init];
+        self.promptView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight - 300);
+    }
+    _promptPlaceView = view;
+    //当请求不到数据时 ,自定义提示view 将会出现;
+    self.promptView.imageName = imgName;
+    self.promptView.alpha = 0.0f;
+    [self.promptView setText:promptString];
+    [view addSubview:self.promptView];
+}
+
+// 结束刷新后调用方法
+- (void)changePromptLabelStateWithArray:(NSMutableArray *)array {
+    NSInteger count;
+    if (array.count) {
+        count = array.count;
+    } else {
+        count = 0;
+    }
+    
+    [UIView animateWithDuration:0.1 animations:^{
+        [[self promptView] setAlpha:count ? 0.0f :1.0f ] ;
+    }] ;
+    
+}
+
+- (BOOL)networkAvaiable {
+    return [self checkNetworkAvaiable];
+}
+
+- (BOOL)checkNetworkAvaiable {
+    BOOL isExistenceNetwork = YES;
+    Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
+    switch ([reach currentReachabilityStatus]) {
+        case NotReachable:
+            isExistenceNetwork = NO;
+            //NSLog(@"notReachable");
+            break;
+        case ReachableViaWiFi:
+            isExistenceNetwork = YES;
+            //NSLog(@"WIFI");
+            break;
+        case ReachableViaWWAN:
+            isExistenceNetwork = YES;
+            //NSLog(@"3G");
+            break;
+    }
+    return isExistenceNetwork;
+}
+
+- (MyCourseRankSortView *)sortView {
+    if (!_sortView) {
+        _sortView = [MyCourseRankSortView sharedInstance];
+        [_sortView configWithStatusArray:self.statusArray subjectArray:self.subjectList];
+        MJWeakSelf;
+        [_sortView sortActionCallback:^(MY_COURSE_SORTTYPE type, NSString * _Nullable status, NSString * _Nullable subjectId, NSInteger statusIndex, NSInteger subjectIndex) {
+            [weakSelf sortActionWithType:type status:status subjectId:subjectId statusChooseIndex:statusIndex subjectChooseIndex:subjectIndex];
+        }];
+    }
+    return _sortView;
+}
+
+- (void)sortActionWithType:(MY_COURSE_SORTTYPE)type status:(NSString *)status subjectId:(NSString *)subjectId statusChooseIndex:(NSInteger)statusChooseIndex subjectChooseIndex:(NSInteger)subjectChooseIndex  {
+    self.searchView.arrowUp = NO;
+    if (type == MY_COURSE_SORTTYPE_SORT) {
+        self.statusChooseIndex = statusChooseIndex;
+        self.subjectChooseIndex = subjectChooseIndex;
+        self.status = status;
+        self.subjectId = subjectId;
+        if ([NSString isEmptyString:status]) {
+            self.status = nil;
+        }
+        if ([NSString isEmptyString:subjectId]) {
+            self.subjectId = nil;
+        }
+        [self refreshAndRequestData];
+    }
+}
+
+- (NSMutableArray *)statusArray {
+    if (!_statusArray) {
+        _statusArray = [NSMutableArray arrayWithArray:@[@{@"name":@"全部",@"id":@""},@{@"name":@"未开课",@"id":@"NOT_START"},@{@"name":@"已开课",@"id":@"ING"},@{@"name":@"已结课",@"id":@"COMPLETE"}]];
+    }
+    return _statusArray;
+}
+
+- (void)setSubjectList:(NSMutableArray *)subjectList {
+    NSMutableArray *array = [NSMutableArray arrayWithArray:subjectList];
+    [array insertObject:@{@"name":@"全部",@"id":@""} atIndex:0];
+    _subjectList = array;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 19 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupListCell.h

@@ -0,0 +1,19 @@
+//
+//  MyLiveCourseGroupListCell.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import <UIKit/UIKit.h>
+#import "LiveLessonModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyLiveCourseGroupListCell : UICollectionViewCell
+
+- (void)configWithSource:(LiveLessonModel *)model;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 87 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupListCell.m

@@ -0,0 +1,87 @@
+//
+//  MyLiveCourseGroupListCell.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyLiveCourseGroupListCell.h"
+
+
+@interface MyLiveCourseGroupListCell ()
+
+@property (weak, nonatomic) IBOutlet UILabel *courseStatus;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseTime;
+
+@property (weak, nonatomic) IBOutlet UIImageView *courseCover;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseSubject;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseTitle;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseDesc;
+
+@property (weak, nonatomic) IBOutlet UILabel *finishDesc;
+
+@property (weak, nonatomic) IBOutlet UIImageView *avatar;
+
+@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
+
+@end
+
+@implementation MyLiveCourseGroupListCell
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+}
+
+- (void)configWithSource:(LiveLessonModel *)model {
+    [self evaluateGroupStatus:model.status];
+    // time
+    NSDateFormatter *formatter = [NSObject getDateformatter];
+    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
+    NSDate *startDate = [formatter dateFromString:model.startTime];
+    [formatter setDateFormat:@"yyyy-MM-dd HH:mm"];
+    NSString *courseBegin = [formatter stringFromDate:startDate];
+    self.courseTime.text = [NSString returnNoNullStringWithString:courseBegin];
+    
+    [self.courseCover sd_setImageWithURL:[NSURL URLWithString:[model.cover getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:@"video_placeholder"]];
+    self.courseSubject.text = [NSString returnNoNullStringWithString:model.subjectName];
+    self.courseTitle.text = [NSString returnNoNullStringWithString:model.name];
+    self.courseDesc.text = [NSString returnNoNullStringWithString:model.courseIntroduce];
+    
+    NSMutableAttributedString *attrs = [[NSMutableAttributedString alloc] initWithString:@"已上课时 " attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular],NSForegroundColorAttributeName:HexRGB(0x999999)}];
+    NSAttributedString *finishNumAttr = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%zd", model.completeCourseNum] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightSemibold],NSForegroundColorAttributeName:THEMECOLOR}];
+    [attrs appendAttributedString:finishNumAttr];
+    
+    NSAttributedString *totalDescAttr = [[NSAttributedString alloc] initWithString:@" /总课时 " attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular],NSForegroundColorAttributeName:HexRGB(0x999999)}];
+    [attrs appendAttributedString:totalDescAttr];
+    NSAttributedString *totalNumAttr = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%zd", model.courseNum] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightSemibold],NSForegroundColorAttributeName:THEMECOLOR}];
+    [attrs appendAttributedString:totalNumAttr];
+    self.finishDesc.attributedText = attrs;
+    [self.avatar sd_setImageWithURL:[NSURL URLWithString:[model.avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:TEACHER_AVATAR]];
+    self.nameLabel.text = [NSString returnNoNullStringWithString:model.realName];
+}
+
+
+- (void)evaluateGroupStatus:(NSString *)status {
+    if ([status isEqualToString:@"ING"]) {
+        self.courseStatus.text = @"已开课";
+        self.courseStatus.textColor = THEMECOLOR;
+    }
+    else if ([status isEqualToString:@"NOT_START"]) {
+        self.courseStatus.text = @"未开课";
+        self.courseStatus.textColor = HexRGB(0xFF802C);
+    }
+    else if ([status isEqualToString:@"COMPLETE"]) {
+        self.courseStatus.text = @"已结课";
+        self.courseStatus.textColor = HexRGB(0x999999);
+    }
+    else if ([status isEqualToString:@"CANCEL"]) {
+        self.courseStatus.text = @"已取消";
+        self.courseStatus.textColor = HexRGB(0x999999);
+    }
+}
+@end

+ 208 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupListCell.xib

@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="MyLiveCourseGroupListCell">
+            <rect key="frame" x="0.0" y="0.0" width="277" height="347"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                <rect key="frame" x="0.0" y="0.0" width="277" height="347"/>
+                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xJj-eX-YDa">
+                        <rect key="frame" x="0.0" y="0.0" width="277" height="347"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" image="mine_page_live_tag" translatesAutoresizingMaskIntoConstraints="NO" id="AUA-6F-MXS">
+                                <rect key="frame" x="12" y="15" width="20" height="16"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="16" id="Q24-w6-KDC"/>
+                                    <constraint firstAttribute="width" constant="20" id="YQF-hU-pNP"/>
+                                </constraints>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" text="已开课" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8nr-OW-hsO">
+                                <rect key="frame" x="223" y="13" width="42" height="20"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="20" id="pzy-qh-z2B"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
+                                <color key="textColor" red="0.1764705882352941" green="0.7803921568627451" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="video_placeholder" translatesAutoresizingMaskIntoConstraints="NO" id="gJz-ge-yei">
+                                <rect key="frame" x="12" y="46" width="253" height="142.33333333333334"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" secondItem="gJz-ge-yei" secondAttribute="height" multiplier="16:9" id="LzS-SI-uJM"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="6"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </imageView>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7YS-Lc-hvS">
+                                <rect key="frame" x="20" y="54" width="36" height="19"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="长笛" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K2S-UG-2xD">
+                                        <rect key="frame" x="6" y="3.0000000000000009" width="24" height="13.333333333333336"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.40000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="trailing" secondItem="K2S-UG-2xD" secondAttribute="trailing" constant="6" id="Hic-K1-lqh"/>
+                                    <constraint firstAttribute="height" constant="19" id="hWL-ge-oF0"/>
+                                    <constraint firstItem="K2S-UG-2xD" firstAttribute="centerY" secondItem="7YS-Lc-hvS" secondAttribute="centerY" id="iPi-1x-OB8"/>
+                                    <constraint firstItem="K2S-UG-2xD" firstAttribute="leading" secondItem="7YS-Lc-hvS" secondAttribute="leading" constant="6" id="uer-1m-fKJ"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="3"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="从零开始学竖笛直播课" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UwF-HP-7VM">
+                                <rect key="frame" x="12" y="196.33333333333334" width="253" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="22" id="mec-OG-ov4"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
+                                <color key="textColor" red="0.074509803920000006" green="0.078431372550000003" blue="0.08235294118" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="国际著名长笛演奏家、教育家张子珊女士为您讲…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2hL-aY-XV2">
+                                <rect key="frame" x="12" y="222.33333333333334" width="253" height="20"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="20" id="1yp-t1-vx3"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <color key="textColor" red="0.46666666670000001" green="0.46666666670000001" blue="0.46666666670000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" text="已上课时 4 /总课时 6" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9sU-yS-7be">
+                                <rect key="frame" x="132.66666666666663" y="312.66666666666669" width="132.33333333333337" height="17"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" image="arrange_course_icon" translatesAutoresizingMaskIntoConstraints="NO" id="iiI-K9-fO1">
+                                <rect key="frame" x="118.66666666666667" y="314" width="12.000000000000014" height="14"/>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" text="开课时间:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="80p-dX-TfO">
+                                <rect key="frame" x="39" y="13" width="62.666666666666657" height="20"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="20" id="YXu-A7-8Le"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="2024-11-16 09:30" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Erw-V1-YaB">
+                                <rect key="frame" x="101.66666666666669" y="13" width="111.33333333333331" height="20"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="20" id="wGf-c3-p4r"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" image="teacher_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="uha-Ll-P2J">
+                                <rect key="frame" x="12" y="309" width="26" height="26"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="26" id="L5T-Jb-JAQ"/>
+                                    <constraint firstAttribute="width" constant="26" id="gcG-Oq-9UX"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="13"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="严琦" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8Nu-1r-jPb">
+                                <rect key="frame" x="44" y="313.66666666666669" width="28" height="17"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="2hL-aY-XV2" firstAttribute="leading" secondItem="xJj-eX-YDa" secondAttribute="leading" constant="12" id="2cb-S7-ZtC"/>
+                            <constraint firstAttribute="trailing" secondItem="8nr-OW-hsO" secondAttribute="trailing" constant="12" id="8TP-Md-KQH"/>
+                            <constraint firstItem="2hL-aY-XV2" firstAttribute="top" secondItem="UwF-HP-7VM" secondAttribute="bottom" constant="4" id="A21-Y9-bAb"/>
+                            <constraint firstItem="9sU-yS-7be" firstAttribute="leading" secondItem="iiI-K9-fO1" secondAttribute="trailing" constant="2" id="ARq-CK-t43"/>
+                            <constraint firstItem="8nr-OW-hsO" firstAttribute="centerY" secondItem="Erw-V1-YaB" secondAttribute="centerY" id="FNS-k4-sdX"/>
+                            <constraint firstItem="9sU-yS-7be" firstAttribute="centerY" secondItem="iiI-K9-fO1" secondAttribute="centerY" id="GdY-8C-uHO"/>
+                            <constraint firstItem="UwF-HP-7VM" firstAttribute="leading" secondItem="xJj-eX-YDa" secondAttribute="leading" constant="12" id="Jxb-8y-cp8"/>
+                            <constraint firstItem="uha-Ll-P2J" firstAttribute="centerY" secondItem="8Nu-1r-jPb" secondAttribute="centerY" id="Khr-LO-1Mq"/>
+                            <constraint firstAttribute="trailing" secondItem="9sU-yS-7be" secondAttribute="trailing" constant="12" id="L4i-wF-Re6"/>
+                            <constraint firstItem="gJz-ge-yei" firstAttribute="top" secondItem="AUA-6F-MXS" secondAttribute="bottom" constant="15" id="LSH-OU-dCc"/>
+                            <constraint firstAttribute="bottom" secondItem="iiI-K9-fO1" secondAttribute="bottom" constant="19" id="NWV-ey-fKP"/>
+                            <constraint firstItem="uha-Ll-P2J" firstAttribute="top" relation="greaterThanOrEqual" secondItem="2hL-aY-XV2" secondAttribute="bottom" constant="8" id="PhD-JF-tYU"/>
+                            <constraint firstAttribute="trailing" secondItem="2hL-aY-XV2" secondAttribute="trailing" constant="12" id="TPk-MW-c6u"/>
+                            <constraint firstItem="gJz-ge-yei" firstAttribute="leading" secondItem="xJj-eX-YDa" secondAttribute="leading" constant="12" id="Tab-w6-EMA"/>
+                            <constraint firstItem="Erw-V1-YaB" firstAttribute="centerY" secondItem="AUA-6F-MXS" secondAttribute="centerY" id="VJ0-ON-udH"/>
+                            <constraint firstItem="Erw-V1-YaB" firstAttribute="leading" secondItem="80p-dX-TfO" secondAttribute="trailing" id="VJg-Sr-bvJ"/>
+                            <constraint firstItem="iiI-K9-fO1" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="8Nu-1r-jPb" secondAttribute="trailing" constant="10" id="ZBZ-QR-QyI"/>
+                            <constraint firstItem="7YS-Lc-hvS" firstAttribute="top" secondItem="gJz-ge-yei" secondAttribute="top" constant="8" id="ZJz-b9-4Z5"/>
+                            <constraint firstItem="7YS-Lc-hvS" firstAttribute="leading" secondItem="gJz-ge-yei" secondAttribute="leading" constant="8" id="Zms-fW-utt"/>
+                            <constraint firstAttribute="trailing" secondItem="gJz-ge-yei" secondAttribute="trailing" constant="12" id="bx1-H0-mEf"/>
+                            <constraint firstItem="Erw-V1-YaB" firstAttribute="centerY" secondItem="80p-dX-TfO" secondAttribute="centerY" id="frC-9a-09X"/>
+                            <constraint firstItem="UwF-HP-7VM" firstAttribute="top" secondItem="gJz-ge-yei" secondAttribute="bottom" constant="8" id="ign-tx-78w"/>
+                            <constraint firstItem="Erw-V1-YaB" firstAttribute="centerY" secondItem="80p-dX-TfO" secondAttribute="centerY" id="qla-3N-95K"/>
+                            <constraint firstItem="80p-dX-TfO" firstAttribute="leading" secondItem="AUA-6F-MXS" secondAttribute="trailing" constant="7" id="stl-6Q-jnH"/>
+                            <constraint firstItem="AUA-6F-MXS" firstAttribute="leading" secondItem="xJj-eX-YDa" secondAttribute="leading" constant="12" id="tiQ-ev-GVh"/>
+                            <constraint firstItem="AUA-6F-MXS" firstAttribute="top" secondItem="xJj-eX-YDa" secondAttribute="top" constant="15" id="uyB-TJ-90N"/>
+                            <constraint firstAttribute="trailing" secondItem="UwF-HP-7VM" secondAttribute="trailing" constant="12" id="vcj-Ub-YSw"/>
+                            <constraint firstItem="8Nu-1r-jPb" firstAttribute="leading" secondItem="uha-Ll-P2J" secondAttribute="trailing" constant="6" id="vkV-ZO-YCH"/>
+                            <constraint firstItem="8nr-OW-hsO" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Erw-V1-YaB" secondAttribute="trailing" constant="10" id="wHo-Hj-RZX"/>
+                            <constraint firstAttribute="bottom" secondItem="uha-Ll-P2J" secondAttribute="bottom" constant="12" id="xsy-Uh-l9v"/>
+                            <constraint firstItem="80p-dX-TfO" firstAttribute="centerY" secondItem="AUA-6F-MXS" secondAttribute="centerY" id="yJc-jc-rXM"/>
+                            <constraint firstItem="uha-Ll-P2J" firstAttribute="leading" secondItem="xJj-eX-YDa" secondAttribute="leading" constant="12" id="ym8-Sd-WGK"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="6"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </view>
+                </subviews>
+            </view>
+            <viewLayoutGuide key="safeArea" id="SEy-5g-ep8"/>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="xJj-eX-YDa" secondAttribute="trailing" id="aOq-qQ-0hO"/>
+                <constraint firstItem="xJj-eX-YDa" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="d22-hH-C7Q"/>
+                <constraint firstItem="xJj-eX-YDa" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="tYg-hx-rEf"/>
+                <constraint firstAttribute="bottom" secondItem="xJj-eX-YDa" secondAttribute="bottom" id="xP1-4D-31W"/>
+            </constraints>
+            <size key="customSize" width="277" height="347"/>
+            <connections>
+                <outlet property="avatar" destination="uha-Ll-P2J" id="tSq-hx-hCK"/>
+                <outlet property="courseCover" destination="gJz-ge-yei" id="Z0x-gZ-31s"/>
+                <outlet property="courseDesc" destination="2hL-aY-XV2" id="XSy-3v-1GF"/>
+                <outlet property="courseStatus" destination="8nr-OW-hsO" id="FD1-lo-pGc"/>
+                <outlet property="courseSubject" destination="K2S-UG-2xD" id="wQv-N0-1Gn"/>
+                <outlet property="courseTime" destination="Erw-V1-YaB" id="Bfa-at-etw"/>
+                <outlet property="courseTitle" destination="UwF-HP-7VM" id="w83-3a-9Ke"/>
+                <outlet property="finishDesc" destination="9sU-yS-7be" id="7Ee-v0-TRQ"/>
+                <outlet property="nameLabel" destination="8Nu-1r-jPb" id="LHq-Qf-Hzs"/>
+            </connections>
+            <point key="canvasLocation" x="228.24427480916029" y="95.422535211267615"/>
+        </collectionViewCell>
+    </objects>
+    <resources>
+        <image name="arrange_course_icon" width="12" height="14"/>
+        <image name="mine_page_live_tag" width="20" height="16"/>
+        <image name="teacher_avatar" width="150" height="150"/>
+        <image name="video_placeholder" width="103" height="72"/>
+    </resources>
+</document>

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupView.h

@@ -0,0 +1,18 @@
+//
+//  MyLiveCourseGroupView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "kSJXCollectionView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyLiveCourseGroupView : kSJXCollectionView
+
+@property (nonatomic, strong) NSMutableArray *subjectList;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 368 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/LiveCourseGroup/MyLiveCourseGroupView.m

@@ -0,0 +1,368 @@
+//
+//  MyLiveCourseGroupView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyLiveCourseGroupView.h"
+#import "MyCourseSearchView.h"
+#import "MyLiveCourseGroupListCell.h"
+#import "StateView.h"
+#import "Reachability.h"
+#import "LiveLessonModel.h"
+#import "KSBaseWKWebViewController.h"
+#import "MyCourseRankSortView.h"
+
+@interface MyLiveCourseGroupView ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
+
+@property (nonatomic, strong) NSMutableArray *dataArray;
+
+@property (nonatomic, strong) StateView *promptView;
+@property (nonatomic, strong) UIView *promptPlaceView;
+
+@property (nonatomic, assign) BOOL networkAvaiable; // 网络是否可用
+
+@property (nonatomic, assign) BOOL isLoadMore;
+@property (nonatomic, assign) NSInteger rows;
+@property (nonatomic, assign) NSInteger pages;
+
+@property (nonatomic, strong) MyCourseSearchView *searchView;
+
+@property (nonatomic, strong) NSString *searchKey;
+
+@property (nonatomic, strong) NSString *subjectId;
+
+@property (nonatomic, strong) NSString *status;
+
+@property (nonatomic, strong) NSString *classDate;
+
+@property (nonatomic, assign) NSInteger subjectChooseIndex;
+
+@property (nonatomic, assign) NSInteger statusChooseIndex;
+
+@property (nonatomic, strong) MyCourseRankSortView *sortView;
+
+@property (nonatomic, strong) NSMutableArray *statusArray;
+@end
+
+
+@implementation MyLiveCourseGroupView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
+        layout.sectionInset = UIEdgeInsetsMake(0, 14, 12, 14);
+        
+        self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) collectionViewLayout:layout];
+        self.collectionView.backgroundColor = [UIColor clearColor];
+        self.collectionView.delegate = self;
+        self.collectionView.dataSource = self;
+        self.collectionView.showsVerticalScrollIndicator = NO;
+        self.collectionView.showsHorizontalScrollIndicator = NO;
+        [self.collectionView registerNib:[UINib nibWithNibName:@"MyLiveCourseGroupListCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:@"MyLiveCourseGroupListCell"];
+        [self addSubview:self.collectionView];
+        self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        MJWeakSelf;
+        self.collectionView.mj_header = [KSGifRefreshHeader headerWithRefreshingBlock:^{
+            [weakSelf resetParamenter];
+            [weakSelf requestData];
+        }];
+        self.collectionView.mj_footer = [KSGifRefreshFooter footerWithRefreshingBlock:^{
+            if (weakSelf.isLoadMore) {
+                weakSelf.pages += 1;
+                [weakSelf requestData];
+            }
+            else {
+                [weakSelf.collectionView.mj_footer endRefreshingWithNoMoreData];
+            }
+        }];
+    }
+    return self;
+}
+
+- (void)endRefresh {
+    @weakObj(self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        @strongObj(self);
+        [self.collectionView.mj_header endRefreshing];
+        [self.collectionView.mj_footer endRefreshing];
+    });
+}
+
+- (void)refreshAndRequestData {
+    [self resetParamenter];
+    [self requestData];
+}
+
+- (void)resetParamenter {
+    self.isLoadMore = YES;
+    self.pages = 1;
+    self.rows = 10;
+    self.dataArray = [NSMutableArray array];
+    [self.collectionView.mj_footer resetNoMoreData];
+    [self setPromptString:@"暂无内容" imageName:@"empty_course" inView:self.collectionView];
+    [self.collectionView reloadData];
+}
+
+- (void)requestData {
+    [KSNetworkingManager queryMyLiveCourse:KS_POST classDate:self.classDate status:self.status subjectId:self.subjectId page:self.pages rows:self.rows success:^(NSDictionary * _Nonnull dic) {
+        [self endRefresh];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [[dic ks_dictionaryValueForKey:@"data"] ks_arrayValueForKey:@"rows"];
+            for (NSDictionary *parm in sourceArray) {
+                LiveLessonModel *model = [[LiveLessonModel alloc] initWithDictionary:parm];
+                [self.dataArray addObject:model];
+            }
+            
+            if (sourceArray.count < self.rows) {
+                self.isLoadMore = NO;
+            }
+        }
+        else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
+        }
+        [self.collectionView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    } faliure:^(NSError * _Nonnull error) {
+        [self endRefresh];
+        if (self.networkAvaiable == NO) {
+            [self setPromptString:@"暂无网络" imageName:@"no_networking" inView:self.collectionView];
+        }
+        [self.dataArray removeAllObjects];
+        [self.collectionView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    }];
+}
+
+- (void)beginRefreshImmediately {
+    [self.collectionView.mj_header beginRefreshing];
+}
+
+- (void)selectCellAtIndexPath:(NSIndexPath *)indexPath {
+    
+    if (self.lastSelectedIndexPath == indexPath) {
+        return;
+    }
+    if (self.lastSelectedIndexPath != nil) {
+        UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:self.lastSelectedIndexPath];
+        [cell setSelected:NO];
+    }
+    UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
+    [cell setSelected:YES];
+    self.lastSelectedIndexPath = indexPath;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat searchViewHeight = [MyCourseSearchView getViewHeight];
+
+    if (![self.subviews containsObject:self.searchView]) {
+        [self addSubview:self.searchView];
+        [self.searchView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.mas_equalTo(self);
+            make.height.mas_equalTo(searchViewHeight);
+        }];
+    }
+
+    [self.collectionView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.bottom.mas_equalTo(self);
+        make.top.mas_equalTo(self.searchView.mas_bottom);
+    }];
+}
+
+
+- (void)beginFirstRefresh {
+    if (!self.isHeaderRefreshed) {
+        [self beginRefreshImmediately];
+    }
+}
+
+#pragma mark ----- collection view
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
+    return 1;
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    MyLiveCourseGroupListCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MyLiveCourseGroupListCell" forIndexPath:indexPath];
+    
+    LiveLessonModel *model = [self.dataArray objectAtIndex:indexPath.row];
+    [cell configWithSource:model];
+    return cell;
+}
+
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    LiveLessonModel *model = self.dataArray[indexPath.row];
+    KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
+    NSString *url = [NSString stringWithFormat:@"%@/#/liveDetail?joinRoom=1&groupId=%@&classId=%@", WEBHOST, model.courseGoupId,model.courseId];
+    ctrl.url = url;
+    [self.naviController pushViewController:ctrl animated:YES];
+}
+
+- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
+    CGFloat width = KPortraitWidth - 28;
+    if (IS_IPAD) {
+        width = (KPortraitWidth - 28 - 12 * 2 - 12) / 2.0f;
+    }
+    CGFloat height = (width - 12 * 2) / 16 * 9 + 143;
+    return CGSizeMake(width, height);
+}
+
+#pragma mark ------ lazying
+- (MyCourseSearchView *)searchView {
+    if (!_searchView) {
+        _searchView = [MyCourseSearchView sharedInstance];
+        MJWeakSelf;
+        [_searchView searchActionCallback:^(MY_COURSE_SORT type, NSString * _Nullable searchKey) {
+            [weakSelf searchAction:type searchKey:searchKey];
+        }];
+    }
+    return _searchView;
+}
+
+- (void)searchAction:(MY_COURSE_SORT)type searchKey:(NSString *)searchKey {
+    switch (type) {
+        case MY_COURSE_SORT_RANK:
+        {
+            [self showSortView];
+        }
+            break;
+        case MY_COURSE_SORT_SEARCH:
+        {
+            [self evaluateSource:searchKey];
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)showSortView {
+    self.searchView.arrowUp = YES;
+    [self.sortView refreshUI:self.statusChooseIndex subjectId:self.subjectChooseIndex];
+    [self.sortView showInView:[NSObject getKeyWindow]];
+}
+
+- (void)evaluateSource:(NSString *)searchKey {
+    self.searchKey = searchKey;
+    [self refreshAndRequestData];
+}
+
+/**
+ 设置没有数据时的显示
+ 
+ @param promptString 提示语
+ @param imgName 图片名称
+ @param view 显示在什么地方
+ */
+- (void)setPromptString:(NSString *)promptString imageName:(NSString *)imgName inView:(UIView *)view {
+    if (self.promptView != nil) {
+        [self.promptView removeFromSuperview];
+    }
+    else {
+        self.promptView = [[StateView alloc]init];
+        self.promptView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight - 300);
+    }
+    _promptPlaceView = view;
+    //当请求不到数据时 ,自定义提示view 将会出现;
+    self.promptView.imageName = imgName;
+    self.promptView.alpha = 0.0f;
+    [self.promptView setText:promptString];
+    [view addSubview:self.promptView];
+}
+
+// 结束刷新后调用方法
+- (void)changePromptLabelStateWithArray:(NSMutableArray *)array {
+    NSInteger count;
+    if (array.count) {
+        count = array.count;
+    } else {
+        count = 0;
+    }
+    
+    [UIView animateWithDuration:0.1 animations:^{
+        [[self promptView] setAlpha:count ? 0.0f :1.0f ] ;
+    }] ;
+    
+}
+
+- (BOOL)networkAvaiable {
+    return [self checkNetworkAvaiable];
+}
+
+- (BOOL)checkNetworkAvaiable {
+    BOOL isExistenceNetwork = YES;
+    Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
+    switch ([reach currentReachabilityStatus]) {
+        case NotReachable:
+            isExistenceNetwork = NO;
+            //NSLog(@"notReachable");
+            break;
+        case ReachableViaWiFi:
+            isExistenceNetwork = YES;
+            //NSLog(@"WIFI");
+            break;
+        case ReachableViaWWAN:
+            isExistenceNetwork = YES;
+            //NSLog(@"3G");
+            break;
+    }
+    return isExistenceNetwork;
+}
+
+- (MyCourseRankSortView *)sortView {
+    if (!_sortView) {
+        _sortView = [MyCourseRankSortView sharedInstance];
+        [_sortView configWithStatusArray:self.statusArray subjectArray:self.subjectList];
+        MJWeakSelf;
+        [_sortView sortActionCallback:^(MY_COURSE_SORTTYPE type, NSString * _Nullable status, NSString * _Nullable subjectId, NSInteger statusIndex, NSInteger subjectIndex) {
+            [weakSelf sortActionWithType:type status:status subjectId:subjectId statusChooseIndex:statusIndex subjectChooseIndex:subjectIndex];
+        }];
+    }
+    return _sortView;
+}
+
+- (void)sortActionWithType:(MY_COURSE_SORTTYPE)type status:(NSString *)status subjectId:(NSString *)subjectId statusChooseIndex:(NSInteger)statusChooseIndex subjectChooseIndex:(NSInteger)subjectChooseIndex  {
+    self.searchView.arrowUp = NO;
+    if (type == MY_COURSE_SORTTYPE_SORT) {
+        self.statusChooseIndex = statusChooseIndex;
+        self.subjectChooseIndex = subjectChooseIndex;
+        self.status = status;
+        self.subjectId = subjectId;
+        if ([NSString isEmptyString:status]) {
+            self.status = nil;
+        }
+        if ([NSString isEmptyString:subjectId]) {
+            self.subjectId = nil;
+        }
+        [self refreshAndRequestData];
+    }
+}
+
+- (NSMutableArray *)statusArray {
+    if (!_statusArray) {
+        _statusArray = [NSMutableArray arrayWithArray:@[@{@"name":@"全部",@"id":@""},@{@"name":@"未开课",@"id":@"NOT_START"},@{@"name":@"已开课",@"id":@"ING"},@{@"name":@"已结课",@"id":@"COMPLETE"}]];
+    }
+    return _statusArray;
+}
+
+- (void)setSubjectList:(NSMutableArray *)subjectList {
+    NSMutableArray *array = [NSMutableArray arrayWithArray:subjectList];
+    [array insertObject:@{@"name":@"全部",@"id":@""} atIndex:0];
+    _subjectList = array;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 19 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicGroupListCell.h

@@ -0,0 +1,19 @@
+//
+//  MyMusicGroupListCell.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import <UIKit/UIKit.h>
+#import "ProgramCourseGroupModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyMusicGroupListCell : UITableViewCell
+
+- (void)configWithSource:(ProgramCourseGroupModel *)model;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 80 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicGroupListCell.m

@@ -0,0 +1,80 @@
+//
+//  MyMusicGroupListCell.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyMusicGroupListCell.h"
+
+@interface MyMusicGroupListCell ()
+
+@property (weak, nonatomic) IBOutlet UILabel *courseGroupName;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseStudents;
+
+@property (weak, nonatomic) IBOutlet UILabel *subjectLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseDesc;
+
+@end
+
+@implementation MyMusicGroupListCell
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    self.selectionStyle = UITableViewCellSelectionStyleNone;
+}
+
+- (void)configWithSource:(ProgramCourseGroupModel *)model {
+    
+    self.courseGroupName.text = [NSString returnNoNullStringWithString:model.courseGroupName];
+    /// 状态
+    [self evaluateGroupStatus:model.status];
+        
+    self.courseStudents.text = [NSString returnNoNullStringWithString:model.teacherName];
+    
+    self.subjectLabel.text = [NSString returnNoNullStringWithString:model.subjectName];
+    
+    // 课程描述
+    NSMutableAttributedString *attrs = [[NSMutableAttributedString alloc] initWithString:@"已上课时 " attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular],NSForegroundColorAttributeName:HexRGB(0x999999)}];
+    NSAttributedString *finishNumAttr = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%.0f", model.completeCourseNum] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightSemibold],NSForegroundColorAttributeName:THEMECOLOR}];
+    [attrs appendAttributedString:finishNumAttr];
+    
+    NSAttributedString *totalDescAttr = [[NSAttributedString alloc] initWithString:@" /总课时 " attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular],NSForegroundColorAttributeName:HexRGB(0x999999)}];
+    [attrs appendAttributedString:totalDescAttr];
+    NSAttributedString *totalNumAttr = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%.0f", model.courseNum] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightSemibold],NSForegroundColorAttributeName:THEMECOLOR}];
+    [attrs appendAttributedString:totalNumAttr];
+    self.courseDesc.attributedText = attrs;
+}
+
+
+- (void)evaluateGroupStatus:(NSString *)status {
+    if ([status isEqualToString:@"ING"]) {
+        self.statusLabel.text = @"已开课";
+        self.statusLabel.textColor = THEMECOLOR;
+    }
+    else if ([status isEqualToString:@"NOT_START"]) {
+        self.statusLabel.text = @"未开课";
+        self.statusLabel.textColor = HexRGB(0xFF802C);
+    }
+    else if ([status isEqualToString:@"COMPLETE"]) {
+        self.statusLabel.text = @"已结课";
+        self.statusLabel.textColor = HexRGB(0x999999);
+    }
+    else if ([status isEqualToString:@"CANCEL"]) {
+        self.statusLabel.text = @"已取消";
+        self.statusLabel.textColor = HexRGB(0x999999);
+    }
+}
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+@end

+ 141 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicGroupListCell.xib

@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="105" id="KGk-i7-Jjw" customClass="MyMusicGroupListCell">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="106"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="106"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wVO-PU-gXJ">
+                        <rect key="frame" x="14" y="0.0" width="292" height="94"/>
+                        <subviews>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="张老师琴房课" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dy9-VA-eiu">
+                                <rect key="frame" x="12" y="12" width="95.333333333333329" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="22" id="p5C-Kg-rww"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
+                                <color key="textColor" red="0.074509803920000006" green="0.078431372550000003" blue="0.08235294118" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" text="未开课" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1Ol-S1-0uy">
+                                <rect key="frame" x="238" y="12" width="42" height="17"/>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
+                                <color key="textColor" red="1" green="0.50196078430000002" blue="0.17254901959999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="course_musicRoom" translatesAutoresizingMaskIntoConstraints="NO" id="H34-rn-KTf">
+                                <rect key="frame" x="12" y="42" width="40" height="40"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="40" id="Kbe-83-N14"/>
+                                    <constraint firstAttribute="width" constant="40" id="McX-ua-4GD"/>
+                                </constraints>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="张涵宇、向冰冰等5人" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hQh-fY-QGG">
+                                <rect key="frame" x="60" y="42" width="128" height="17"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="17" id="cta-ti-zwQ"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <view contentMode="scaleToFill" horizontalCompressionResistancePriority="752" translatesAutoresizingMaskIntoConstraints="NO" id="vge-mo-L76">
+                                <rect key="frame" x="193" y="42" width="38" height="17"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="单簧管" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HuW-TI-Qg2">
+                                        <rect key="frame" x="4" y="2.6666666666666643" width="30" height="12"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
+                                        <color key="textColor" red="1" green="0.54901960780000003" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="1" green="0.94509803920000002" blue="0.87058823529999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="17" id="EKs-GN-PrW"/>
+                                    <constraint firstItem="HuW-TI-Qg2" firstAttribute="leading" secondItem="vge-mo-L76" secondAttribute="leading" constant="4" id="PXG-Ga-ZuL"/>
+                                    <constraint firstAttribute="trailing" secondItem="HuW-TI-Qg2" secondAttribute="trailing" constant="4" id="hfg-wn-1T6"/>
+                                    <constraint firstItem="HuW-TI-Qg2" firstAttribute="centerY" secondItem="vge-mo-L76" secondAttribute="centerY" id="tIg-gR-Rs4"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="4"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="已上课时 4 /总课时 6" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pMp-Fa-WxS">
+                                <rect key="frame" x="77.000000000000014" y="64.666666666666671" width="132.33333333333337" height="17"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="arrange_course_icon" translatesAutoresizingMaskIntoConstraints="NO" id="UMu-rh-fKg">
+                                <rect key="frame" x="63" y="66" width="12" height="14"/>
+                            </imageView>
+                        </subviews>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <constraints>
+                            <constraint firstItem="hQh-fY-QGG" firstAttribute="leading" secondItem="H34-rn-KTf" secondAttribute="trailing" constant="8" id="5VJ-nV-V4r"/>
+                            <constraint firstItem="H34-rn-KTf" firstAttribute="leading" secondItem="wVO-PU-gXJ" secondAttribute="leading" constant="12" id="7oN-IZ-bHp"/>
+                            <constraint firstItem="dy9-VA-eiu" firstAttribute="top" secondItem="wVO-PU-gXJ" secondAttribute="top" constant="12" id="9xd-i0-ns0"/>
+                            <constraint firstItem="pMp-Fa-WxS" firstAttribute="centerY" secondItem="UMu-rh-fKg" secondAttribute="centerY" id="Aco-Kv-llh"/>
+                            <constraint firstItem="pMp-Fa-WxS" firstAttribute="leading" secondItem="UMu-rh-fKg" secondAttribute="trailing" constant="2" id="D7D-IT-PsW"/>
+                            <constraint firstItem="hQh-fY-QGG" firstAttribute="top" secondItem="H34-rn-KTf" secondAttribute="top" id="JCY-y9-xpg"/>
+                            <constraint firstAttribute="trailing" secondItem="1Ol-S1-0uy" secondAttribute="trailing" constant="12" id="QHO-GJ-PWT"/>
+                            <constraint firstItem="UMu-rh-fKg" firstAttribute="leading" secondItem="H34-rn-KTf" secondAttribute="trailing" constant="11" id="Qmv-DU-ZYM"/>
+                            <constraint firstItem="1Ol-S1-0uy" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="dy9-VA-eiu" secondAttribute="trailing" constant="10" id="UFV-EE-oA1"/>
+                            <constraint firstItem="dy9-VA-eiu" firstAttribute="leading" secondItem="wVO-PU-gXJ" secondAttribute="leading" constant="12" id="VEF-5y-R1e"/>
+                            <constraint firstItem="1Ol-S1-0uy" firstAttribute="top" secondItem="wVO-PU-gXJ" secondAttribute="top" constant="12" id="WKU-QV-WGl"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="pMp-Fa-WxS" secondAttribute="trailing" constant="12" id="bQe-YL-cUT"/>
+                            <constraint firstItem="vge-mo-L76" firstAttribute="centerY" secondItem="hQh-fY-QGG" secondAttribute="centerY" id="caQ-vi-RYp"/>
+                            <constraint firstItem="H34-rn-KTf" firstAttribute="top" secondItem="dy9-VA-eiu" secondAttribute="bottom" constant="8" id="eAK-e9-KFp"/>
+                            <constraint firstItem="vge-mo-L76" firstAttribute="leading" secondItem="hQh-fY-QGG" secondAttribute="trailing" constant="5" id="hnf-Ts-Avn"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="vge-mo-L76" secondAttribute="trailing" constant="12" id="uuM-Oj-f5J"/>
+                            <constraint firstItem="UMu-rh-fKg" firstAttribute="bottom" secondItem="H34-rn-KTf" secondAttribute="bottom" constant="-2" id="wLG-6O-Nv3"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="10"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="trailing" secondItem="wVO-PU-gXJ" secondAttribute="trailing" constant="14" id="1ii-QB-Vkc"/>
+                    <constraint firstItem="wVO-PU-gXJ" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="JO7-me-hyT"/>
+                    <constraint firstItem="wVO-PU-gXJ" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="sNQ-Ok-pa8"/>
+                    <constraint firstAttribute="bottom" secondItem="wVO-PU-gXJ" secondAttribute="bottom" constant="12" id="tIB-nf-OP6"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <connections>
+                <outlet property="courseDesc" destination="pMp-Fa-WxS" id="4fb-Q2-fAR"/>
+                <outlet property="courseGroupName" destination="dy9-VA-eiu" id="FHM-97-lzy"/>
+                <outlet property="courseStudents" destination="hQh-fY-QGG" id="Epo-eU-D0S"/>
+                <outlet property="statusLabel" destination="1Ol-S1-0uy" id="snf-BD-ZBZ"/>
+                <outlet property="subjectLabel" destination="HuW-TI-Qg2" id="W8c-3O-Eva"/>
+            </connections>
+            <point key="canvasLocation" x="33.587786259541986" y="57.74647887323944"/>
+        </tableViewCell>
+    </objects>
+    <resources>
+        <image name="arrange_course_icon" width="12" height="14"/>
+        <image name="course_musicRoom" width="40" height="40"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicRoomCourseGroupView.h

@@ -0,0 +1,18 @@
+//
+//  MyMusicRoomCourseGroupView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "KSJXBodyView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyMusicRoomCourseGroupView : KSJXBodyView
+
+@property (nonatomic, strong) NSMutableArray *subjectList;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 354 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MusicRoomCourseGroup/MyMusicRoomCourseGroupView.m

@@ -0,0 +1,354 @@
+//
+//  MyMusicRoomCourseGroupView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyMusicRoomCourseGroupView.h"
+#import "MyCourseSearchView.h"
+#import "MyMusicGroupListCell.h"
+#import "StateView.h"
+#import "Reachability.h"
+#import "ProgramCourseGroupModel.h"
+#import "MyCourseRankSortView.h"
+
+@interface MyMusicRoomCourseGroupView ()<UITableViewDelegate,UITableViewDataSource>
+
+@property (nonatomic, assign) BOOL isLoadMore;
+@property (nonatomic, assign) NSInteger rows;
+@property (nonatomic, assign) NSInteger pages;
+
+@property (nonatomic, strong) NSMutableArray *dataArray;
+
+@property (nonatomic, strong) StateView *promptView;
+@property (nonatomic, strong) UIView *promptPlaceView;
+
+@property (nonatomic, assign) BOOL networkAvaiable; // 网络是否可用
+
+@property (nonatomic, strong) MyCourseSearchView *searchView;
+
+@property (nonatomic, strong) NSString *searchKey;
+
+@property (nonatomic, strong) NSString *subjectId;
+
+@property (nonatomic, strong) NSString *status;
+
+@property (nonatomic, assign) NSInteger subjectChooseIndex;
+
+@property (nonatomic, assign) NSInteger statusChooseIndex;
+
+@property (nonatomic, strong) MyCourseRankSortView *sortView;
+
+@property (nonatomic, strong) NSMutableArray *statusArray;
+
+@end
+
+@implementation MyMusicRoomCourseGroupView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) style:UITableViewStylePlain];
+        self.tableView.backgroundColor = [UIColor clearColor];
+        self.tableView.showsVerticalScrollIndicator = NO;
+        
+        self.tableView.dataSource = self;
+        self.tableView.delegate = self;
+        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+        [self addSubview:self.tableView];
+        self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        [self.tableView registerNib:[UINib nibWithNibName:@"MyMusicGroupListCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MyMusicGroupListCell"];
+
+        UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, iPhoneXSafeBottomMargin)];
+        bottomView.backgroundColor = [UIColor clearColor];
+        self.tableView.tableFooterView = bottomView;
+        
+        MJWeakSelf;
+        self.tableView.mj_header = [KSGifRefreshHeader headerWithRefreshingBlock:^{
+            [weakSelf resetParamenter];
+            [weakSelf requestData];
+        }];
+        self.tableView.mj_footer = [KSGifRefreshFooter footerWithRefreshingBlock:^{
+            if (weakSelf.isLoadMore) {
+                weakSelf.pages += 1;
+                [weakSelf requestData];
+            }
+            else {
+                [weakSelf.tableView.mj_footer endRefreshingWithNoMoreData];
+            }
+        }];
+    }
+    return self;
+}
+
+- (void)refreshAndRequestData {
+    [self resetParamenter];
+    [self requestData];
+}
+
+- (void)resetParamenter {
+    self.isLoadMore = YES;
+    self.pages = 1;
+    self.rows = 10;
+    self.dataArray = [NSMutableArray array];
+    [self.tableView.mj_footer resetNoMoreData];
+    [self setPromptString:@"暂无内容" imageName:@"empty_course" inView:self.tableView];
+    [self.tableView reloadData];
+}
+
+- (void)endRefresh {
+    @weakObj(self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        @strongObj(self);
+        [self.tableView.mj_header endRefreshing];
+        [self.tableView.mj_footer endRefreshing];
+    });
+}
+
+
+- (void)requestData {
+    [KSNetworkingManager myCourseGroupRequest:KS_POST courseType:@"PIANO_ROOM_CLASS" search:self.searchKey subjectId:self.subjectId status:self.status success:^(NSDictionary * _Nonnull dic) {
+        [self endRefresh];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [[dic ks_dictionaryValueForKey:@"data"] ks_arrayValueForKey:@"rows"];
+            for (NSDictionary *parm in sourceArray) {
+                ProgramCourseGroupModel *model = [[ProgramCourseGroupModel alloc] initWithDictionary:parm];
+                [self.dataArray addObject:model];
+            }
+            if (sourceArray.count < self.rows) {
+                self.isLoadMore = NO;
+            }
+        }
+        else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
+        }
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    } faliure:^(NSError * _Nonnull error) {
+        [self endRefresh];
+        if (self.networkAvaiable == NO) {
+            [self setPromptString:@"暂无网络" imageName:@"no_networking" inView:self.tableView];
+        }
+        [self.dataArray removeAllObjects];
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    }];
+}
+
+- (void)beginRefreshImmediately {
+    [self.tableView.mj_header beginRefreshing];
+}
+
+- (void)beginFirstRefresh {
+    if (!self.isHeaderRefreshed) {
+        [self beginRefreshImmediately];
+    }
+}
+- (void)selectCellAtIndexPath:(NSIndexPath *)indexPath {
+    
+    if (self.lastSelectedIndexPath == indexPath) {
+        return;
+    }
+    if (self.lastSelectedIndexPath != nil) {
+        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.lastSelectedIndexPath];
+        [cell setSelected:NO animated:NO];
+    }
+    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+    [cell setSelected:YES animated:NO];
+    self.lastSelectedIndexPath = indexPath;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat searchViewHeight = [MyCourseSearchView getViewHeight];
+
+    if (![self.subviews containsObject:self.searchView]) {
+        [self addSubview:self.searchView];
+        [self.searchView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.mas_equalTo(self);
+            make.height.mas_equalTo(searchViewHeight);
+        }];
+    }
+
+    [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.bottom.mas_equalTo(self);
+        make.top.mas_equalTo(self.searchView.mas_bottom);
+    }];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 106.0f;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    ProgramCourseGroupModel *model = self.dataArray[indexPath.row];
+    MyMusicGroupListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyMusicGroupListCell"];
+    [cell configWithSource:model];
+    return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    // 课程组详情
+    
+}
+
+#pragma mark ------ lazying
+- (MyCourseSearchView *)searchView {
+    if (!_searchView) {
+        _searchView = [MyCourseSearchView sharedInstance];
+        MJWeakSelf;
+        [_searchView searchActionCallback:^(MY_COURSE_SORT type, NSString * _Nullable searchKey) {
+            [weakSelf searchAction:type searchKey:searchKey];
+        }];
+    }
+    return _searchView;
+}
+
+- (void)searchAction:(MY_COURSE_SORT)type searchKey:(NSString *)searchKey {
+    switch (type) {
+        case MY_COURSE_SORT_RANK:
+        {
+            [self showSortView];
+        }
+            break;
+        case MY_COURSE_SORT_SEARCH:
+        {
+            [self evaluateSource:searchKey];
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)showSortView {
+    self.searchView.arrowUp = YES;
+    [self.sortView refreshUI:self.statusChooseIndex subjectId:self.subjectChooseIndex];
+    [self.sortView showInView:[NSObject getKeyWindow]];
+}
+
+
+- (void)evaluateSource:(NSString *)searchKey {
+    self.searchKey = searchKey;
+    [self refreshAndRequestData];
+}
+
+/**
+ 设置没有数据时的显示
+ 
+ @param promptString 提示语
+ @param imgName 图片名称
+ @param view 显示在什么地方
+ */
+- (void)setPromptString:(NSString *)promptString imageName:(NSString *)imgName inView:(UIView *)view {
+    if (self.promptView != nil) {
+        [self.promptView removeFromSuperview];
+    }
+    else {
+        self.promptView = [[StateView alloc]init];
+        self.promptView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight - 300);
+    }
+    _promptPlaceView = view;
+    //当请求不到数据时 ,自定义提示view 将会出现;
+    self.promptView.imageName = imgName;
+    self.promptView.alpha = 0.0f;
+    [self.promptView setText:promptString];
+    [view addSubview:self.promptView];
+}
+
+// 结束刷新后调用方法
+- (void)changePromptLabelStateWithArray:(NSMutableArray *)array {
+    NSInteger count;
+    if (array.count) {
+        count = array.count;
+    } else {
+        count = 0;
+    }
+    
+    [UIView animateWithDuration:0.1 animations:^{
+        [[self promptView] setAlpha:count ? 0.0f :1.0f ] ;
+    }] ;
+    
+}
+
+- (BOOL)networkAvaiable {
+    return [self checkNetworkAvaiable];
+}
+
+- (BOOL)checkNetworkAvaiable {
+    BOOL isExistenceNetwork = YES;
+    Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
+    switch ([reach currentReachabilityStatus]) {
+        case NotReachable:
+            isExistenceNetwork = NO;
+            //NSLog(@"notReachable");
+            break;
+        case ReachableViaWiFi:
+            isExistenceNetwork = YES;
+            //NSLog(@"WIFI");
+            break;
+        case ReachableViaWWAN:
+            isExistenceNetwork = YES;
+            //NSLog(@"3G");
+            break;
+    }
+    return isExistenceNetwork;
+}
+
+- (MyCourseRankSortView *)sortView {
+    if (!_sortView) {
+        _sortView = [MyCourseRankSortView sharedInstance];
+        [_sortView configWithStatusArray:self.statusArray subjectArray:self.subjectList];
+        MJWeakSelf;
+        [_sortView sortActionCallback:^(MY_COURSE_SORTTYPE type, NSString * _Nullable status, NSString * _Nullable subjectId, NSInteger statusIndex, NSInteger subjectIndex) {
+            [weakSelf sortActionWithType:type status:status subjectId:subjectId statusChooseIndex:statusIndex subjectChooseIndex:subjectIndex];
+        }];
+    }
+    return _sortView;
+}
+
+- (void)sortActionWithType:(MY_COURSE_SORTTYPE)type status:(NSString *)status subjectId:(NSString *)subjectId statusChooseIndex:(NSInteger)statusChooseIndex subjectChooseIndex:(NSInteger)subjectChooseIndex  {
+    self.searchView.arrowUp = NO;
+    if (type == MY_COURSE_SORTTYPE_SORT) {
+        self.statusChooseIndex = statusChooseIndex;
+        self.subjectChooseIndex = subjectChooseIndex;
+        self.status = status;
+        self.subjectId = subjectId;
+        if ([NSString isEmptyString:status]) {
+            self.status = nil;
+        }
+        if ([NSString isEmptyString:subjectId]) {
+            self.subjectId = nil;
+        }
+        [self refreshAndRequestData];
+    }
+}
+
+- (NSMutableArray *)statusArray {
+    if (!_statusArray) {
+        _statusArray = [NSMutableArray arrayWithArray:@[@{@"name":@"全部",@"id":@""},@{@"name":@"未开课",@"id":@"NOT_START"},@{@"name":@"已开课",@"id":@"ING"},@{@"name":@"已结课",@"id":@"COMPLETE"}]];
+    }
+    return _statusArray;
+}
+
+- (void)setSubjectList:(NSMutableArray *)subjectList {
+    NSMutableArray *array = [NSMutableArray arrayWithArray:subjectList];
+    [array insertObject:@{@"name":@"全部",@"id":@""} atIndex:0];
+    _subjectList = array;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 24 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseGroupNavView.h

@@ -0,0 +1,24 @@
+//
+//  MyCourseGroupNavView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef void(^MyCourseNavCallback)(BOOL isBack);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyCourseGroupNavView : UIView
+
++ (instancetype)sharedInstance;
+
+- (void)navAction:(MyCourseNavCallback)callback;
+
++ (CGFloat)getViewHeight;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 54 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseGroupNavView.m

@@ -0,0 +1,54 @@
+//
+//  MyCourseGroupNavView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyCourseGroupNavView.h"
+
+@interface MyCourseGroupNavView ()
+
+@property (nonatomic, copy) MyCourseNavCallback callback;
+
+@end
+
+@implementation MyCourseGroupNavView
+
++ (instancetype)sharedInstance {
+    MyCourseGroupNavView *view = [[[NSBundle mainBundle] loadNibNamed:@"MyCourseGroupNavView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)navAction:(MyCourseNavCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+}
+
+- (IBAction)backAction:(id)sender {
+    if (self.callback) {
+        self.callback(YES);
+    }
+}
+
+- (IBAction)showTips:(id)sender {
+    if (self.callback) {
+        self.callback(NO);
+    }
+}
+
+
+
++ (CGFloat)getViewHeight {
+    return kNaviBarHeight;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 86 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseGroupNavView.xib

@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="MyCourseGroupNavView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="85"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="boo-Uv-klO">
+                    <rect key="frame" x="0.0" y="41" width="393" height="44"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="back_black" translatesAutoresizingMaskIntoConstraints="NO" id="lME-kR-y32">
+                            <rect key="frame" x="15" y="12" width="12" height="20"/>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZQy-2D-h6w">
+                            <rect key="frame" x="0.0" y="0.0" width="44" height="44"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="44" id="w9i-XK-uls"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="backAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="KYl-xW-s4f"/>
+                            </connections>
+                        </button>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我的课程" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="98I-jh-ZtZ">
+                            <rect key="frame" x="160.66666666666666" y="11" width="71.666666666666657" height="22"/>
+                            <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
+                            <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="program_tips" translatesAutoresizingMaskIntoConstraints="NO" id="cd4-ry-QF5">
+                            <rect key="frame" x="359" y="12" width="20" height="20"/>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2NZ-5x-aXa">
+                            <rect key="frame" x="349" y="0.0" width="44" height="44"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="44" id="PzE-Li-O3n"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="showTips:" destination="iN0-l3-epB" eventType="touchUpInside" id="bZ4-N4-jqD"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="98I-jh-ZtZ" firstAttribute="centerX" secondItem="boo-Uv-klO" secondAttribute="centerX" id="4tB-jZ-AdF"/>
+                        <constraint firstAttribute="bottom" secondItem="2NZ-5x-aXa" secondAttribute="bottom" id="HDe-1V-kAD"/>
+                        <constraint firstItem="98I-jh-ZtZ" firstAttribute="centerY" secondItem="boo-Uv-klO" secondAttribute="centerY" id="Pvy-mZ-sFV"/>
+                        <constraint firstItem="ZQy-2D-h6w" firstAttribute="leading" secondItem="boo-Uv-klO" secondAttribute="leading" id="RwT-Sy-l8Y"/>
+                        <constraint firstItem="2NZ-5x-aXa" firstAttribute="top" secondItem="boo-Uv-klO" secondAttribute="top" id="TsK-67-A91"/>
+                        <constraint firstItem="lME-kR-y32" firstAttribute="centerY" secondItem="boo-Uv-klO" secondAttribute="centerY" id="VCd-jy-Kac"/>
+                        <constraint firstAttribute="trailing" secondItem="cd4-ry-QF5" secondAttribute="trailing" constant="14" id="kQN-fo-WaD"/>
+                        <constraint firstItem="lME-kR-y32" firstAttribute="leading" secondItem="boo-Uv-klO" secondAttribute="leading" constant="15" id="kU9-EE-M9h"/>
+                        <constraint firstAttribute="height" constant="44" id="laL-1y-8Ft"/>
+                        <constraint firstAttribute="bottom" secondItem="ZQy-2D-h6w" secondAttribute="bottom" id="lwF-uW-uUV"/>
+                        <constraint firstAttribute="trailing" secondItem="2NZ-5x-aXa" secondAttribute="trailing" id="n7o-en-OzA"/>
+                        <constraint firstItem="ZQy-2D-h6w" firstAttribute="top" secondItem="boo-Uv-klO" secondAttribute="top" id="pW2-IL-fwr"/>
+                        <constraint firstItem="cd4-ry-QF5" firstAttribute="centerY" secondItem="boo-Uv-klO" secondAttribute="centerY" id="vns-at-f0e"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstAttribute="bottom" secondItem="boo-Uv-klO" secondAttribute="bottom" id="hmX-5v-XW9"/>
+                <constraint firstAttribute="trailing" secondItem="boo-Uv-klO" secondAttribute="trailing" id="j6u-s5-T4c"/>
+                <constraint firstItem="boo-Uv-klO" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="vnd-3J-BBM"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <point key="canvasLocation" x="32.824427480916029" y="120.07042253521128"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="back_black" width="12" height="20"/>
+        <image name="program_tips" width="20" height="20"/>
+    </resources>
+</document>

+ 33 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseRankSortView.h

@@ -0,0 +1,33 @@
+//
+//  MyCourseRankSortView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/21.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSInteger, MY_COURSE_SORTTYPE) {
+    MY_COURSE_SORTTYPE_HIDE,
+    MY_COURSE_SORTTYPE_SORT,
+};
+
+typedef void(^MyCourseSortTypeCallback)(MY_COURSE_SORTTYPE type, NSString * _Nullable status, NSString * _Nullable subjectId, NSInteger statusIndex, NSInteger subjectIndex);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyCourseRankSortView : UIView
+
++ (instancetype)sharedInstance;
+
+- (void)configWithStatusArray:(NSMutableArray *)statusArray subjectArray:(NSMutableArray *)subjectArray;
+
+- (void)refreshUI:(NSInteger)statusIndex subjectId:(NSInteger)subjectIndex;
+
+- (void)sortActionCallback:(MyCourseSortTypeCallback)callback;
+
+- (void)showInView:(UIView *)displayView;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 338 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseRankSortView.m

@@ -0,0 +1,338 @@
+//
+//  MyCourseRankSortView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/21.
+//
+
+#import "MyCourseRankSortView.h"
+#import "MyCourseSearchView.h"
+
+@interface MyCourseRankSortView ()<UIScrollViewDelegate,UIGestureRecognizerDelegate>
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topSpace;
+
+@property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
+
+@property (weak, nonatomic) IBOutlet UIView *containerView;
+
+@property (weak, nonatomic) IBOutlet UIView *sortButtonContainer;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *sortContainerHeight;
+
+@property (nonatomic, copy) MyCourseSortTypeCallback callback;
+
+@property (nonatomic, strong) NSMutableArray *statusArray;
+
+@property (nonatomic, strong) NSMutableArray *subjectArray;
+
+@property (nonatomic, strong) UIScrollView *scrollView;
+
+@property (nonatomic, strong) NSString *status;
+
+@property (nonatomic, strong) NSString *subjectId;
+
+@property (nonatomic, assign) NSInteger statusChooseIndex; // 状态
+
+@property (nonatomic, assign) NSInteger subjectChooseIndex; // 声部id
+
+@end
+
+@implementation MyCourseRankSortView
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    self.containerView.layer.cornerRadius = 20.0f;
+    self.containerView.layer.maskedCorners = kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner;
+    [self.sortButtonContainer addSubview:self.scrollView];
+    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.bottom.left.right.mas_equalTo(self.sortButtonContainer);
+    }];
+    self.statusChooseIndex = 1000;
+    self.subjectChooseIndex = 2000;
+    self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
+    [self addGestureRecognizer:self.tapGesture];
+    self.tapGesture.delegate = self;
+    self.topSpace.constant = kNaviBarHeight + 44 + [MyCourseSearchView getViewHeight];
+}
+
+
++ (instancetype)sharedInstance {
+    MyCourseRankSortView *view = [[[NSBundle mainBundle] loadNibNamed:@"MyCourseRankSortView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithStatusArray:(NSMutableArray *)statusArray subjectArray:(NSMutableArray *)subjectArray {
+    self.statusArray = [statusArray mutableCopy];
+    self.subjectArray = [subjectArray mutableCopy];
+}
+
+- (void)refreshUI:(NSInteger)statusIndex subjectId:(NSInteger)subjectIndex {
+    self.statusChooseIndex = statusIndex;
+    self.subjectChooseIndex = subjectIndex;
+    
+    if (statusIndex == 0) {
+        self.statusChooseIndex = 1000;
+    }
+    if (subjectIndex == 0) {
+        self.subjectChooseIndex = 2000;
+    }
+    
+    [self configUI];
+}
+
+- (void)configUI {
+    [self.scrollView removeAllSubViews];
+    CGFloat topHeight = 0.0f;
+    
+    CGFloat midSpace = 9.0f;
+    CGFloat leftSpace = 14.0f;
+    CGFloat topSpace = 9.0f;
+    CGFloat buttonHeight = 32.0f;
+
+    // 添加课程状态数据
+    if (self.statusArray.count) {
+        topHeight += 24.0f;
+        UIView *statusLineView = [[UIView alloc] init];
+        [self.scrollView addSubview:statusLineView];
+        statusLineView.backgroundColor = THEMECOLOR;
+        statusLineView.layer.cornerRadius = 2.0f;
+        [statusLineView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.mas_equalTo(self.sortButtonContainer.mas_left).offset(16);
+            make.top.mas_equalTo(self.scrollView.mas_top).offset(topHeight);
+            make.width.mas_equalTo(4);
+            make.height.mas_equalTo(11);
+        }];
+        UILabel *statusLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+        statusLabel.textColor = HexRGB(0x333333);
+        statusLabel.text = @"课程状态";
+        statusLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightMedium];
+        [self.scrollView addSubview:statusLabel];
+        [statusLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.mas_equalTo(statusLineView.mas_right).offset(6);
+            make.height.mas_equalTo(22);
+            make.centerY.mas_equalTo(statusLineView.mas_centerY);
+        }];
+        topHeight += 16.0f;
+        
+        
+        CGFloat buttonWidth = (KPortraitWidth - leftSpace * 2 - midSpace * 3) / 4.0f;
+
+        for (NSInteger index = 0; index < self.statusArray.count; index++) {
+            CGFloat xSpace = leftSpace + (buttonWidth + midSpace) * (index % 4);
+            CGFloat ySpace = topSpace + (buttonHeight + topSpace) * (index / 4);
+            
+            NSDictionary *parm = self.statusArray[index];
+            NSString *title = [parm ks_stringValueForKey:@"name"];
+            UIButton *button = [self createButton:1000+index buttonTitle:title];
+            [self.scrollView addSubview:button];
+            if (self.statusChooseIndex == 1000 + index) {
+                [self modifyButtonStatus:YES buttonIndex:1000+index];
+                self.status = [parm ks_stringValueForKey:@"id"];
+            }
+            [button mas_makeConstraints:^(MASConstraintMaker *make) {
+                make.left.mas_equalTo(self.sortButtonContainer.mas_left).offset(xSpace);
+                make.width.mas_equalTo(buttonWidth);
+                make.height.mas_equalTo(buttonHeight);
+                make.top.mas_equalTo(statusLabel.mas_bottom).offset(ySpace);
+            }];
+            // 增加行高
+            if (index % 4 == 0) {
+                topHeight += (buttonHeight + topSpace);
+            }
+        }
+    }
+    
+    if (self.subjectArray) {
+        topHeight += 24.0;
+        UIView *lineView = [[UIView alloc] init];
+        [self.scrollView addSubview:lineView];
+        lineView.backgroundColor = THEMECOLOR;
+        lineView.layer.cornerRadius = 2.0f;
+        [lineView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.mas_equalTo(self.sortButtonContainer.mas_left).offset(16);
+            make.top.mas_equalTo(self.scrollView.mas_top).offset(topHeight);
+            make.width.mas_equalTo(4);
+            make.height.mas_equalTo(11);
+        }];
+        UILabel *subjectLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+        subjectLabel.textColor = HexRGB(0x333333);
+        subjectLabel.text = @"声部";
+        subjectLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightMedium];
+        [self.scrollView addSubview:subjectLabel];
+        [subjectLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.mas_equalTo(lineView.mas_right).offset(6);
+            make.height.mas_equalTo(22);
+            make.centerY.mas_equalTo(lineView.mas_centerY);
+        }];
+        topHeight += 16.0f;
+        
+        CGFloat buttonWidth = (KPortraitWidth - leftSpace * 2 - midSpace * 2) / 3.0f;
+
+        for (NSInteger index = 0; index < self.subjectArray.count; index++) {
+            CGFloat xSpace = leftSpace + (buttonWidth + midSpace) * (index % 3);
+            CGFloat ySpace = topSpace + (buttonHeight + topSpace) * (index / 3);
+            
+            NSDictionary *parm = self.subjectArray[index];
+            NSString *title = [parm ks_stringValueForKey:@"name"];
+            UIButton *button = [self createButton:2000+index buttonTitle:title];
+            [self.scrollView addSubview:button];
+            if (self.subjectChooseIndex == 2000 + index) {
+                [self modifyButtonStatus:YES buttonIndex:2000+index];
+                self.subjectId = [parm ks_stringValueForKey:@"id"];
+            }
+            [button mas_makeConstraints:^(MASConstraintMaker *make) {
+                make.left.mas_equalTo(self.sortButtonContainer.mas_left).offset(xSpace);
+                make.width.mas_equalTo(buttonWidth);
+                make.height.mas_equalTo(buttonHeight);
+                make.top.mas_equalTo(subjectLabel.mas_bottom).offset(ySpace);
+            }];
+            // 增加行高
+            if (index % 3 == 0) {
+                topHeight += (buttonHeight + topSpace);
+            }
+        }
+        topHeight += 18; // 底部区域
+    }
+    if (topHeight > 303) {
+        topHeight = 303.0f;
+    }
+    self.sortContainerHeight.constant = topHeight;
+}
+
+- (void)sortActionCallback:(MyCourseSortTypeCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+}
+
+
+- (void)showInView:(UIView *)displayView {
+    if (![displayView.subviews containsObject:self]) {
+        [displayView addSubview:self];
+        [self mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.bottom.mas_equalTo(displayView);
+        }];
+    }
+}
+
+- (void)resetAllChoose {
+    if (self.statusChooseIndex != 0) {
+        [self modifyButtonStatus:NO buttonIndex:self.statusChooseIndex];
+        self.statusChooseIndex = 1000;
+        [self modifyButtonStatus:YES buttonIndex:self.statusChooseIndex];
+    }
+    
+    if (self.subjectChooseIndex != 0) {
+        [self modifyButtonStatus:NO buttonIndex:self.subjectChooseIndex];
+        self.subjectChooseIndex = 2000;
+        [self modifyButtonStatus:YES buttonIndex:self.subjectChooseIndex];
+    }
+    self.status = nil;
+    self.subjectId = nil;
+}
+
+- (void)hideView {
+    [self removeFromSuperview];
+}
+
+- (void)tapAction:(id)sender {
+    [self hideView];
+    if (self.callback) {
+        self.callback(MY_COURSE_SORTTYPE_HIDE, self.status, self.subjectId,self.statusChooseIndex , self.subjectChooseIndex);
+    }
+}
+
+- (IBAction)resetAction:(id)sender {
+    [self resetAllChoose];
+}
+
+- (IBAction)sureAction:(id)sender {
+    [self hideView];
+    if (self.callback) {
+        self.callback(MY_COURSE_SORTTYPE_SORT, self.status, self.subjectId, self.statusChooseIndex, self.subjectChooseIndex);
+    }
+}
+
+
+#pragma mark ----- lazying
+- (UIScrollView *)scrollView {
+    if (!_scrollView) {
+        _scrollView = [[UIScrollView alloc] init];
+        _scrollView.delegate = self;
+        _scrollView.pagingEnabled = YES;
+        _scrollView.bounces = NO;
+        _scrollView.backgroundColor = [UIColor clearColor];
+        _scrollView.showsHorizontalScrollIndicator = NO;
+        _scrollView.showsVerticalScrollIndicator = NO;
+    }
+    return _scrollView;
+}
+
+- (UIButton *)createButton:(NSInteger)tag buttonTitle:(NSString *)buttonTitle {
+    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
+    button.tag = tag;
+    button.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5);
+    [button setTitle:buttonTitle forState:UIControlStateNormal];
+    [button.titleLabel setFont:[UIFont systemFontOfSize:13.0f weight:UIFontWeightRegular]];
+    button.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
+    [button setTitleColor:HexRGB(0x999999) forState:UIControlStateNormal];
+    [button addTarget:self action:@selector(buttonClickAction:) forControlEvents:UIControlEventTouchUpInside];
+    button.layer.cornerRadius =  4.0f;
+    button.backgroundColor = HexRGB(0xF8F8F8);
+    button.layer.borderWidth = 1.0f;
+    button.layer.borderColor = [UIColor clearColor].CGColor;
+    return button;
+}
+
+- (void)buttonClickAction:(UIButton *)sender {
+    if (sender.tag >= 1000 && sender.tag < 2000) { // 状态
+        
+        if (self.statusChooseIndex != sender.tag) {
+            [self modifyButtonStatus:NO buttonIndex:self.statusChooseIndex];
+            [self modifyButtonStatus:YES buttonIndex:sender.tag];
+            self.statusChooseIndex = sender.tag;
+            NSDictionary *parm = self.statusArray[self.statusChooseIndex-1000];
+            self.status = [parm ks_stringValueForKey:@"id"];
+        }
+    }
+    else if (sender.tag >= 2000 && sender.tag < 3000) { // 声部
+        if (self.subjectChooseIndex != sender.tag) {
+            [self modifyButtonStatus:NO buttonIndex:self.subjectChooseIndex];
+            [self modifyButtonStatus:YES buttonIndex:sender.tag];
+            self.subjectChooseIndex = sender.tag;
+            NSDictionary *parm = self.subjectArray[self.subjectChooseIndex-2000];
+            self.subjectId = [parm ks_stringValueForKey:@"id"];
+        }
+    }
+}
+
+- (void)modifyButtonStatus:(BOOL)isChoose buttonIndex:(NSInteger)buttonIndex {
+    UIButton *button = (UIButton *)[self.scrollView viewWithTag:buttonIndex];
+    if (isChoose) {
+        [button setBackgroundColor:HexRGB(0xE9FFF8)];
+        [button setTitleColor:HexRGB(0x2DC7AA) forState:UIControlStateNormal];
+        button.layer.borderColor = HexRGB(0x2DC7AA).CGColor;
+    }
+    else {
+        [button setBackgroundColor:HexRGB(0xF8F8F8)];
+        [button setTitleColor:HexRGB(0x999999) forState:UIControlStateNormal];
+        button.layer.borderColor = [UIColor clearColor].CGColor;
+    }
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
+    if ([touch.view isDescendantOfView:self.containerView]) {
+        return NO;
+    }
+    return YES;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 140 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseRankSortView.xib

@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="MyCourseRankSortView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4cU-Yc-xQ4">
+                    <rect key="frame" x="0.0" y="522" width="393" height="330"/>
+                    <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DGd-qK-ni7">
+                    <rect key="frame" x="0.0" y="160" width="393" height="382"/>
+                    <subviews>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ezp-zR-evZ">
+                            <rect key="frame" x="0.0" y="300" width="393" height="82"/>
+                            <subviews>
+                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gfc-W3-txU">
+                                    <rect key="frame" x="0.0" y="0.0" width="393" height="1"/>
+                                    <color key="backgroundColor" red="0.94901960784313721" green="0.94901960784313721" blue="0.94901960784313721" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="1" id="kav-ju-hw2"/>
+                                    </constraints>
+                                </view>
+                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Z2o-te-Oi9">
+                                    <rect key="frame" x="13" y="21" width="176" height="44"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="44" id="amB-tc-E8X"/>
+                                    </constraints>
+                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                                    <state key="normal" title="重置">
+                                        <color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                    </state>
+                                    <userDefinedRuntimeAttributes>
+                                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                            <real key="value" value="22"/>
+                                        </userDefinedRuntimeAttribute>
+                                        <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                            <real key="value" value="1"/>
+                                        </userDefinedRuntimeAttribute>
+                                        <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                            <color key="value" red="0.85882352941176465" green="0.85882352941176465" blue="0.85882352941176465" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        </userDefinedRuntimeAttribute>
+                                    </userDefinedRuntimeAttributes>
+                                    <connections>
+                                        <action selector="resetAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="RCf-7h-QJ1"/>
+                                    </connections>
+                                </button>
+                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="b8q-UA-MQi">
+                                    <rect key="frame" x="204" y="21" width="176" height="44"/>
+                                    <color key="backgroundColor" red="0.1764705882352941" green="0.7803921568627451" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
+                                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                                    <state key="normal" title="确认"/>
+                                    <userDefinedRuntimeAttributes>
+                                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                            <real key="value" value="22"/>
+                                        </userDefinedRuntimeAttribute>
+                                    </userDefinedRuntimeAttributes>
+                                    <connections>
+                                        <action selector="sureAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="yOG-yx-r2y"/>
+                                    </connections>
+                                </button>
+                            </subviews>
+                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstItem="b8q-UA-MQi" firstAttribute="centerY" secondItem="Z2o-te-Oi9" secondAttribute="centerY" id="3xH-Gk-irg"/>
+                                <constraint firstAttribute="trailing" secondItem="Gfc-W3-txU" secondAttribute="trailing" id="9sB-nY-Cyp"/>
+                                <constraint firstItem="b8q-UA-MQi" firstAttribute="leading" secondItem="Z2o-te-Oi9" secondAttribute="trailing" constant="15" id="K0h-tS-FfS"/>
+                                <constraint firstAttribute="trailing" secondItem="b8q-UA-MQi" secondAttribute="trailing" constant="13" id="KgJ-A0-cG3"/>
+                                <constraint firstAttribute="height" constant="82" id="LQe-1g-eN8"/>
+                                <constraint firstItem="b8q-UA-MQi" firstAttribute="width" secondItem="Z2o-te-Oi9" secondAttribute="width" id="MYf-N3-2qm"/>
+                                <constraint firstItem="Z2o-te-Oi9" firstAttribute="top" secondItem="Gfc-W3-txU" secondAttribute="bottom" constant="20" id="XE5-Af-9Ni"/>
+                                <constraint firstItem="Gfc-W3-txU" firstAttribute="leading" secondItem="Ezp-zR-evZ" secondAttribute="leading" id="Xtd-Gh-kcD"/>
+                                <constraint firstItem="b8q-UA-MQi" firstAttribute="height" secondItem="Z2o-te-Oi9" secondAttribute="height" id="dxj-Gn-BGe"/>
+                                <constraint firstItem="Gfc-W3-txU" firstAttribute="top" secondItem="Ezp-zR-evZ" secondAttribute="top" id="ocy-qs-mM1"/>
+                                <constraint firstItem="Z2o-te-Oi9" firstAttribute="leading" secondItem="Ezp-zR-evZ" secondAttribute="leading" constant="13" id="qf4-7T-0hy"/>
+                            </constraints>
+                        </view>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CQx-oG-dvA">
+                            <rect key="frame" x="0.0" y="0.0" width="393" height="300"/>
+                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="300" id="NHL-TK-Rov"/>
+                            </constraints>
+                        </view>
+                    </subviews>
+                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="CQx-oG-dvA" firstAttribute="top" secondItem="DGd-qK-ni7" secondAttribute="top" id="Aee-Ts-MVR"/>
+                        <constraint firstAttribute="trailing" secondItem="CQx-oG-dvA" secondAttribute="trailing" id="Bth-fi-V6m"/>
+                        <constraint firstItem="Ezp-zR-evZ" firstAttribute="leading" secondItem="DGd-qK-ni7" secondAttribute="leading" id="DUq-NZ-ChI"/>
+                        <constraint firstItem="Ezp-zR-evZ" firstAttribute="top" secondItem="CQx-oG-dvA" secondAttribute="bottom" id="QVM-Ba-8bF"/>
+                        <constraint firstAttribute="trailing" secondItem="Ezp-zR-evZ" secondAttribute="trailing" id="bP8-cu-2Hz"/>
+                        <constraint firstItem="CQx-oG-dvA" firstAttribute="leading" secondItem="DGd-qK-ni7" secondAttribute="leading" id="kg1-iX-KVu"/>
+                        <constraint firstAttribute="bottom" secondItem="Ezp-zR-evZ" secondAttribute="bottom" id="wIc-Xn-BZK"/>
+                    </constraints>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6Rs-lR-WaE">
+                    <rect key="frame" x="0.0" y="0.0" width="393" height="160"/>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <gestureRecognizers/>
+            <constraints>
+                <constraint firstItem="4cU-Yc-xQ4" firstAttribute="top" secondItem="DGd-qK-ni7" secondAttribute="bottom" constant="-20" id="4Kb-cW-aHR"/>
+                <constraint firstItem="DGd-qK-ni7" firstAttribute="top" secondItem="6Rs-lR-WaE" secondAttribute="bottom" id="DWI-00-zj1"/>
+                <constraint firstItem="DGd-qK-ni7" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="160" id="NpJ-u5-lsV"/>
+                <constraint firstItem="6Rs-lR-WaE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="Rni-Wj-EsN"/>
+                <constraint firstItem="6Rs-lR-WaE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="U5Z-Uc-OBk"/>
+                <constraint firstAttribute="trailing" secondItem="4cU-Yc-xQ4" secondAttribute="trailing" id="V4i-GC-Wj7"/>
+                <constraint firstItem="DGd-qK-ni7" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="ZgY-iI-Snw"/>
+                <constraint firstItem="4cU-Yc-xQ4" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="dhL-w1-pO7"/>
+                <constraint firstAttribute="bottom" secondItem="4cU-Yc-xQ4" secondAttribute="bottom" id="f8A-Ad-0em"/>
+                <constraint firstAttribute="trailing" secondItem="DGd-qK-ni7" secondAttribute="trailing" id="pEx-p2-NcO"/>
+                <constraint firstAttribute="trailing" secondItem="6Rs-lR-WaE" secondAttribute="trailing" id="zXR-UA-adp"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="containerView" destination="DGd-qK-ni7" id="F7R-ow-4Bo"/>
+                <outlet property="sortButtonContainer" destination="CQx-oG-dvA" id="L3n-Ji-hyF"/>
+                <outlet property="sortContainerHeight" destination="NHL-TK-Rov" id="rt2-f1-5lr"/>
+                <outlet property="topSpace" destination="NpJ-u5-lsV" id="MIZ-Qu-0iP"/>
+            </connections>
+            <point key="canvasLocation" x="41.984732824427482" y="19.718309859154932"/>
+        </view>
+    </objects>
+</document>

+ 31 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseSearchView.h

@@ -0,0 +1,31 @@
+//
+//  MyCourseSearchView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSInteger, MY_COURSE_SORT) {
+    MY_COURSE_SORT_RANK,
+    MY_COURSE_SORT_SEARCH,
+};
+
+typedef void(^MyCourseSortCallback)(MY_COURSE_SORT type, NSString * _Nullable searchKey);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyCourseSearchView : UIView
+
+@property (nonatomic, assign) BOOL arrowUp;
+
++ (instancetype)sharedInstance;
+
+- (void)searchActionCallback:(MyCourseSortCallback)callback;
+
++ (CGFloat)getViewHeight;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 65 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseSearchView.m

@@ -0,0 +1,65 @@
+//
+//  MyCourseSearchView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyCourseSearchView.h"
+
+@interface MyCourseSearchView ()<UITextFieldDelegate>
+
+@property (weak, nonatomic) IBOutlet UITextField *searchField;
+
+@property (nonatomic, copy) MyCourseSortCallback callback;
+
+
+@end
+
+@implementation MyCourseSearchView
+
++ (instancetype)sharedInstance {
+    MyCourseSearchView *view = [[[NSBundle mainBundle] loadNibNamed:@"MyCourseSearchView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)searchActionCallback:(MyCourseSortCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+}
+
+- (IBAction)chooseRank:(id)sender {
+    [self endEditing:YES];
+    if (self.callback) {
+        self.callback(MY_COURSE_SORT_RANK, nil);
+    }
+}
+
+- (IBAction)searchAction:(id)sender {
+    [self endEditing:YES];
+    if (self.callback) {
+        self.callback(MY_COURSE_SORT_SEARCH, self.searchField.text);
+    }
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    [self endEditing:YES];
+    if (self.callback) {
+        self.callback(MY_COURSE_SORT_SEARCH, textField.text);
+    }
+    return YES;
+}
+
++ (CGFloat)getViewHeight {
+    return 58.0f;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 129 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyCourseSortView/MyCourseSearchView.xib

@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="MyCourseSearchView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="64"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ypg-l8-Rgd">
+                    <rect key="frame" x="14" y="12" width="41" height="34"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="筛选" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JbG-oJ-9Y1">
+                            <rect key="frame" x="0.0" y="8.6666666666666679" width="28" height="17"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                            <color key="textColor" red="0.074509803920000006" green="0.078431372550000003" blue="0.08235294118" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sort_up_grey" translatesAutoresizingMaskIntoConstraints="NO" id="aG3-fG-AR8">
+                            <rect key="frame" x="32" y="14.666666666666668" width="9" height="5"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="9" id="VIv-ab-N47"/>
+                            </constraints>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CNb-m9-7cz">
+                            <rect key="frame" x="0.0" y="0.0" width="41" height="34"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="chooseRank:" destination="iN0-l3-epB" eventType="touchUpInside" id="qTC-X8-xv5"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="CNb-m9-7cz" firstAttribute="leading" secondItem="Ypg-l8-Rgd" secondAttribute="leading" id="3Ko-sR-Sfo"/>
+                        <constraint firstItem="aG3-fG-AR8" firstAttribute="centerY" secondItem="JbG-oJ-9Y1" secondAttribute="centerY" id="5Pv-pc-saN"/>
+                        <constraint firstAttribute="trailing" secondItem="CNb-m9-7cz" secondAttribute="trailing" id="AHI-d6-4bY"/>
+                        <constraint firstItem="JbG-oJ-9Y1" firstAttribute="centerY" secondItem="Ypg-l8-Rgd" secondAttribute="centerY" id="AM6-bB-BQb"/>
+                        <constraint firstAttribute="height" constant="34" id="BDR-wh-jff"/>
+                        <constraint firstItem="aG3-fG-AR8" firstAttribute="leading" secondItem="JbG-oJ-9Y1" secondAttribute="trailing" constant="4" id="GKm-Li-G2a"/>
+                        <constraint firstItem="CNb-m9-7cz" firstAttribute="top" secondItem="Ypg-l8-Rgd" secondAttribute="top" id="LqW-5k-uBk"/>
+                        <constraint firstAttribute="trailing" secondItem="aG3-fG-AR8" secondAttribute="trailing" id="oob-Rf-G6r"/>
+                        <constraint firstItem="JbG-oJ-9Y1" firstAttribute="leading" secondItem="Ypg-l8-Rgd" secondAttribute="leading" id="tiT-ut-MJE"/>
+                        <constraint firstAttribute="bottom" secondItem="CNb-m9-7cz" secondAttribute="bottom" id="w2y-M0-GGk"/>
+                    </constraints>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="afT-Br-uER">
+                    <rect key="frame" x="67" y="12" width="312" height="34"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="search_green" translatesAutoresizingMaskIntoConstraints="NO" id="TDe-Bu-KkR">
+                            <rect key="frame" x="12" y="9" width="16" height="16"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="16" id="dva-6g-68u"/>
+                                <constraint firstAttribute="width" constant="16" id="vS0-WG-a1n"/>
+                            </constraints>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CM2-S3-m7O">
+                            <rect key="frame" x="253" y="3" width="56" height="28"/>
+                            <color key="backgroundColor" red="0.1764705882" green="0.78039215689999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="28" id="JIY-oi-nMf"/>
+                                <constraint firstAttribute="width" constant="56" id="PIP-R2-4Sh"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" title="搜索"/>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="14"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                            <connections>
+                                <action selector="searchAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="ouv-ni-pJU"/>
+                            </connections>
+                        </button>
+                        <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入搜索关键词" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="ZbY-Gz-MYd">
+                            <rect key="frame" x="34" y="0.0" width="207" height="34"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                            <textInputTraits key="textInputTraits"/>
+                        </textField>
+                    </subviews>
+                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="ZbY-Gz-MYd" firstAttribute="top" secondItem="afT-Br-uER" secondAttribute="top" id="7sA-K4-RGK"/>
+                        <constraint firstItem="TDe-Bu-KkR" firstAttribute="centerY" secondItem="afT-Br-uER" secondAttribute="centerY" id="G55-Ie-9Rm"/>
+                        <constraint firstItem="CM2-S3-m7O" firstAttribute="centerY" secondItem="afT-Br-uER" secondAttribute="centerY" id="LQP-CB-Egm"/>
+                        <constraint firstAttribute="bottom" secondItem="ZbY-Gz-MYd" secondAttribute="bottom" id="dv2-Hw-7Wd"/>
+                        <constraint firstItem="ZbY-Gz-MYd" firstAttribute="leading" secondItem="TDe-Bu-KkR" secondAttribute="trailing" constant="6" id="jZe-s7-n8Q"/>
+                        <constraint firstItem="TDe-Bu-KkR" firstAttribute="leading" secondItem="afT-Br-uER" secondAttribute="leading" constant="12" id="oW6-Ub-o9t"/>
+                        <constraint firstItem="CM2-S3-m7O" firstAttribute="leading" secondItem="ZbY-Gz-MYd" secondAttribute="trailing" constant="12" id="rMo-2L-q7X"/>
+                        <constraint firstAttribute="height" constant="34" id="rYi-Wd-MfN"/>
+                        <constraint firstAttribute="trailing" secondItem="CM2-S3-m7O" secondAttribute="trailing" constant="3" id="uGB-M0-dSp"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="17"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="Ypg-l8-Rgd" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="FYK-PB-ZgN"/>
+                <constraint firstAttribute="trailing" secondItem="afT-Br-uER" secondAttribute="trailing" constant="14" id="dsj-NO-EbS"/>
+                <constraint firstItem="Ypg-l8-Rgd" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="12" id="gwS-lP-Rdk"/>
+                <constraint firstItem="afT-Br-uER" firstAttribute="centerY" secondItem="Ypg-l8-Rgd" secondAttribute="centerY" id="l2b-DF-DD2"/>
+                <constraint firstItem="afT-Br-uER" firstAttribute="leading" secondItem="Ypg-l8-Rgd" secondAttribute="trailing" constant="12" id="t9H-no-QBP"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="searchField" destination="ZbY-Gz-MYd" id="uG1-ld-TiF"/>
+            </connections>
+            <point key="canvasLocation" x="32.824427480916029" y="-2.1126760563380285"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="search_green" width="15" height="16"/>
+        <image name="sort_up_grey" width="9" height="5"/>
+    </resources>
+</document>

+ 0 - 1
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLessonBodyView.m

@@ -516,7 +516,6 @@
     detailVC.courseGroupId = model.courseGroupId;
     detailVC.teacherId = model.teacherId;
     [self.naviController pushViewController:detailVC animated:YES];
-    
 }
 
 /**

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLiveCourseCell.m

@@ -38,7 +38,7 @@
     }
     [self.courseCoverImage sd_setImageWithURL:[NSURL URLWithString:[model.cover getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:@"video_placeholder"]];
     
-    self.courseNameLabel.text = [NSString returnNoNullStringWithString:model.name];
+    self.courseNameLabel.text = [NSString returnNoNullStringWithString:model.courseName];
     self.subjectName.text = [NSString returnNoNullStringWithString:model.subjectName];
     self.targetId = model.imGroupId;
     // time

+ 19 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.h

@@ -0,0 +1,19 @@
+//
+//  MyProgramCourseGroupCell.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import <UIKit/UIKit.h>
+#import "ProgramCourseGroupModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyProgramCourseGroupCell : UITableViewCell
+
+- (void)configWithSource:(ProgramCourseGroupModel *)model isVipCourse:(BOOL)isVipCourse;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 86 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.m

@@ -0,0 +1,86 @@
+//
+//  MyProgramCourseGroupCell.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyProgramCourseGroupCell.h"
+
+@interface MyProgramCourseGroupCell ()
+
+@property (weak, nonatomic) IBOutlet UILabel *programTitle;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseStatus;
+
+@property (weak, nonatomic) IBOutlet UIImageView *avatar;
+
+@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *subjectView;
+
+@property (weak, nonatomic) IBOutlet UILabel *subjectLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseDesc;
+
+@end
+
+@implementation MyProgramCourseGroupCell
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    self.selectionStyle = UITableViewCellSelectionStyleNone;
+}
+
+- (void)configWithSource:(ProgramCourseGroupModel *)model isVipCourse:(BOOL)isVipCourse {
+    
+    self.programTitle.text = [NSString returnNoNullStringWithString:model.courseGroupName];
+    /// 状态
+    [self evaluateGroupStatus:model.status];
+    
+    [self.avatar sd_setImageWithURL:[NSURL URLWithString:[model.teacherAvatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:STUDENT_AVATAR]];
+    
+    self.nameLabel.text = [NSString returnNoNullStringWithString:model.teacherName];
+    
+    self.subjectLabel.text = [NSString returnNoNullStringWithString:model.subjectName];
+    
+    // 课程描述
+    NSMutableAttributedString *attrs = [[NSMutableAttributedString alloc] initWithString:@"已上课时 " attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular],NSForegroundColorAttributeName:HexRGB(0x999999)}];
+    NSAttributedString *finishNumAttr = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%.0f", model.completeCourseNum] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightSemibold],NSForegroundColorAttributeName:THEMECOLOR}];
+    [attrs appendAttributedString:finishNumAttr];
+    
+    NSAttributedString *totalDescAttr = [[NSAttributedString alloc] initWithString:@" /总课时 " attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular],NSForegroundColorAttributeName:HexRGB(0x999999)}];
+    [attrs appendAttributedString:totalDescAttr];
+    NSAttributedString *totalNumAttr = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%.0f", model.courseNum] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f weight:UIFontWeightSemibold],NSForegroundColorAttributeName:THEMECOLOR}];
+    [attrs appendAttributedString:totalNumAttr];
+    self.courseDesc.attributedText = attrs;
+}
+
+
+- (void)evaluateGroupStatus:(NSString *)status {
+    if ([status isEqualToString:@"ING"]) {
+        self.courseStatus.text = @"已开课";
+        self.courseStatus.textColor = THEMECOLOR;
+    }
+    else if ([status isEqualToString:@"NOT_START"]) {
+        self.courseStatus.text = @"未开课";
+        self.courseStatus.textColor = HexRGB(0xFF802C);
+    }
+    else if ([status isEqualToString:@"COMPLETE"]) {
+        self.courseStatus.text = @"已结课";
+        self.courseStatus.textColor = HexRGB(0x999999);
+    }
+    else if ([status isEqualToString:@"CANCEL"]) {
+        self.courseStatus.text = @"已取消";
+        self.courseStatus.textColor = HexRGB(0x999999);
+    }
+}
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+@end

+ 147 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.xib

@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="123" id="KGk-i7-Jjw" customClass="MyProgramCourseGroupCell">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="106"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="106"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hOG-9r-FYS">
+                        <rect key="frame" x="14" y="0.0" width="292" height="94"/>
+                        <subviews>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="VIP定制课-张涵宇" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fSB-R2-WNn">
+                                <rect key="frame" x="12" y="12" width="130.33333333333334" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="22" id="yBY-pf-3Gt"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
+                                <color key="textColor" red="0.074509803921568626" green="0.078431372549019607" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" text="未开课" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YcB-0r-jIC">
+                                <rect key="frame" x="238" y="12" width="42" height="17"/>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
+                                <color key="textColor" red="1" green="0.50196078431372548" blue="0.17254901960784313" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" image="teacher_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="Vki-dh-9s6">
+                                <rect key="frame" x="12" y="42" width="40" height="40"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="40" id="1t4-E5-ggF"/>
+                                    <constraint firstAttribute="height" constant="40" id="TJ2-qk-5z4"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="20"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="向冰冰" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6KB-MT-3Xa">
+                                <rect key="frame" x="62" y="43" width="39" height="17"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="17" id="6JM-FU-U7f"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="arrange_course_icon" translatesAutoresizingMaskIntoConstraints="NO" id="thQ-Vr-ooa">
+                                <rect key="frame" x="63" y="68" width="12" height="14"/>
+                            </imageView>
+                            <view contentMode="scaleToFill" horizontalCompressionResistancePriority="752" translatesAutoresizingMaskIntoConstraints="NO" id="fHv-aO-hTk">
+                                <rect key="frame" x="106" y="43" width="38" height="17"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="单簧管" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fmo-ut-d02">
+                                        <rect key="frame" x="4" y="2.6666666666666643" width="30" height="12"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
+                                        <color key="textColor" red="1" green="0.5490196078431373" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="1" green="0.94509803921568625" blue="0.87058823529411766" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstItem="Fmo-ut-d02" firstAttribute="centerY" secondItem="fHv-aO-hTk" secondAttribute="centerY" id="88h-UI-mze"/>
+                                    <constraint firstAttribute="trailing" secondItem="Fmo-ut-d02" secondAttribute="trailing" constant="4" id="JOf-3A-rAe"/>
+                                    <constraint firstAttribute="height" constant="17" id="ovP-MY-OYD"/>
+                                    <constraint firstItem="Fmo-ut-d02" firstAttribute="leading" secondItem="fHv-aO-hTk" secondAttribute="leading" constant="4" id="uHB-Xv-Do1"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="4"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="已上课时 34 /总课时 20" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JcJ-gf-HY4">
+                                <rect key="frame" x="79" y="67" width="129" height="16"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="16" id="LXf-Qg-nV3"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="YcB-0r-jIC" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fSB-R2-WNn" secondAttribute="trailing" constant="10" id="0Y7-8G-mFF"/>
+                            <constraint firstItem="fHv-aO-hTk" firstAttribute="leading" secondItem="6KB-MT-3Xa" secondAttribute="trailing" constant="5" id="4St-wE-Cud"/>
+                            <constraint firstItem="Vki-dh-9s6" firstAttribute="top" secondItem="fSB-R2-WNn" secondAttribute="bottom" constant="8" id="7BC-Sv-XIT"/>
+                            <constraint firstItem="fHv-aO-hTk" firstAttribute="centerY" secondItem="6KB-MT-3Xa" secondAttribute="centerY" id="Cyj-9i-Qcu"/>
+                            <constraint firstItem="fSB-R2-WNn" firstAttribute="leading" secondItem="hOG-9r-FYS" secondAttribute="leading" constant="12" id="GbP-2m-C6c"/>
+                            <constraint firstItem="thQ-Vr-ooa" firstAttribute="top" secondItem="6KB-MT-3Xa" secondAttribute="bottom" constant="8" id="IDW-ds-9YC"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="fHv-aO-hTk" secondAttribute="trailing" constant="12" id="Jb1-0I-kqm"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="JcJ-gf-HY4" secondAttribute="trailing" constant="12" id="N3u-Qa-brC"/>
+                            <constraint firstItem="6KB-MT-3Xa" firstAttribute="leading" secondItem="Vki-dh-9s6" secondAttribute="trailing" constant="10" id="N81-aa-HFk"/>
+                            <constraint firstItem="6KB-MT-3Xa" firstAttribute="top" secondItem="fSB-R2-WNn" secondAttribute="bottom" constant="9" id="RhP-KQ-ExU"/>
+                            <constraint firstItem="JcJ-gf-HY4" firstAttribute="leading" secondItem="thQ-Vr-ooa" secondAttribute="trailing" constant="4" id="S19-6a-nNB"/>
+                            <constraint firstItem="JcJ-gf-HY4" firstAttribute="centerY" secondItem="thQ-Vr-ooa" secondAttribute="centerY" id="Vg7-2b-0SI"/>
+                            <constraint firstItem="YcB-0r-jIC" firstAttribute="top" secondItem="hOG-9r-FYS" secondAttribute="top" constant="12" id="ZvC-KZ-QO8"/>
+                            <constraint firstItem="fSB-R2-WNn" firstAttribute="top" secondItem="hOG-9r-FYS" secondAttribute="top" constant="12" id="e2X-jz-1wa"/>
+                            <constraint firstItem="Vki-dh-9s6" firstAttribute="leading" secondItem="hOG-9r-FYS" secondAttribute="leading" constant="12" id="k25-T3-H2k"/>
+                            <constraint firstItem="thQ-Vr-ooa" firstAttribute="leading" secondItem="Vki-dh-9s6" secondAttribute="trailing" constant="11" id="w3I-Ch-OAi"/>
+                            <constraint firstAttribute="trailing" secondItem="YcB-0r-jIC" secondAttribute="trailing" constant="12" id="zpd-wE-jND"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="10"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="bottom" secondItem="hOG-9r-FYS" secondAttribute="bottom" constant="12" id="5Sf-z3-Tz9"/>
+                    <constraint firstItem="hOG-9r-FYS" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="Imi-54-xvz"/>
+                    <constraint firstAttribute="trailing" secondItem="hOG-9r-FYS" secondAttribute="trailing" constant="14" id="KzP-2w-x9d"/>
+                    <constraint firstItem="hOG-9r-FYS" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="cGE-R5-38a"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <connections>
+                <outlet property="avatar" destination="Vki-dh-9s6" id="hLD-Pl-7hg"/>
+                <outlet property="courseDesc" destination="JcJ-gf-HY4" id="Ck1-zp-SxF"/>
+                <outlet property="courseStatus" destination="YcB-0r-jIC" id="V7K-v4-pNK"/>
+                <outlet property="nameLabel" destination="6KB-MT-3Xa" id="C8E-lh-8Jq"/>
+                <outlet property="programTitle" destination="fSB-R2-WNn" id="9y7-Iv-5m1"/>
+                <outlet property="subjectLabel" destination="Fmo-ut-d02" id="Jfa-Vr-NFF"/>
+                <outlet property="subjectView" destination="fHv-aO-hTk" id="RS8-s9-veB"/>
+            </connections>
+            <point key="canvasLocation" x="33.587786259541986" y="47.183098591549296"/>
+        </tableViewCell>
+    </objects>
+    <resources>
+        <image name="arrange_course_icon" width="12" height="14"/>
+        <image name="teacher_avatar" width="150" height="150"/>
+    </resources>
+</document>

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyVipCourseGroupView.h

@@ -0,0 +1,18 @@
+//
+//  MyVipCourseGroupView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "KSJXBodyView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyVipCourseGroupView : KSJXBodyView
+
+@property (nonatomic, strong) NSMutableArray *subjectList;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 356 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VIPCourseGroup/MyVipCourseGroupView.m

@@ -0,0 +1,356 @@
+//
+//  MyVipCourseGroupView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyVipCourseGroupView.h"
+#import "MyProgramCourseGroupCell.h"
+#import "MyCourseSearchView.h"
+#import "StateView.h"
+#import "Reachability.h"
+#import "ProgramCourseGroupModel.h"
+#import "MyCourseRankSortView.h"
+
+@interface MyVipCourseGroupView ()<UITableViewDelegate,UITableViewDataSource>
+
+@property (nonatomic, assign) BOOL isLoadMore;
+@property (nonatomic, assign) NSInteger rows;
+@property (nonatomic, assign) NSInteger pages;
+
+@property (nonatomic, strong) NSMutableArray *dataArray;
+
+@property (nonatomic, strong) StateView *promptView;
+@property (nonatomic, strong) UIView *promptPlaceView;
+
+@property (nonatomic, assign) BOOL networkAvaiable; // 网络是否可用
+
+@property (nonatomic, strong) MyCourseSearchView *searchView;
+
+@property (nonatomic, strong) NSString *searchKey;
+
+@property (nonatomic, strong) NSString *subjectId;
+
+@property (nonatomic, assign) NSInteger subjectChooseIndex;
+
+@property (nonatomic, strong) NSString *status;
+
+@property (nonatomic, assign) NSInteger statusChooseIndex;
+@property (nonatomic, strong) MyCourseRankSortView *sortView;
+
+@property (nonatomic, strong) NSMutableArray *statusArray;
+
+
+@end
+
+@implementation MyVipCourseGroupView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) style:UITableViewStylePlain];
+        self.tableView.backgroundColor = [UIColor clearColor];
+        self.tableView.showsVerticalScrollIndicator = NO;
+        
+        self.tableView.dataSource = self;
+        self.tableView.delegate = self;
+        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+        [self addSubview:self.tableView];
+        self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        [self.tableView registerNib:[UINib nibWithNibName:@"MyProgramCourseGroupCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MyProgramCourseGroupCell"];
+
+        UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, iPhoneXSafeBottomMargin)];
+        bottomView.backgroundColor = [UIColor clearColor];
+        self.tableView.tableFooterView = bottomView;
+        
+        MJWeakSelf;
+        self.tableView.mj_header = [KSGifRefreshHeader headerWithRefreshingBlock:^{
+            [weakSelf resetParamenter];
+            [weakSelf requestData];
+        }];
+        self.tableView.mj_footer = [KSGifRefreshFooter footerWithRefreshingBlock:^{
+            if (weakSelf.isLoadMore) {
+                weakSelf.pages += 1;
+                [weakSelf requestData];
+            }
+            else {
+                [weakSelf.tableView.mj_footer endRefreshingWithNoMoreData];
+            }
+        }];
+    }
+    return self;
+}
+
+- (void)refreshAndRequestData {
+    [self resetParamenter];
+    [self requestData];
+}
+
+- (void)resetParamenter {
+    self.isLoadMore = YES;
+    self.pages = 1;
+    self.rows = 10;
+    
+    self.dataArray = [NSMutableArray array];
+    [self.tableView.mj_footer resetNoMoreData];
+    [self setPromptString:@"暂无内容" imageName:@"empty_course" inView:self.tableView];
+    [self.tableView reloadData];
+}
+
+- (void)endRefresh {
+    @weakObj(self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        @strongObj(self);
+        [self.tableView.mj_header endRefreshing];
+        [self.tableView.mj_footer endRefreshing];
+    });
+}
+
+
+- (void)requestData {
+    [KSNetworkingManager myCourseGroupRequest:KS_POST courseType:@"VIP" search:self.searchKey subjectId:self.subjectId status:self.status success:^(NSDictionary * _Nonnull dic) {
+        [self endRefresh];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [[dic ks_dictionaryValueForKey:@"data"] ks_arrayValueForKey:@"rows"];
+            for (NSDictionary *parm in sourceArray) {
+                ProgramCourseGroupModel *model = [[ProgramCourseGroupModel alloc] initWithDictionary:parm];
+                [self.dataArray addObject:model];
+            }
+            if (sourceArray.count < self.rows) {
+                self.isLoadMore = NO;
+            }
+        }
+        else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
+        }
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    } faliure:^(NSError * _Nonnull error) {
+        [self endRefresh];
+        if (self.networkAvaiable == NO) {
+            [self setPromptString:@"暂无网络" imageName:@"no_networking" inView:self.tableView];
+        }
+        [self.dataArray removeAllObjects];
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    }];
+    
+    
+}
+
+- (void)beginRefreshImmediately {
+    [self.tableView.mj_header beginRefreshing];
+}
+
+- (void)beginFirstRefresh {
+    if (!self.isHeaderRefreshed) {
+        [self beginRefreshImmediately];
+    }
+}
+- (void)selectCellAtIndexPath:(NSIndexPath *)indexPath {
+    
+    if (self.lastSelectedIndexPath == indexPath) {
+        return;
+    }
+    if (self.lastSelectedIndexPath != nil) {
+        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.lastSelectedIndexPath];
+        [cell setSelected:NO animated:NO];
+    }
+    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+    [cell setSelected:YES animated:NO];
+    self.lastSelectedIndexPath = indexPath;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat searchViewHeight = [MyCourseSearchView getViewHeight];
+
+    if (![self.subviews containsObject:self.searchView]) {
+        [self addSubview:self.searchView];
+        [self.searchView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.mas_equalTo(self);
+            make.height.mas_equalTo(searchViewHeight);
+        }];
+    }
+
+    [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.bottom.mas_equalTo(self);
+        make.top.mas_equalTo(self.searchView.mas_bottom);
+    }];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 106.0f;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    ProgramCourseGroupModel *model = self.dataArray[indexPath.row];
+    MyProgramCourseGroupCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyProgramCourseGroupCell"];
+    [cell configWithSource:model isVipCourse:NO];
+    return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    // 课程详情
+}
+
+#pragma mark ------ lazying
+- (MyCourseSearchView *)searchView {
+    if (!_searchView) {
+        _searchView = [MyCourseSearchView sharedInstance];
+        MJWeakSelf;
+        [_searchView searchActionCallback:^(MY_COURSE_SORT type, NSString * _Nullable searchKey) {
+            [weakSelf searchAction:type searchKey:searchKey];
+        }];
+    }
+    return _searchView;
+}
+
+- (void)searchAction:(MY_COURSE_SORT)type searchKey:(NSString *)searchKey {
+    switch (type) {
+        case MY_COURSE_SORT_RANK:
+        {
+            [self showSortView];
+        }
+            break;
+        case MY_COURSE_SORT_SEARCH:
+        {
+            [self evaluateSource:searchKey];
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)showSortView {
+    self.searchView.arrowUp = YES;
+    [self.sortView refreshUI:self.statusChooseIndex subjectId:self.subjectChooseIndex];
+    [self.sortView showInView:[NSObject getKeyWindow]];
+}
+
+- (void)evaluateSource:(NSString *)searchKey {
+    self.searchKey = searchKey;
+    [self refreshAndRequestData];
+}
+
+/**
+ 设置没有数据时的显示
+ 
+ @param promptString 提示语
+ @param imgName 图片名称
+ @param view 显示在什么地方
+ */
+- (void)setPromptString:(NSString *)promptString imageName:(NSString *)imgName inView:(UIView *)view {
+    if (self.promptView != nil) {
+        [self.promptView removeFromSuperview];
+    }
+    else {
+        self.promptView = [[StateView alloc]init];
+        self.promptView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight - 300);
+    }
+    _promptPlaceView = view;
+    //当请求不到数据时 ,自定义提示view 将会出现;
+    self.promptView.imageName = imgName;
+    self.promptView.alpha = 0.0f;
+    [self.promptView setText:promptString];
+    [view addSubview:self.promptView];
+}
+
+// 结束刷新后调用方法
+- (void)changePromptLabelStateWithArray:(NSMutableArray *)array {
+    NSInteger count;
+    if (array.count) {
+        count = array.count;
+    } else {
+        count = 0;
+    }
+    
+    [UIView animateWithDuration:0.1 animations:^{
+        [[self promptView] setAlpha:count ? 0.0f :1.0f ] ;
+    }] ;
+    
+}
+
+- (BOOL)networkAvaiable {
+    return [self checkNetworkAvaiable];
+}
+
+- (BOOL)checkNetworkAvaiable {
+    BOOL isExistenceNetwork = YES;
+    Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
+    switch ([reach currentReachabilityStatus]) {
+        case NotReachable:
+            isExistenceNetwork = NO;
+            //NSLog(@"notReachable");
+            break;
+        case ReachableViaWiFi:
+            isExistenceNetwork = YES;
+            //NSLog(@"WIFI");
+            break;
+        case ReachableViaWWAN:
+            isExistenceNetwork = YES;
+            //NSLog(@"3G");
+            break;
+    }
+    return isExistenceNetwork;
+}
+
+
+- (MyCourseRankSortView *)sortView {
+    if (!_sortView) {
+        _sortView = [MyCourseRankSortView sharedInstance];
+        [_sortView configWithStatusArray:self.statusArray subjectArray:self.subjectList];
+        MJWeakSelf;
+        [_sortView sortActionCallback:^(MY_COURSE_SORTTYPE type, NSString * _Nullable status, NSString * _Nullable subjectId, NSInteger statusIndex, NSInteger subjectIndex) {
+            [weakSelf sortActionWithType:type status:status subjectId:subjectId statusChooseIndex:statusIndex subjectChooseIndex:subjectIndex];
+        }];
+    }
+    return _sortView;
+}
+
+- (void)sortActionWithType:(MY_COURSE_SORTTYPE)type status:(NSString *)status subjectId:(NSString *)subjectId statusChooseIndex:(NSInteger)statusChooseIndex subjectChooseIndex:(NSInteger)subjectChooseIndex  {
+    self.searchView.arrowUp = NO;
+    if (type == MY_COURSE_SORTTYPE_SORT) {
+        self.statusChooseIndex = statusChooseIndex;
+        self.subjectChooseIndex = subjectChooseIndex;
+        self.status = status;
+        self.subjectId = subjectId;
+        if ([NSString isEmptyString:status]) {
+            self.status = nil;
+        }
+        if ([NSString isEmptyString:subjectId]) {
+            self.subjectId = nil;
+        }
+        [self refreshAndRequestData];
+    }
+}
+
+- (NSMutableArray *)statusArray {
+    if (!_statusArray) {
+        _statusArray = [NSMutableArray arrayWithArray:@[@{@"name":@"全部",@"id":@""},@{@"name":@"未开课",@"id":@"NOT_START"},@{@"name":@"已开课",@"id":@"ING"},@{@"name":@"已结课",@"id":@"COMPLETE"}]];
+    }
+    return _statusArray;
+}
+
+- (void)setSubjectList:(NSMutableArray *)subjectList {
+    NSMutableArray *array = [NSMutableArray arrayWithArray:subjectList];
+    [array insertObject:@{@"name":@"全部",@"id":@""} atIndex:0];
+    _subjectList = array;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 2 - 2
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseCell.m

@@ -37,11 +37,11 @@
     [self.coverImage sd_setImageWithURL:[NSURL URLWithString:[model.lessonCoverUrl getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:@"video_placeholder"]];
     self.courseTitle.text = [NSString returnNoNullStringWithString:model.lessonName];
     [self.teacherAvatar sd_setImageWithURL:[NSURL URLWithString:[model.avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:TEACHER_AVATAR]];
-    if ([NSString isEmptyString:model.username]) {
+    if ([NSString isEmptyString:model.userName]) {
         self.teacherName.text = [NSString stringWithFormat:@"游客%.0f",model.teacherId];
     }
     else {
-        self.teacherName.text = model.username;
+        self.teacherName.text = model.userName;
     }
     
    

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoCourseGroupView.h

@@ -0,0 +1,18 @@
+//
+//  MyVideoCourseGroupView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "KSJXBodyView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyVideoCourseGroupView : KSJXBodyView
+
+@property (nonatomic, strong) NSMutableArray *subjectList;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 346 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoCourseGroupView.m

@@ -0,0 +1,346 @@
+//
+//  MyVideoCourseGroupView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyVideoCourseGroupView.h"
+#import "MyCourseSearchView.h"
+#import "MyVideoGroupListCell.h"
+#import "VideoCourseModel.h"
+#import "StateView.h"
+#import "Reachability.h"
+#import "KSBaseWKWebViewController.h"
+#import "MyCourseRankSortView.h"
+
+@interface MyVideoCourseGroupView ()<UITableViewDelegate,UITableViewDataSource>
+
+@property (nonatomic, assign) BOOL isLoadMore;
+@property (nonatomic, assign) NSInteger rows;
+@property (nonatomic, assign) NSInteger pages;
+
+@property (nonatomic, strong) NSMutableArray *dataArray;
+
+@property (nonatomic, strong) StateView *promptView;
+@property (nonatomic, strong) UIView *promptPlaceView;
+
+@property (nonatomic, assign) BOOL networkAvaiable; // 网络是否可用
+
+@property (nonatomic, strong) MyCourseSearchView *searchView;
+
+@property (nonatomic, strong) NSString *searchKey;
+
+@property (nonatomic, strong) NSString *subjectId;
+
+@property (nonatomic, strong) NSString *audioStatus;
+
+@property (nonatomic, assign) NSInteger subjectChooseIndex;
+
+@property (nonatomic, strong) MyCourseRankSortView *sortView;
+
+@end
+
+@implementation MyVideoCourseGroupView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) style:UITableViewStylePlain];
+        self.tableView.backgroundColor = [UIColor clearColor];
+        self.tableView.showsVerticalScrollIndicator = NO;
+        
+        self.tableView.dataSource = self;
+        self.tableView.delegate = self;
+        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+        [self addSubview:self.tableView];
+        self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        [self.tableView registerNib:[UINib nibWithNibName:@"MyVideoGroupListCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MyVideoGroupListCell"];
+
+        UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, iPhoneXSafeBottomMargin)];
+        bottomView.backgroundColor = [UIColor clearColor];
+        self.tableView.tableFooterView = bottomView;
+        
+        MJWeakSelf;
+        self.tableView.mj_header = [KSGifRefreshHeader headerWithRefreshingBlock:^{
+            [weakSelf resetParamenter];
+            [weakSelf requestData];
+        }];
+        self.tableView.mj_footer = [KSGifRefreshFooter footerWithRefreshingBlock:^{
+            if (weakSelf.isLoadMore) {
+                weakSelf.pages += 1;
+                [weakSelf requestData];
+            }
+            else {
+                [weakSelf.tableView.mj_footer endRefreshingWithNoMoreData];
+            }
+        }];
+    }
+    return self;
+}
+
+- (void)refreshAndRequestData {
+    [self resetParamenter];
+    [self requestData];
+}
+
+- (void)resetParamenter {
+    self.isLoadMore = YES;
+    self.pages = 1;
+    self.rows = 10;
+    self.audioStatus = @"PASS";
+    self.dataArray = [NSMutableArray array];
+    [self.tableView.mj_footer resetNoMoreData];
+    [self setPromptString:@"暂无内容" imageName:@"empty_course" inView:self.tableView];
+    [self.tableView reloadData];
+}
+
+- (void)endRefresh {
+    @weakObj(self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        @strongObj(self);
+        [self.tableView.mj_header endRefreshing];
+        [self.tableView.mj_footer endRefreshing];
+    });
+}
+
+
+- (void)requestData {
+    [KSNetworkingManager videoLessonGroupRequest:KS_POST lessonSubject:self.searchKey page:self.pages rows:self.rows success:^(NSDictionary * _Nonnull dic) {
+        [self endRefresh];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [[dic ks_dictionaryValueForKey:@"data"] ks_arrayValueForKey:@"rows"];
+            for (NSDictionary *parm in sourceArray) {
+                VideoCourseModel *model = [[VideoCourseModel alloc] initWithDictionary:parm];
+                [self.dataArray addObject:model];
+            }
+            
+            if (sourceArray.count < self.rows) {
+                self.isLoadMore = NO;
+            }
+        }
+        else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
+        }
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    } faliure:^(NSError * _Nonnull error) {
+        [self endRefresh];
+        if (self.networkAvaiable == NO) {
+            [self setPromptString:@"暂无网络" imageName:@"no_networking" inView:self.tableView];
+        }
+        [self.dataArray removeAllObjects];
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    }];
+}
+
+- (void)beginRefreshImmediately {
+    [self.tableView.mj_header beginRefreshing];
+}
+
+- (void)beginFirstRefresh {
+    if (!self.isHeaderRefreshed) {
+        [self beginRefreshImmediately];
+    }
+}
+- (void)selectCellAtIndexPath:(NSIndexPath *)indexPath {
+    
+    if (self.lastSelectedIndexPath == indexPath) {
+        return;
+    }
+    if (self.lastSelectedIndexPath != nil) {
+        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.lastSelectedIndexPath];
+        [cell setSelected:NO animated:NO];
+    }
+    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+    [cell setSelected:YES animated:NO];
+    self.lastSelectedIndexPath = indexPath;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    CGFloat searchViewHeight = [MyCourseSearchView getViewHeight];
+
+    if (![self.subviews containsObject:self.searchView]) {
+        [self addSubview:self.searchView];
+        [self.searchView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.mas_equalTo(self);
+            make.height.mas_equalTo(searchViewHeight);
+        }];
+    }
+
+    [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.bottom.mas_equalTo(self);
+        make.top.mas_equalTo(self.searchView.mas_bottom);
+    }];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 117.0f;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    VideoCourseModel *model = self.dataArray[indexPath.row];
+    MyVideoGroupListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyVideoGroupListCell"];
+    [cell configWithSource:model];
+    return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    // 课程详情
+    
+    VideoCourseModel *model = [self.dataArray objectAtIndex:indexPath.row];
+    NSString *url = [NSString stringWithFormat:@"%@%@%@", WEBHOST, @"/#/videoDetail?groupId=",model.internalBaseClassIdentifier];
+    KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
+    ctrl.url = url;
+    [self.naviController pushViewController:ctrl animated:YES];
+}
+
+#pragma mark ------ lazying
+- (MyCourseSearchView *)searchView {
+    if (!_searchView) {
+        _searchView = [MyCourseSearchView sharedInstance];
+        MJWeakSelf;
+        [_searchView searchActionCallback:^(MY_COURSE_SORT type, NSString * _Nullable searchKey) {
+            [weakSelf searchAction:type searchKey:searchKey];
+        }];
+    }
+    return _searchView;
+}
+
+- (void)searchAction:(MY_COURSE_SORT)type searchKey:(NSString *)searchKey {
+    switch (type) {
+        case MY_COURSE_SORT_RANK:
+        {
+            [self showSortView];
+        }
+            break;
+        case MY_COURSE_SORT_SEARCH:
+        {
+            [self evaluateSource:searchKey];
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)showSortView {
+    self.searchView.arrowUp = YES;
+    [self.sortView refreshUI:0 subjectId:self.subjectChooseIndex];
+    [self.sortView showInView:[NSObject getKeyWindow]];
+}
+
+- (void)evaluateSource:(NSString *)searchKey {
+    self.searchKey = searchKey;
+    [self refreshAndRequestData];
+}
+
+/**
+ 设置没有数据时的显示
+ 
+ @param promptString 提示语
+ @param imgName 图片名称
+ @param view 显示在什么地方
+ */
+- (void)setPromptString:(NSString *)promptString imageName:(NSString *)imgName inView:(UIView *)view {
+    if (self.promptView != nil) {
+        [self.promptView removeFromSuperview];
+    }
+    else {
+        self.promptView = [[StateView alloc]init];
+        self.promptView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight - 300);
+    }
+    _promptPlaceView = view;
+    //当请求不到数据时 ,自定义提示view 将会出现;
+    self.promptView.imageName = imgName;
+    self.promptView.alpha = 0.0f;
+    [self.promptView setText:promptString];
+    [view addSubview:self.promptView];
+}
+
+// 结束刷新后调用方法
+- (void)changePromptLabelStateWithArray:(NSMutableArray *)array {
+    NSInteger count;
+    if (array.count) {
+        count = array.count;
+    } else {
+        count = 0;
+    }
+    
+    [UIView animateWithDuration:0.1 animations:^{
+        [[self promptView] setAlpha:count ? 0.0f :1.0f ] ;
+    }] ;
+    
+}
+
+- (BOOL)networkAvaiable {
+    return [self checkNetworkAvaiable];
+}
+
+- (BOOL)checkNetworkAvaiable {
+    BOOL isExistenceNetwork = YES;
+    Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
+    switch ([reach currentReachabilityStatus]) {
+        case NotReachable:
+            isExistenceNetwork = NO;
+            //NSLog(@"notReachable");
+            break;
+        case ReachableViaWiFi:
+            isExistenceNetwork = YES;
+            //NSLog(@"WIFI");
+            break;
+        case ReachableViaWWAN:
+            isExistenceNetwork = YES;
+            //NSLog(@"3G");
+            break;
+    }
+    return isExistenceNetwork;
+}
+
+- (MyCourseRankSortView *)sortView {
+    if (!_sortView) {
+        _sortView = [MyCourseRankSortView sharedInstance];
+        [_sortView configWithStatusArray:[NSMutableArray array] subjectArray:self.subjectList];
+        MJWeakSelf;
+        [_sortView sortActionCallback:^(MY_COURSE_SORTTYPE type, NSString * _Nullable status, NSString * _Nullable subjectId, NSInteger statusIndex, NSInteger subjectIndex) {
+            [weakSelf sortActionWithType:type status:status subjectId:subjectId statusChooseIndex:statusIndex subjectChooseIndex:subjectIndex];
+        }];
+    }
+    return _sortView;
+}
+
+- (void)sortActionWithType:(MY_COURSE_SORTTYPE)type status:(NSString *)status subjectId:(NSString *)subjectId statusChooseIndex:(NSInteger)statusChooseIndex subjectChooseIndex:(NSInteger)subjectChooseIndex  {
+    self.searchView.arrowUp = NO;
+    if (type == MY_COURSE_SORTTYPE_SORT) {
+        self.subjectChooseIndex = subjectChooseIndex;
+        self.subjectId = subjectId;
+
+        if ([NSString isEmptyString:subjectId]) {
+            self.subjectId = nil;
+        }
+        [self refreshAndRequestData];
+    }
+}
+
+- (void)setSubjectList:(NSMutableArray *)subjectList {
+    NSMutableArray *array = [NSMutableArray arrayWithArray:subjectList];
+    [array insertObject:@{@"name":@"全部",@"id":@""} atIndex:0];
+    _subjectList = array;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 19 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoGroupListCell.h

@@ -0,0 +1,19 @@
+//
+//  MyVideoGroupListCell.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import <UIKit/UIKit.h>
+#import "VideoCourseModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MyVideoGroupListCell : UITableViewCell
+
+- (void)configWithSource:(VideoCourseModel *)model;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 75 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoGroupListCell.m

@@ -0,0 +1,75 @@
+//
+//  MyVideoGroupListCell.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/20.
+//
+
+#import "MyVideoGroupListCell.h"
+
+@interface MyVideoGroupListCell ()
+
+@property (weak, nonatomic) IBOutlet UIImageView *coverImage;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseTitle;
+
+@property (weak, nonatomic) IBOutlet UILabel *subjectLabel;
+
+
+@property (weak, nonatomic) IBOutlet UILabel *courseCount;
+
+@property (weak, nonatomic) IBOutlet UIView *musicView;
+
+@property (weak, nonatomic) IBOutlet UILabel *musicLabel;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *musicRight;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *musicLabelLeft;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *musicLabelRight;
+
+@property (weak, nonatomic) IBOutlet UIImageView *avatar;
+
+@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
+
+@end
+
+@implementation MyVideoGroupListCell
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    self.selectionStyle = UITableViewCellSelectionStyleNone;
+}
+
+- (void)configWithSource:(VideoCourseModel *)model {
+    [self.coverImage sd_setImageWithURL:[NSURL URLWithString:[model.lessonCoverUrl getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:@"video_placeholder"]];
+    self.courseTitle.text = [NSString returnNoNullStringWithString:model.lessonName];
+    
+    self.subjectLabel.text = [NSString returnNoNullStringWithString:model.lessonSubjectName];
+    self.courseCount.text = [NSString stringWithFormat:@"%.0f课时",model.lessonCount];
+    
+    // 曲目
+    if (model.musicNum > 0) {
+        self.musicLabel.text = [NSString stringWithFormat:@"%zd首曲目", model.musicNum];
+        self.musicRight.constant = 4.0f;
+        self.musicLabelLeft.constant = 6.0f;
+        self.musicLabelRight.constant = 6.0f;
+    }
+    else {
+        self.musicView.hidden = YES;
+        self.musicLabel.text = @"";
+        self.musicRight.constant = 0.0f;
+        self.musicLabelLeft.constant = 0.0f;
+        self.musicLabelRight.constant = 0.0f;
+    }
+    [self.avatar sd_setImageWithURL:[NSURL URLWithString:[model.avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:TEACHER_AVATAR]];
+    self.nameLabel.text = [NSString returnNoNullStringWithString:model.userName];
+}
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+@end

+ 196 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/VideoCourseGroup/MyVideoGroupListCell.xib

@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="122" id="KGk-i7-Jjw" customClass="MyVideoGroupListCell">
+            <rect key="frame" x="0.0" y="0.0" width="371" height="117"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
+                <rect key="frame" x="0.0" y="0.0" width="371" height="117"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Udr-EQ-mCS">
+                        <rect key="frame" x="14" y="0.0" width="343" height="105"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="video_placeholder" translatesAutoresizingMaskIntoConstraints="NO" id="yHe-XE-Lr9">
+                                <rect key="frame" x="12" y="12" width="146" height="81"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="146" id="4pS-KZ-UWw"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="6"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </imageView>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="X9f-x2-drl">
+                                <rect key="frame" x="16" y="16" width="28" height="14"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="长笛" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="exN-B6-D82">
+                                        <rect key="frame" x="4" y="1" width="20" height="12"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="12" id="ikn-PM-oTz"/>
+                                        </constraints>
+                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
+                                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.40000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstItem="exN-B6-D82" firstAttribute="leading" secondItem="X9f-x2-drl" secondAttribute="leading" constant="4" id="Pp4-io-kgG"/>
+                                    <constraint firstItem="exN-B6-D82" firstAttribute="top" secondItem="X9f-x2-drl" secondAttribute="top" constant="1" id="Sdc-Bh-yPV"/>
+                                    <constraint firstAttribute="trailing" secondItem="exN-B6-D82" secondAttribute="trailing" constant="4" id="ZoE-Wu-dfN"/>
+                                    <constraint firstAttribute="bottom" secondItem="exN-B6-D82" secondAttribute="bottom" constant="1" id="bTK-Fb-JWN"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="3"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="F1K-0G-zso">
+                                <rect key="frame" x="227.33333333333334" y="43" width="42.666666666666657" height="18"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="4课时" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="v90-bW-vHn">
+                                        <rect key="frame" x="6.0000000000000018" y="0.0" width="30.666666666666671" height="18"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="11"/>
+                                        <color key="textColor" red="0.46666666670000001" green="0.46666666670000001" blue="0.46666666670000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.96078431369999995" green="0.96470588239999999" blue="0.98039215690000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="bottom" secondItem="v90-bW-vHn" secondAttribute="bottom" id="5h0-Iy-yWB"/>
+                                    <constraint firstItem="v90-bW-vHn" firstAttribute="top" secondItem="F1K-0G-zso" secondAttribute="top" id="7xe-eT-jkE"/>
+                                    <constraint firstItem="v90-bW-vHn" firstAttribute="leading" secondItem="F1K-0G-zso" secondAttribute="leading" constant="6" id="dlG-Su-nI6"/>
+                                    <constraint firstAttribute="trailing" secondItem="v90-bW-vHn" secondAttribute="trailing" constant="6" id="ok0-iJ-Pn6"/>
+                                    <constraint firstAttribute="height" constant="18" id="z1A-ue-NeB"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="3"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s0F-Lb-ssK">
+                                <rect key="frame" x="170" y="43" width="53.333333333333343" height="18"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3首曲目" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iyS-6i-p8d">
+                                        <rect key="frame" x="6" y="0.0" width="41.333333333333336" height="18"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="11"/>
+                                        <color key="textColor" red="0.46666666670000001" green="0.46666666670000001" blue="0.46666666670000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.96078431369999995" green="0.96470588239999999" blue="0.98039215690000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstItem="iyS-6i-p8d" firstAttribute="leading" secondItem="s0F-Lb-ssK" secondAttribute="leading" constant="6" id="D1W-ya-XTp"/>
+                                    <constraint firstAttribute="trailing" secondItem="iyS-6i-p8d" secondAttribute="trailing" constant="6" id="KdW-az-aHD"/>
+                                    <constraint firstItem="iyS-6i-p8d" firstAttribute="top" secondItem="s0F-Lb-ssK" secondAttribute="top" id="RPS-ph-dP9"/>
+                                    <constraint firstAttribute="height" constant="18" id="q2C-Mr-nFf"/>
+                                    <constraint firstAttribute="bottom" secondItem="iyS-6i-p8d" secondAttribute="bottom" id="vd2-Ha-5o7"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="3"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="从零开始学竖笛视频课" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mt0-5a-cZX">
+                                <rect key="frame" x="170" y="14" width="161" height="21"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="21" id="cxi-yY-VOh"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
+                                <color key="textColor" red="0.074509803920000006" green="0.078431372550000003" blue="0.08235294118" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="teacher_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="zNI-h7-bkF">
+                                <rect key="frame" x="170" y="70" width="20" height="20"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="20" id="TKT-Qy-H8M"/>
+                                    <constraint firstAttribute="width" constant="20" id="TS7-uE-d3O"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="10"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="严琦" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ecO-2w-UK0">
+                                <rect key="frame" x="194" y="72.333333333333329" width="26" height="15.666666666666671"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="ecO-2w-UK0" secondAttribute="trailing" constant="12" id="3Gf-G0-s3Y"/>
+                            <constraint firstItem="mt0-5a-cZX" firstAttribute="leading" secondItem="yHe-XE-Lr9" secondAttribute="trailing" constant="12" id="4qP-St-sut"/>
+                            <constraint firstItem="zNI-h7-bkF" firstAttribute="leading" secondItem="yHe-XE-Lr9" secondAttribute="trailing" constant="12" id="C2T-Gw-jRX"/>
+                            <constraint firstItem="zNI-h7-bkF" firstAttribute="bottom" secondItem="yHe-XE-Lr9" secondAttribute="bottom" constant="-3" id="MPy-3R-zqm"/>
+                            <constraint firstItem="X9f-x2-drl" firstAttribute="top" secondItem="yHe-XE-Lr9" secondAttribute="top" constant="4" id="O7s-Rx-Hw1"/>
+                            <constraint firstItem="mt0-5a-cZX" firstAttribute="top" secondItem="Udr-EQ-mCS" secondAttribute="top" constant="14" id="PRJ-as-u9Y"/>
+                            <constraint firstItem="ecO-2w-UK0" firstAttribute="centerY" secondItem="zNI-h7-bkF" secondAttribute="centerY" id="Qbz-ET-xIL"/>
+                            <constraint firstItem="F1K-0G-zso" firstAttribute="leading" secondItem="s0F-Lb-ssK" secondAttribute="trailing" constant="4" id="SXq-85-l63"/>
+                            <constraint firstItem="yHe-XE-Lr9" firstAttribute="leading" secondItem="Udr-EQ-mCS" secondAttribute="leading" constant="12" id="Tv8-dG-A6n"/>
+                            <constraint firstItem="X9f-x2-drl" firstAttribute="leading" secondItem="yHe-XE-Lr9" secondAttribute="leading" constant="4" id="Uk4-8b-nqs"/>
+                            <constraint firstAttribute="trailing" secondItem="mt0-5a-cZX" secondAttribute="trailing" constant="12" id="VuQ-5P-99N"/>
+                            <constraint firstItem="yHe-XE-Lr9" firstAttribute="top" secondItem="Udr-EQ-mCS" secondAttribute="top" constant="12" id="gU6-wa-Z8R"/>
+                            <constraint firstItem="ecO-2w-UK0" firstAttribute="leading" secondItem="zNI-h7-bkF" secondAttribute="trailing" constant="4" id="kUu-TU-aw4"/>
+                            <constraint firstItem="F1K-0G-zso" firstAttribute="top" secondItem="mt0-5a-cZX" secondAttribute="bottom" constant="8" id="rAb-fS-D7G"/>
+                            <constraint firstAttribute="bottom" secondItem="yHe-XE-Lr9" secondAttribute="bottom" constant="12" id="rqi-SV-VFi"/>
+                            <constraint firstItem="s0F-Lb-ssK" firstAttribute="top" secondItem="mt0-5a-cZX" secondAttribute="bottom" constant="8" id="stU-Hk-Cos"/>
+                            <constraint firstItem="s0F-Lb-ssK" firstAttribute="leading" secondItem="yHe-XE-Lr9" secondAttribute="trailing" constant="12" id="ve6-AF-Aw1"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="6"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="trailing" secondItem="Udr-EQ-mCS" secondAttribute="trailing" constant="14" id="03X-JT-0rr"/>
+                    <constraint firstItem="Udr-EQ-mCS" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="AAZ-RO-HON"/>
+                    <constraint firstAttribute="bottom" secondItem="Udr-EQ-mCS" secondAttribute="bottom" constant="12" id="RrG-Pu-XNv"/>
+                    <constraint firstItem="Udr-EQ-mCS" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="Vg0-bH-ZXt"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <connections>
+                <outlet property="avatar" destination="zNI-h7-bkF" id="cgu-Z9-Mrs"/>
+                <outlet property="courseCount" destination="v90-bW-vHn" id="5bp-SD-Cny"/>
+                <outlet property="courseTitle" destination="mt0-5a-cZX" id="t4L-p5-nxr"/>
+                <outlet property="coverImage" destination="yHe-XE-Lr9" id="QyM-LP-5tb"/>
+                <outlet property="musicLabel" destination="iyS-6i-p8d" id="U0g-N3-JfH"/>
+                <outlet property="musicLabelLeft" destination="D1W-ya-XTp" id="Apx-TQ-du0"/>
+                <outlet property="musicLabelRight" destination="KdW-az-aHD" id="ktN-uz-yML"/>
+                <outlet property="musicRight" destination="SXq-85-l63" id="dX3-8A-FC9"/>
+                <outlet property="musicView" destination="s0F-Lb-ssK" id="HdR-vE-j7d"/>
+                <outlet property="nameLabel" destination="ecO-2w-UK0" id="9Xj-Ez-UAf"/>
+                <outlet property="subjectLabel" destination="exN-B6-D82" id="jpA-FQ-AhE"/>
+            </connections>
+            <point key="canvasLocation" x="72.51908396946564" y="46.126760563380287"/>
+        </tableViewCell>
+    </objects>
+    <resources>
+        <image name="teacher_avatar" width="150" height="150"/>
+        <image name="video_placeholder" width="103" height="72"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>