ソースを参照

陪练课课程组详情

Steven 5 ヶ月 前
コミット
b2a07b3388
63 ファイル変更3288 行追加83 行削除
  1. 102 0
      KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj
  2. 22 0
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/courseDetail_bg.imageset/Contents.json
  3. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/courseDetail_bg.imageset/courseDetail_bg@2x.png
  4. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/courseDetail_bg.imageset/courseDetail_bg@3x.png
  5. 22 0
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_attendence.imageset/Contents.json
  6. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_attendence.imageset/course_attendence@2x.png
  7. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_attendence.imageset/course_attendence@3x.png
  8. 22 0
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_noArrive.imageset/Contents.json
  9. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_noArrive.imageset/course_noArrive@2x.png
  10. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_noArrive.imageset/course_noArrive@3x.png
  11. 22 0
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_plan_icon.imageset/Contents.json
  12. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_plan_icon.imageset/course_plan_icon@2x.png
  13. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_plan_icon.imageset/course_plan_icon@3x.png
  14. 22 0
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/group_addPlan.imageset/Contents.json
  15. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/group_addPlan.imageset/group_addPlan@2x.png
  16. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/group_addPlan.imageset/group_addPlan@3x.png
  17. 22 0
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/plan_edit.imageset/Contents.json
  18. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/plan_edit.imageset/plan_edit@2x.png
  19. BIN
      KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/plan_edit.imageset/plan_edit@3x.png
  20. 29 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.h
  21. 56 0
      KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.m
  22. 5 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/AccompanyCourse/Controller/AccompanyCourseGroupViewController.h
  23. 191 67
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/AccompanyCourse/Controller/AccompanyCourseGroupViewController.m
  24. 33 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Controller/VIPCourseGroupViewController.m
  25. 30 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseGroupDetailModel.h
  26. 169 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseGroupDetailModel.m
  27. 23 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseStudentVos.h
  28. 120 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseStudentVos.m
  29. 28 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/GroupCourseListModel.h
  30. 177 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/GroupCourseListModel.m
  31. 20 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseGroupBodyView.h
  32. 288 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseGroupBodyView.m
  33. 27 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseInfoView.h
  34. 158 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseInfoView.m
  35. 166 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseInfoView.xib
  36. 21 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseListCell.h
  37. 91 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseListCell.m
  38. 189 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseListCell.xib
  39. 24 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupNavView.h
  40. 51 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupNavView.m
  41. 70 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupNavView.xib
  42. 24 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAddView.h
  43. 54 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAddView.m
  44. 89 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAddView.xib
  45. 24 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAlertView.h
  46. 166 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAlertView.m
  47. 157 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAlertView.xib
  48. 26 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanDescView.h
  49. 100 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanDescView.m
  50. 111 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanDescView.xib
  51. 20 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/GroupCourseSortView.h
  52. 35 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/GroupCourseSortView.m
  53. 175 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/GroupCourseSortView.xib
  54. 1 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/Controller/MyCourseViewController.m
  55. 5 1
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/AccompanyCourseGroup/MyAccompanyCourseGroupView.m
  56. 9 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/CourseGroupAlertView/CourseDescAlertView.h
  57. 36 3
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/CourseGroupAlertView/CourseDescAlertView.m
  58. 1 8
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.m
  59. 5 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/VIPCourseGroup/MyVipCourseGroupView.m
  60. 24 2
      KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/Controller/MineVipProgramViewController.m
  61. 1 1
      KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/View/VIPProgramCreate/MineVipProgramNavView.h
  62. 6 1
      KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/View/VIPProgramCreate/MineVipProgramNavView.m
  63. 19 0
      KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/View/VIPProgramCreate/MineVipProgramNavView.xib

+ 102 - 0
KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj

@@ -382,6 +382,13 @@
 		BC1E28502C77218A0063E0A1 /* KSDeleteFailedAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC1E284E2C77218A0063E0A1 /* KSDeleteFailedAlertView.m */; };
 		BC206EDE2CEF2623001F2B85 /* MusicRoomCourseCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC206EDC2CEF2623001F2B85 /* MusicRoomCourseCell.m */; };
 		BC206EDF2CEF2623001F2B85 /* MusicRoomCourseCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC206EDD2CEF2623001F2B85 /* MusicRoomCourseCell.xib */; };
+		BC206EE72CF015A9001F2B85 /* ProgramCourseInfoView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC206EE62CF015A9001F2B85 /* ProgramCourseInfoView.m */; };
+		BC206EE92CF015B0001F2B85 /* ProgramCourseInfoView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC206EE82CF015B0001F2B85 /* ProgramCourseInfoView.xib */; };
+		BC206EED2CF01838001F2B85 /* ProgramCourseListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC206EEC2CF01838001F2B85 /* ProgramCourseListCell.xib */; };
+		BC206EEE2CF01838001F2B85 /* ProgramCourseListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC206EEB2CF01838001F2B85 /* ProgramCourseListCell.m */; };
+		BC206EF12CF01B94001F2B85 /* ProgramCourseGroupBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC206EF02CF01B94001F2B85 /* ProgramCourseGroupBodyView.m */; };
+		BC206EF42CF01D4A001F2B85 /* GroupCourseSortView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC206EF32CF01D4A001F2B85 /* GroupCourseSortView.m */; };
+		BC206EF62CF01D53001F2B85 /* GroupCourseSortView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC206EF52CF01D53001F2B85 /* GroupCourseSortView.xib */; };
 		BC221FA128C72B9500F99802 /* MyStyleVideoView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC221F9D28C72B9500F99802 /* MyStyleVideoView.xib */; };
 		BC221FA228C72B9500F99802 /* MyStyleVideoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC221F9E28C72B9500F99802 /* MyStyleVideoCell.xib */; };
 		BC221FA328C72B9500F99802 /* MyStyleVideoView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC221F9F28C72B9500F99802 /* MyStyleVideoView.m */; };
@@ -468,6 +475,17 @@
 		BC33000F2BBAB5ED003D4921 /* KnowledgePointListModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC33000A2BBAB5ED003D4921 /* KnowledgePointListModel.m */; };
 		BC3300102BBAB5ED003D4921 /* MaterialList.m in Sources */ = {isa = PBXBuildFile; fileRef = BC33000C2BBAB5ED003D4921 /* MaterialList.m */; };
 		BC332DB3284866BE005AEF95 /* KSOrderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BC332DB1284866BE005AEF95 /* KSOrderManager.m */; };
+		BC366FBD2CF0221000583E61 /* CourseGroupNavView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC366FBC2CF0221000583E61 /* CourseGroupNavView.m */; };
+		BC366FBF2CF0221800583E61 /* CourseGroupNavView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC366FBE2CF0221800583E61 /* CourseGroupNavView.xib */; };
+		BC366FC22CF0237A00583E61 /* CourseGroupPlanAddView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC366FC12CF0237A00583E61 /* CourseGroupPlanAddView.m */; };
+		BC366FC42CF0238500583E61 /* CourseGroupPlanAddView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC366FC32CF0238500583E61 /* CourseGroupPlanAddView.xib */; };
+		BC366FC72CF028B800583E61 /* CourseGroupPlanDescView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC366FC62CF028B800583E61 /* CourseGroupPlanDescView.m */; };
+		BC366FC92CF028C300583E61 /* CourseGroupPlanDescView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC366FC82CF028C300583E61 /* CourseGroupPlanDescView.xib */; };
+		BC366FCC2CF05E4200583E61 /* CourseGroupPlanAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC366FCB2CF05E4200583E61 /* CourseGroupPlanAlertView.m */; };
+		BC366FCE2CF05E4E00583E61 /* CourseGroupPlanAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC366FCD2CF05E4E00583E61 /* CourseGroupPlanAlertView.xib */; };
+		BC366FD32CF0610400583E61 /* CourseStudentVos.m in Sources */ = {isa = PBXBuildFile; fileRef = BC366FD02CF0610400583E61 /* CourseStudentVos.m */; };
+		BC366FD42CF0610400583E61 /* GroupCourseListModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC366FD22CF0610400583E61 /* GroupCourseListModel.m */; };
+		BC366FD72CF067F700583E61 /* CourseGroupDetailModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC366FD62CF067F700583E61 /* CourseGroupDetailModel.m */; };
 		BC3673D428A606A500059721 /* musicRoom_animation_3.png in Resources */ = {isa = PBXBuildFile; fileRef = BC3673C828A606A400059721 /* musicRoom_animation_3.png */; };
 		BC3673D528A606A500059721 /* live_animation_2.png in Resources */ = {isa = PBXBuildFile; fileRef = BC3673C928A606A400059721 /* live_animation_2.png */; };
 		BC3673D628A606A500059721 /* live_animation_0.png in Resources */ = {isa = PBXBuildFile; fileRef = BC3673CA28A606A400059721 /* live_animation_0.png */; };
@@ -1856,6 +1874,17 @@
 		BC206EDB2CEF2623001F2B85 /* MusicRoomCourseCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicRoomCourseCell.h; sourceTree = "<group>"; };
 		BC206EDC2CEF2623001F2B85 /* MusicRoomCourseCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MusicRoomCourseCell.m; sourceTree = "<group>"; };
 		BC206EDD2CEF2623001F2B85 /* MusicRoomCourseCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MusicRoomCourseCell.xib; sourceTree = "<group>"; };
+		BC206EE52CF015A9001F2B85 /* ProgramCourseInfoView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProgramCourseInfoView.h; sourceTree = "<group>"; };
+		BC206EE62CF015A9001F2B85 /* ProgramCourseInfoView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProgramCourseInfoView.m; sourceTree = "<group>"; };
+		BC206EE82CF015B0001F2B85 /* ProgramCourseInfoView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ProgramCourseInfoView.xib; sourceTree = "<group>"; };
+		BC206EEA2CF01838001F2B85 /* ProgramCourseListCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProgramCourseListCell.h; sourceTree = "<group>"; };
+		BC206EEB2CF01838001F2B85 /* ProgramCourseListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProgramCourseListCell.m; sourceTree = "<group>"; };
+		BC206EEC2CF01838001F2B85 /* ProgramCourseListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ProgramCourseListCell.xib; sourceTree = "<group>"; };
+		BC206EEF2CF01B94001F2B85 /* ProgramCourseGroupBodyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProgramCourseGroupBodyView.h; sourceTree = "<group>"; };
+		BC206EF02CF01B94001F2B85 /* ProgramCourseGroupBodyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProgramCourseGroupBodyView.m; sourceTree = "<group>"; };
+		BC206EF22CF01D4A001F2B85 /* GroupCourseSortView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GroupCourseSortView.h; sourceTree = "<group>"; };
+		BC206EF32CF01D4A001F2B85 /* GroupCourseSortView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GroupCourseSortView.m; sourceTree = "<group>"; };
+		BC206EF52CF01D53001F2B85 /* GroupCourseSortView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = GroupCourseSortView.xib; sourceTree = "<group>"; };
 		BC221F9B28C72B9500F99802 /* MyStyleVideoView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyStyleVideoView.h; sourceTree = "<group>"; };
 		BC221F9C28C72B9500F99802 /* MyStyleVideoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyStyleVideoCell.h; sourceTree = "<group>"; };
 		BC221F9D28C72B9500F99802 /* MyStyleVideoView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyStyleVideoView.xib; sourceTree = "<group>"; };
@@ -2001,6 +2030,24 @@
 		BC33000C2BBAB5ED003D4921 /* MaterialList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MaterialList.m; sourceTree = "<group>"; };
 		BC332DB1284866BE005AEF95 /* KSOrderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSOrderManager.m; sourceTree = "<group>"; };
 		BC332DB2284866BE005AEF95 /* KSOrderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSOrderManager.h; sourceTree = "<group>"; };
+		BC366FBB2CF0221000583E61 /* CourseGroupNavView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CourseGroupNavView.h; sourceTree = "<group>"; };
+		BC366FBC2CF0221000583E61 /* CourseGroupNavView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CourseGroupNavView.m; sourceTree = "<group>"; };
+		BC366FBE2CF0221800583E61 /* CourseGroupNavView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CourseGroupNavView.xib; sourceTree = "<group>"; };
+		BC366FC02CF0237A00583E61 /* CourseGroupPlanAddView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CourseGroupPlanAddView.h; sourceTree = "<group>"; };
+		BC366FC12CF0237A00583E61 /* CourseGroupPlanAddView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CourseGroupPlanAddView.m; sourceTree = "<group>"; };
+		BC366FC32CF0238500583E61 /* CourseGroupPlanAddView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CourseGroupPlanAddView.xib; sourceTree = "<group>"; };
+		BC366FC52CF028B800583E61 /* CourseGroupPlanDescView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CourseGroupPlanDescView.h; sourceTree = "<group>"; };
+		BC366FC62CF028B800583E61 /* CourseGroupPlanDescView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CourseGroupPlanDescView.m; sourceTree = "<group>"; };
+		BC366FC82CF028C300583E61 /* CourseGroupPlanDescView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CourseGroupPlanDescView.xib; sourceTree = "<group>"; };
+		BC366FCA2CF05E4200583E61 /* CourseGroupPlanAlertView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CourseGroupPlanAlertView.h; sourceTree = "<group>"; };
+		BC366FCB2CF05E4200583E61 /* CourseGroupPlanAlertView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CourseGroupPlanAlertView.m; sourceTree = "<group>"; };
+		BC366FCD2CF05E4E00583E61 /* CourseGroupPlanAlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CourseGroupPlanAlertView.xib; sourceTree = "<group>"; };
+		BC366FCF2CF0610400583E61 /* CourseStudentVos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CourseStudentVos.h; sourceTree = "<group>"; };
+		BC366FD02CF0610400583E61 /* CourseStudentVos.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CourseStudentVos.m; sourceTree = "<group>"; };
+		BC366FD12CF0610400583E61 /* GroupCourseListModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GroupCourseListModel.h; sourceTree = "<group>"; };
+		BC366FD22CF0610400583E61 /* GroupCourseListModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GroupCourseListModel.m; sourceTree = "<group>"; };
+		BC366FD52CF067F700583E61 /* CourseGroupDetailModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CourseGroupDetailModel.h; sourceTree = "<group>"; };
+		BC366FD62CF067F700583E61 /* CourseGroupDetailModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CourseGroupDetailModel.m; sourceTree = "<group>"; };
 		BC3673C828A606A400059721 /* musicRoom_animation_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = musicRoom_animation_3.png; sourceTree = "<group>"; };
 		BC3673C928A606A400059721 /* live_animation_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = live_animation_2.png; sourceTree = "<group>"; };
 		BC3673CA28A606A400059721 /* live_animation_0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = live_animation_0.png; sourceTree = "<group>"; };
@@ -4091,6 +4138,7 @@
 		2779360927E32BBF0010E277 /* View */ = {
 			isa = PBXGroup;
 			children = (
+				BC366FBA2CF0220200583E61 /* CourseGroupView */,
 				BCB399AA27F946A200AFF376 /* CourseNavView.h */,
 				BCB399AB27F946A200AFF376 /* CourseNavView.m */,
 				BCB399AD27F946AA00AFF376 /* CourseNavView.xib */,
@@ -5228,6 +5276,28 @@
 			path = CoursewareDownload;
 			sourceTree = "<group>";
 		};
+		BC366FBA2CF0220200583E61 /* CourseGroupView */ = {
+			isa = PBXGroup;
+			children = (
+				BC366FBB2CF0221000583E61 /* CourseGroupNavView.h */,
+				BC366FBC2CF0221000583E61 /* CourseGroupNavView.m */,
+				BC366FBE2CF0221800583E61 /* CourseGroupNavView.xib */,
+				BC366FC02CF0237A00583E61 /* CourseGroupPlanAddView.h */,
+				BC366FC12CF0237A00583E61 /* CourseGroupPlanAddView.m */,
+				BC366FC32CF0238500583E61 /* CourseGroupPlanAddView.xib */,
+				BC366FC52CF028B800583E61 /* CourseGroupPlanDescView.h */,
+				BC366FC62CF028B800583E61 /* CourseGroupPlanDescView.m */,
+				BC366FC82CF028C300583E61 /* CourseGroupPlanDescView.xib */,
+				BC206EF22CF01D4A001F2B85 /* GroupCourseSortView.h */,
+				BC206EF32CF01D4A001F2B85 /* GroupCourseSortView.m */,
+				BC206EF52CF01D53001F2B85 /* GroupCourseSortView.xib */,
+				BC366FCA2CF05E4200583E61 /* CourseGroupPlanAlertView.h */,
+				BC366FCB2CF05E4200583E61 /* CourseGroupPlanAlertView.m */,
+				BC366FCD2CF05E4E00583E61 /* CourseGroupPlanAlertView.xib */,
+			);
+			path = CourseGroupView;
+			sourceTree = "<group>";
+		};
 		BC38C3FF2AF900E100ABFCC2 /* MediaMerge */ = {
 			isa = PBXGroup;
 			children = (
@@ -7584,6 +7654,12 @@
 		BCFB9B842CE487EA00B66BC0 /* Model */ = {
 			isa = PBXGroup;
 			children = (
+				BC366FCF2CF0610400583E61 /* CourseStudentVos.h */,
+				BC366FD02CF0610400583E61 /* CourseStudentVos.m */,
+				BC366FD12CF0610400583E61 /* GroupCourseListModel.h */,
+				BC366FD22CF0610400583E61 /* GroupCourseListModel.m */,
+				BC366FD52CF067F700583E61 /* CourseGroupDetailModel.h */,
+				BC366FD62CF067F700583E61 /* CourseGroupDetailModel.m */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -7594,6 +7670,14 @@
 				BCFB9B8A2CE48D3A00B66BC0 /* VipCouseInfoCell.h */,
 				BCFB9B8B2CE48D3A00B66BC0 /* VipCouseInfoCell.m */,
 				BCFB9B8C2CE48D3A00B66BC0 /* VipCouseInfoCell.xib */,
+				BC206EE52CF015A9001F2B85 /* ProgramCourseInfoView.h */,
+				BC206EE62CF015A9001F2B85 /* ProgramCourseInfoView.m */,
+				BC206EE82CF015B0001F2B85 /* ProgramCourseInfoView.xib */,
+				BC206EEA2CF01838001F2B85 /* ProgramCourseListCell.h */,
+				BC206EEB2CF01838001F2B85 /* ProgramCourseListCell.m */,
+				BC206EEC2CF01838001F2B85 /* ProgramCourseListCell.xib */,
+				BC206EEF2CF01B94001F2B85 /* ProgramCourseGroupBodyView.h */,
+				BC206EF02CF01B94001F2B85 /* ProgramCourseGroupBodyView.m */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -7836,6 +7920,7 @@
 				277931CE27E30FC20010E277 /* KSPremissionAlert.xib in Resources */,
 				BC4058942863028C00111BC5 /* NotiferNavView.xib in Resources */,
 				275E3DFC27F46B440010EC30 /* KSBeautySettingView.xib in Resources */,
+				BC206EE92CF015B0001F2B85 /* ProgramCourseInfoView.xib in Resources */,
 				BC38C48B2AFA207B00ABFCC2 /* KSEmptyStatusView.xib in Resources */,
 				BC48C3B5282931C000EE65C5 /* ReceiveEvaluateCell.xib in Resources */,
 				BC42CAB12BEC9CDA001F076E /* RhythmView.xib in Resources */,
@@ -7870,6 +7955,7 @@
 				BC71DEFE2A89F470003F165E /* TXTimeView.xib in Resources */,
 				BC4217FD2C4E3DFC00C70B2F /* KSUserDetailBottomView.xib in Resources */,
 				BC3673DE28A606A500059721 /* musicRoom_animation_1.png in Resources */,
+				BC366FCE2CF05E4E00583E61 /* CourseGroupPlanAlertView.xib in Resources */,
 				BC1553532AB3279500C1C347 /* TenentGroupAddMemberCell.xib in Resources */,
 				BCC0F7062A8CF13D00C4EFA4 /* TXDanBottomView.xib in Resources */,
 				BCC408E92AFCE11900C60249 /* MusicPublistAlert.xib in Resources */,
@@ -7966,6 +8052,7 @@
 				BC31BF8F2B219C5700F7D538 /* TuningForkSettingView.xib in Resources */,
 				BCEA75282819103B00886A86 /* UnbindBodyView.xib in Resources */,
 				BC8B6E602856ED0600866917 /* WeiboSDK.bundle in Resources */,
+				BC206EED2CF01838001F2B85 /* ProgramCourseListCell.xib in Resources */,
 				27F9030827E86CCB00C08A19 /* DeviceCheckView.xib in Resources */,
 				BC71D1FA2887FDD40010F14B /* img_14.png in Resources */,
 				BC523B1228A09F3800E9D66B /* MineHeadView.xib in Resources */,
@@ -7995,6 +8082,7 @@
 				BC15535C2AB33B0300C1C347 /* TenantCreateStuView.xib in Resources */,
 				BC8B6E562856ED0600866917 /* iOS集成升级必读.pdf in Resources */,
 				BC8B6E6A28575DEE00866917 /* MusicDisplayView.xib in Resources */,
+				BC366FC92CF028C300583E61 /* CourseGroupPlanDescView.xib in Resources */,
 				BCD160732CED8DF600A78B43 /* CourseDescAlertCell.xib in Resources */,
 				BCA9AC492CED921100047BFA /* MyVideoGroupListCell.xib in Resources */,
 				BCD160742CED8DF600A78B43 /* CourseDescAlertView.xib in Resources */,
@@ -8053,6 +8141,7 @@
 				BCFE541A2817BE0800AD6786 /* IncomeHeaderView.xib in Resources */,
 				BC71D1F32887FDD40010F14B /* img_7.png in Resources */,
 				BCE6A0A527F8517900C97704 /* MineVideoCell.xib in Resources */,
+				BC206EF62CF01D53001F2B85 /* GroupCourseSortView.xib in Resources */,
 				BC31BF842B219C5700F7D538 /* tock.wav in Resources */,
 				BCC9F40727F69BD200647449 /* SealClass.strings in Resources */,
 				BCD6D16C28195FC5009A773E /* CashRecordHeadView.xib in Resources */,
@@ -8155,6 +8244,7 @@
 				BC2858302809451B0024697C /* EvaluateCouseCell.xib in Resources */,
 				BC8B6E6D285836B600866917 /* high_staff.png in Resources */,
 				BC71D1F72887FDD40010F14B /* img_15.png in Resources */,
+				BC366FC42CF0238500583E61 /* CourseGroupPlanAddView.xib in Resources */,
 				BC81F0EA29232D01004106AF /* CoursewareListCell.xib in Resources */,
 				BC71D1F92887FDD40010F14B /* img_5.png in Resources */,
 				BCA724002806AEA000DA0D0D /* AccompanyHomeworkCell.xib in Resources */,
@@ -8179,6 +8269,7 @@
 				BC15534A2AB31EF200C1C347 /* TenangGroupCreateBottomView.xib in Resources */,
 				BCDF820D2A8A2955005F8B82 /* MemberSettingMicAlert.xib in Resources */,
 				275E3DE327F467410010EC30 /* BaseEmoji.plist in Resources */,
+				BC366FBF2CF0221800583E61 /* CourseGroupNavView.xib in Resources */,
 				BC71DF072A89F470003F165E /* ClassRoomTitleButton.xib in Resources */,
 				BCC5842028AA559700BAB4CF /* cloud_animation_29.png in Resources */,
 				273C75A027E9681700F7C26F /* SettingBodyView.xib in Resources */,
@@ -8335,6 +8426,7 @@
 				BC106B302A8F4541000759A9 /* TXLiveRoomTimeManager.m in Sources */,
 				BC4BCE702823A02F00522C8B /* AddressBottomView.m in Sources */,
 				BCA724042806AFF100DA0D0D /* AccompanyCourseInfoCell.m in Sources */,
+				BC366FBD2CF0221000583E61 /* CourseGroupNavView.m in Sources */,
 				BC7F7B702C92D04700265AE1 /* KSDeleteAccountTipsAlert.m in Sources */,
 				BC71DE952A89C937003F165E /* TXClassroomMemberChange.m in Sources */,
 				BCA1135328A242FD007FAFB9 /* HomeBannerView.m in Sources */,
@@ -8472,6 +8564,8 @@
 				BC56C97C2923A3FD00AF301F /* CoursewareAlertCell.m in Sources */,
 				BCC408E52AFCE11900C60249 /* MusicPublistAlert.m in Sources */,
 				275E3DE227F467410010EC30 /* KSChatEmojiCollectionCell.m in Sources */,
+				BC366FD32CF0610400583E61 /* CourseStudentVos.m in Sources */,
+				BC366FD42CF0610400583E61 /* GroupCourseListModel.m in Sources */,
 				BC14E4952AB31059000C4983 /* TenantCreateGroupBodyView.m in Sources */,
 				BCA1134828A22A66007FAFB9 /* HomeHotMusicCollectionCell.m in Sources */,
 				BCDF820E2A8A2955005F8B82 /* MemberSettingMicAlert.m in Sources */,
@@ -8527,6 +8621,7 @@
 				BC71DF252A8A014F003F165E /* KSImageDisplayView.m in Sources */,
 				BC31BF942B219C5700F7D538 /* ToneTuningBodyView.m in Sources */,
 				BC7B0F5029271B5E0044CF61 /* CourseWarePreviewView.m in Sources */,
+				BC206EE72CF015A9001F2B85 /* ProgramCourseInfoView.m in Sources */,
 				BC28886D2A8101310064B773 /* KSSearchResultListController.m in Sources */,
 				BC106BA42A8F45AA000759A9 /* TXLiveChatListCell.m in Sources */,
 				BC31BF9C2B219C5700F7D538 /* WidgetBottomButtonView.m in Sources */,
@@ -8577,6 +8672,7 @@
 				BC7CFFC92817F2FF00CAEB21 /* CashRecordListCell.m in Sources */,
 				BCECE2122B3D5F0800C0D555 /* FeedbackListViewController.m in Sources */,
 				BC7CFFBE2817F1D200CAEB21 /* MyBankCardViewController.m in Sources */,
+				BC366FCC2CF05E4200583E61 /* CourseGroupPlanAlertView.m in Sources */,
 				BCA9CE1E27FD5F9D00D558C6 /* MyLiveCourseViewController.m in Sources */,
 				27D83F4227F3EAA700062476 /* MinePageVideoView.m in Sources */,
 				BCDF822C2A8A30AE005F8B82 /* KSTrackingSlider.m in Sources */,
@@ -8607,6 +8703,7 @@
 				2779361E27E3338E0010E277 /* KSUpdateManager.m in Sources */,
 				BCC9F42827F69BD200647449 /* WhiteUtils.m in Sources */,
 				BC106BB42A8F4BC9000759A9 /* LiveModuleService.m in Sources */,
+				BC366FC72CF028B800583E61 /* CourseGroupPlanDescView.m in Sources */,
 				BCAF36EE2CEAE3E8009434AD /* FansGroupAlertView.m in Sources */,
 				BCDF822F2A8A3176005F8B82 /* KSValuePopView.m in Sources */,
 				BCEA75262819103300886A86 /* UnbindBodyView.m in Sources */,
@@ -8620,6 +8717,7 @@
 				27F9CB0E27EC5DF5003E0FE4 /* KSRCloudMediaManager.m in Sources */,
 				BC38C49E2AFA4C7D00ABFCC2 /* KSProgressLoadingView.m in Sources */,
 				BC221FB928C8687300F99802 /* MusicSortView.m in Sources */,
+				BC366FC22CF0237A00583E61 /* CourseGroupPlanAddView.m in Sources */,
 				BC4BCE7D2823B66000522C8B /* AddressDetailBodyView.m in Sources */,
 				BC38C4222AF900E100ABFCC2 /* KSPlayerView.m in Sources */,
 				BCA9AC442CED91F200047BFA /* MyLiveCourseGroupListCell.m in Sources */,
@@ -8657,6 +8755,7 @@
 				BC14E47F2AB2EE58000C4983 /* UnbindBottomView.m in Sources */,
 				BC2C1BA12CEB25DE00EDEB97 /* MineLiveCourseGroupCell.m in Sources */,
 				BC7CFFB22817E6DB00CAEB21 /* KSMutilDatePicker.m in Sources */,
+				BC206EF12CF01B94001F2B85 /* ProgramCourseGroupBodyView.m in Sources */,
 				BCED5CAA284F5D8D009A42DE /* FriendListModel.m in Sources */,
 				BC7B0F5529276D980044CF61 /* KSWareSliderView.m in Sources */,
 				BCEA752B2819133E00886A86 /* CardBindResultBodyView.m in Sources */,
@@ -8841,6 +8940,7 @@
 				BC56C96A2923736200AF301F /* KSHudLoagingManager.m in Sources */,
 				BCD160692CED86FB00A78B43 /* MyCourseGroupNavView.m in Sources */,
 				BC8A2CF828476C3000122BBE /* MusicScoreViewController.m in Sources */,
+				BC366FD72CF067F700583E61 /* CourseGroupDetailModel.m in Sources */,
 				BC71DEF72A89F470003F165E /* TXChatAreaView.m in Sources */,
 				BCB9FA1F286D539A005D766B /* ScanNavView.m in Sources */,
 				BC106B782A8F4586000759A9 /* TXLiveMessageSeatApply.m in Sources */,
@@ -8852,6 +8952,7 @@
 				BC71DF1C2A89F470003F165E /* IACircleSliderThumbLayer.m in Sources */,
 				BC31BF912B219C5700F7D538 /* TunerSettingView.m in Sources */,
 				2779320927E30FC30010E277 /* KSRecordPowerAnimationView.m in Sources */,
+				BC206EEE2CF01838001F2B85 /* ProgramCourseListCell.m in Sources */,
 				BC106C552A9365DE000759A9 /* ClassMemberEmptyView.m in Sources */,
 				BC02BCE628B324C9005CB483 /* LiveDownSeatView.m in Sources */,
 				27BC3B3327F2FD2D00D81E30 /* VideoListBodyView.m in Sources */,
@@ -8876,6 +8977,7 @@
 				BCD1607B2CED8EA700A78B43 /* MyProgramCourseGroupCell.m in Sources */,
 				BC38C42A2AF900E100ABFCC2 /* KSAudioPlayAnimationView.m in Sources */,
 				BC71DF0E2A89F470003F165E /* KSRateSliderView.m in Sources */,
+				BC206EF42CF01D4A001F2B85 /* GroupCourseSortView.m in Sources */,
 				BC7DEC9D2C2D555800154524 /* AudioEnginePlayer.m in Sources */,
 				2779326427E30FD80010E277 /* FSCalendarDelegationProxy.m in Sources */,
 				BC106B852A8F4586000759A9 /* TXLiveMessageCardMessage.m in Sources */,

+ 22 - 0
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/courseDetail_bg.imageset/Contents.json

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

BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/courseDetail_bg.imageset/courseDetail_bg@2x.png


BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/courseDetail_bg.imageset/courseDetail_bg@3x.png


+ 22 - 0
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_attendence.imageset/Contents.json

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

BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_attendence.imageset/course_attendence@2x.png


BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_attendence.imageset/course_attendence@3x.png


+ 22 - 0
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_noArrive.imageset/Contents.json

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

BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_noArrive.imageset/course_noArrive@2x.png


BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_noArrive.imageset/course_noArrive@3x.png


+ 22 - 0
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_plan_icon.imageset/Contents.json

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

BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_plan_icon.imageset/course_plan_icon@2x.png


BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/course_plan_icon.imageset/course_plan_icon@3x.png


+ 22 - 0
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/group_addPlan.imageset/Contents.json

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

BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/group_addPlan.imageset/group_addPlan@2x.png


BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/group_addPlan.imageset/group_addPlan@3x.png


+ 22 - 0
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/plan_edit.imageset/Contents.json

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

BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/plan_edit.imageset/plan_edit@2x.png


BIN
KulexiuForTeacher/KulexiuForTeacher/Assets.xcassets/MyCourse/plan_edit.imageset/plan_edit@3x.png


+ 29 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.h

@@ -1640,6 +1640,35 @@ NS_ASSUME_NONNULL_BEGIN
 /// @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;
 
+// courseGroup/getCourseGroup
 
+/// 查询课程组详情
+/// @param post post
+/// @param courseGroupId 课程组编号
+/// @param success 成功
+/// @param faliure 失败
++ (void)getCourseGroupDetailRequest:(NSString *)post courseGroupId:(NSString *)courseGroupId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
+// /courseSchedule/list
+
+/// 查询课程组关联课程
+/// @param post post
+/// @param courseGroupId 课程组编号
+/// @param classMonth 年月
+/// @param attendanceStatus 考勤状态
+/// @param status 课程状态
+/// @param success 成功
+/// @param faliure 失败
++ (void)courseScheduleListRequest:(NSString *)post courseGroupId:(NSString *)courseGroupId classMonth:(NSString *)classMonth attendanceStatus:(NSString *)attendanceStatus courseStatus:(NSString *)status success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
+// courseGroup/updateCoursePlan
+
+/// 更新课程规划
+/// @param post post
+/// @param courseGroupId 课程组编号
+/// @param coursePlan 课程规划
+/// @param success 成功
+/// @param faliure 失败
++ (void)updateCoursePlanRequset:(NSString *)post courseGroupId:(NSString *)courseGroupId coursePlan:(NSString *)coursePlan success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
 @end
 NS_ASSUME_NONNULL_END

+ 56 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/KSNetworkingManager.m

@@ -3023,4 +3023,60 @@
     [parm setValue:status forKey:@"status"];
     [self request:post andWithUrl:url and:parm success:success faliure:faliure];
 }
+
+// courseGroup/getCourseGroup
+
+/// 查询课程组详情
+/// @param post post
+/// @param courseGroupId 课程组编号
+/// @param success 成功
+/// @param faliure 失败
++ (void)getCourseGroupDetailRequest:(NSString *)post courseGroupId:(NSString *)courseGroupId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    [self configRequestMethodForm];
+    NSString *url = [NSString stringWithFormat:@"%@%@",hostURL, @"/api-teacher/courseGroup/getCourseGroup"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:courseGroupId forKey:@"courseGroupId"];
+    [self request:post andWithUrl:url and:parm success:success faliure:faliure];
+}
+
+// /courseSchedule/list
+
+/// 查询课程组关联课程
+/// @param post post
+/// @param courseGroupId 课程组编号
+/// @param classMonth 年月
+/// @param attendanceStatus 考勤状态
+/// @param status 课程状态
+/// @param success 成功
+/// @param faliure 失败
++ (void)courseScheduleListRequest:(NSString *)post courseGroupId:(NSString *)courseGroupId classMonth:(NSString *)classMonth attendanceStatus:(NSString *)attendanceStatus courseStatus:(NSString *)status success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    
+    [self configRequestMethodJSON];
+    NSString *url = [NSString stringWithFormat:@"%@%@",hostURL, @"/api-teacher/courseSchedule/list"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:courseGroupId forKey:@"courseGroupId"];
+    [parm setValue:classMonth forKey:@"classMonth"];
+    [parm setValue:attendanceStatus forKey:@"attendanceStatus"];
+    [parm setValue:status forKey:@"status"];
+    [self request:post andWithUrl:url and:parm success:success faliure:faliure];
+}
+
+// courseGroup/updateCoursePlan
+
+/// 更新课程规划
+/// @param post post
+/// @param courseGroupId 课程组编号
+/// @param coursePlan 课程规划
+/// @param success 成功
+/// @param faliure 失败
++ (void)updateCoursePlanRequset:(NSString *)post courseGroupId:(NSString *)courseGroupId coursePlan:(NSString *)coursePlan success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+  
+    [self configRequestMethodForm];
+    NSString *url = [NSString stringWithFormat:@"%@%@",hostURL, @"/api-teacher/courseGroup/updateCoursePlan"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:courseGroupId forKey:@"groupId"];
+    [parm setValue:coursePlan forKey:@"coursePlan"];
+    [self request:post andWithUrl:url and:parm success:success faliure:faliure];
+}
+
 @end

+ 5 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/AccompanyCourse/Controller/AccompanyCourseGroupViewController.h

@@ -6,6 +6,8 @@
 //
 
 #import "KSBaseViewController.h"
+#import "JXCategoryView.h"
+#import "JXPagerView.h"
 
 NS_ASSUME_NONNULL_BEGIN
 // 趣纠课--课程组
@@ -13,6 +15,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 @property (nonatomic, strong) NSString *courseGroupId; // 课程组ID
 
+@property (nonatomic, strong) JXPagerView *pagerView;
+@property (nonatomic, strong, readonly) JXCategoryTitleView *categoryView;
+@property (nonatomic, strong) NSArray <NSString *> *titles;
 @end
 
 NS_ASSUME_NONNULL_END

+ 191 - 67
KulexiuForTeacher/KulexiuForTeacher/Module/Course/AccompanyCourse/Controller/AccompanyCourseGroupViewController.m

@@ -7,23 +7,29 @@
 
 #import "AccompanyCourseGroupViewController.h"
 #import <RecordCheckManager.h>
-#import "KSPremissionAlert.h"
-#import "OnlineClassManager.h"
-#import "HomeworkDetailModel.h"
+#import "CourseGroupNavView.h"
+#import "JXCategoryView.h"
+#import "JXPagerListRefreshView.h"
+#import "ProgramCourseInfoView.h"
+#import "ProgramCourseGroupBodyView.h"
+#import "CourseGroupDetailModel.h"
+#import "CourseGroupPlanAlertView.h"
 
-@interface AccompanyCourseGroupViewController ()
+@interface AccompanyCourseGroupViewController ()<JXPagerViewDelegate,JXCategoryViewDelegate>
 
-@property (nonatomic, strong) NSString *courseId;
+@property (nonatomic, strong) NSMutableArray *listViewArray;
 
-@property (nonatomic, strong) NSString *studentId;
+@property (nonatomic, strong) CourseGroupNavView *navView;
 
-@property (nonatomic, assign) NSInteger joinRoomBeforeTime; // 上课开始时间
+@property (nonatomic, assign) NSInteger headHeight;
 
-@property (nonatomic, assign) NSInteger quitRomeEndTime;    // 下课截止时间
+@property (nonatomic, assign) NSInteger topViewHeight;
 
-@property (nonatomic, strong) HomeworkDetailModel *homeworkModel;
+@property (nonatomic, strong) ProgramCourseInfoView *infoView;
 
-@property (nonatomic, strong) OnlineClassManager *classManager;
+@property (nonatomic, assign) BOOL isFirstLoad;
+
+@property (nonatomic, strong) CourseGroupDetailModel *detailModel;
 
 @end
 
@@ -32,86 +38,204 @@
 - (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
+    self.ks_prefersNavigationBarHidden = YES;
+    [self configUI];
+    self.isFirstLoad = YES;
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(forceScroll) name:@"UITextViewScroll" object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enableScroll) name:@"UITextViewEndScroll" object:nil];
 }
 
+- (void)forceScroll {
+    self.pagerView.mainTableView.scrollEnabled = NO;
+}
 
-- (void)tryJoinRoom {
-    
-    NSDateFormatter *dateFormatter = [NSObject getDateformatter];
-    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
-    NSDate *beginDate = [dateFormatter dateFromString:self.homeworkModel.startTime];
-    NSDate *endDate = [dateFormatter dateFromString:self.homeworkModel.endTime];
-    NSDate *currentDate = [NSDate date];
-    NSTimeInterval beginTimeInterval = [beginDate timeIntervalSinceDate:currentDate];
-    NSTimeInterval endTimeInterval = [currentDate timeIntervalSinceDate:endDate];
-    if (beginTimeInterval <= self.joinRoomBeforeTime * 60 && endTimeInterval < 0) {
-        [self joinClassRoom];
-    }
-    else if (endTimeInterval > 0) {
-        [LOADING_MANAGER MBShowAUTOHidingInWindow:@"该课程已结束"];
-    }
-    else {
-        NSString *tipsString = [NSString stringWithFormat:@"课程还未开始,请在上课前%zd分钟进入", self.joinRoomBeforeTime];
-        [LOADING_MANAGER MBShowAUTOHidingInWindow:tipsString];
-    }
+- (void)enableScroll {
+    self.pagerView.mainTableView.scrollEnabled = YES;
 }
 
-// 加入房间
-- (void)joinClassRoom {
+- (void)configUI {
+    [self.scrollView removeFromSuperview];
+    UIImage *bgImage = [UIImage imageNamed:@"courseDetail_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];
     
-    // 加入房间前判断摄像头和麦克风逻辑
-    [RecordCheckManager checkCameraPremissionAvaiableCallback:^(PREMISSIONTYPE type) {
-        [self afterCheckCameraCheckMic:type];
+    [self.view addSubview:self.navView];
+    CGFloat navHeight = [CourseGroupNavView getViewHeight];
+    [self.navView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.mas_equalTo(self.view);
+        make.height.mas_equalTo(navHeight);
     }];
+    self.headHeight = CGFLOAT_MIN;
+    self.titles = @[@""];
+    [self configCategoryView:navHeight];
 }
 
-- (void)afterCheckCameraCheckMic:(PREMISSIONTYPE)cameraType {
-    [RecordCheckManager checkMicPermissionAvaiableCallback:^(PREMISSIONTYPE type) {
-        if (type == PREMISSIONTYPE_YES && cameraType == PREMISSIONTYPE_YES) {
-            // 判断是否进行课前检测
-            [self.classManager joinRoomWithId:self.courseId subjectName:self.homeworkModel.subjectName classEndTime:self.homeworkModel.endTime inViewController:self];
+- (void)requestCourseInfo {
+    
+    [KSNetworkingManager getCourseGroupDetailRequest:KS_POST courseGroupId:self.courseGroupId success:^(NSDictionary * _Nonnull dic) {
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSDictionary *parm = [dic ks_dictionaryValueForKey:@"data"];
+            self.detailModel = [[CourseGroupDetailModel alloc] initWithDictionary:parm];
         }
         else {
-            NSString *content = @"";
-            CHECKDEVICETYPE checkType = CHECKDEVICETYPE_BOTH;
-            if (cameraType == PREMISSIONTYPE_NO && type == PREMISSIONTYPE_NO) {
-                content = @"请开启相机和麦克风访问权限";
-                checkType = CHECKDEVICETYPE_BOTH;
-            }
-            else if (cameraType == PREMISSIONTYPE_NO && type == PREMISSIONTYPE_YES) {
-                content =  @"请开启相机访问权限";
-                checkType = CHECKDEVICETYPE_CAMREA;
-            }
-            else if (cameraType == PREMISSIONTYPE_YES && type == PREMISSIONTYPE_NO) {
-                content = @"请开启麦克风访问权限";
-                checkType = CHECKDEVICETYPE_MIC;
-            }
-            [self showAlertWithMessage:content type:checkType];
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
         }
+        [self refreshHeadView];
+    } faliure:^(NSError * _Nonnull error) {
+        [self refreshHeadView];
     }];
-    
 }
 
-- (void)showAlertWithMessage:(NSString *)message type:(CHECKDEVICETYPE)deviceType {
-    [KSPremissionAlert shareInstanceDisplayImage:deviceType message:message showInView:self.view cancel:^{
-        
-    } confirm:^{
-        [self openSettingView];
-    }];
+- (void)refreshHeadView {
+    self.topViewHeight = [ProgramCourseInfoView getViewHeightWithPlanString:self.detailModel.coursePlan];
+    [self.infoView configWithSource:self.detailModel];
+    [self.pagerView reloadData];
+}
+
+- (void)configCategoryView:(NSInteger)topHeight {
+    
+    _categoryView = [[JXCategoryTitleView alloc] initWithFrame:CGRectMake(0, topHeight, KPortraitWidth, self.headHeight)];
+    self.categoryView.titles = self.titles;
+    self.categoryView.delegate = self;
+    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;
     
+    _pagerView = [self preferredPagingView];
+    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];
+//    self.pagerView.mainTableView.gestureDelegate = self;
+    self.categoryView.listContainer = (id<JXCategoryViewListContainer>)self.pagerView.listContainerView;
+    self.pagerView.listContainerView.listCellBackgroundColor = [UIColor clearColor];
+    [self.view addSubview:self.pagerView];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    self.navigationController.interactivePopGestureRecognizer.enabled = (self.categoryView.selectedIndex == 0);
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    self.navigationController.interactivePopGestureRecognizer.enabled = YES;
+    if (self.isFirstLoad == NO) {
+        [self refreshListPage];
+    }
+    self.isFirstLoad = NO;
+    [self requestCourseInfo];
+}
+
+- (void)refreshListPage {
+    id value = self.listViewArray[0];
+    if ([value isKindOfClass:[KSJXBodyView class]]) {
+        KSJXBodyView *listView = (KSJXBodyView *)value;
+        [listView beginFirstRefresh];
+    }
+}
+
+- (JXPagerView *)preferredPagingView {
+    return [[JXPagerListRefreshView alloc] initWithDelegate:self];
+}
+
+#pragma mark - JXPagerViewDelegate
+
+- (UIView *)tableHeaderViewInPagerView:(JXPagerView *)pagerView {
+    return self.infoView;
 }
 
-- (void)openSettingView {
-    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
+- (NSUInteger)tableHeaderViewHeightInPagerView:(JXPagerView *)pagerView {
+    return self.topViewHeight;
+}
+
+- (NSUInteger)heightForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
+    return self.headHeight;
+}
+
+- (UIView *)viewForPinSectionHeaderInPagerView:(JXPagerView *)pagerView {
+    return self.categoryView;
+}
+
+- (NSInteger)numberOfListsInPagerView:(JXPagerView *)pagerView {
+    //和categoryView的item数量一致
+    return self.titles.count;
+}
+
+- (id<JXPagerViewListViewDelegate>)pagerView:(JXPagerView *)pagerView initListAtIndex:(NSInteger)index {
+    ProgramCourseGroupBodyView *listView = [[ProgramCourseGroupBodyView alloc] init];
+    listView.naviController = self.navigationController;
+    listView.selectIndex = index;
+    listView.courseGroupId = self.courseGroupId;
+    listView.isVipCourse = NO;
+    [self.listViewArray replaceObjectAtIndex:index withObject:listView];
+    self.listViewArray[index] = listView;
+    [listView beginFirstRefresh];
+    return listView;
+}
+
+- (void)dealloc {
+   [[NSNotificationCenter defaultCenter] removeObserver:self];
 }
 
 #pragma mark ----- lazying
-- (OnlineClassManager *)classManager {
-    if (!_classManager) {
-        _classManager = [[OnlineClassManager alloc] init];
+
+- (CourseGroupNavView *)navView {
+    if (!_navView) {
+        _navView = [CourseGroupNavView sharedInstance];
+        MJWeakSelf;
+        [_navView configWithNavTitle:@"趣纠课详情" callback:^{
+            [weakSelf backAction];
+        }];
+    }
+    return _navView;
+}
+- (NSMutableArray *)listViewArray {
+    if (!_listViewArray) {
+        _listViewArray = [NSMutableArray arrayWithArray:@[@""]];
     }
-    return _classManager;
+    return _listViewArray;
 }
+- (ProgramCourseInfoView *)infoView {
+    if (!_infoView) {
+        _infoView  =[ProgramCourseInfoView sharedInstance];
+        MJWeakSelf;
+        [_infoView programActionCallback:^{
+            [weakSelf showModifyPlanView];
+        }];
+    }
+    return _infoView;
+}
+
+- (void)showModifyPlanView {
+    CourseGroupPlanAlertView *alert = [CourseGroupPlanAlertView sharedInstance];
+    MJWeakSelf;
+    [alert configWithDesc:self.detailModel.coursePlan callback:^(NSString * _Nullable planString) {
+        [weakSelf submitAction:planString];
+    }];
+    [alert showInView:self.view];
+}
+
+- (void)submitAction:(NSString *)planString {
+    [LOADING_MANAGER showHUD];
+    [KSNetworkingManager updateCoursePlanRequset:KS_POST courseGroupId:self.courseGroupId coursePlan:planString success:^(NSDictionary * _Nonnull dic) {
+        [LOADING_MANAGER removeHUD];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            [self requestCourseInfo];
+        }
+        else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
+        }
+        
+    } faliure:^(NSError * _Nonnull error) {
+        [LOADING_MANAGER removeHUD];
+    }];
+}
+
 /*
 #pragma mark - Navigation
 

+ 33 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Controller/VIPCourseGroupViewController.m

@@ -10,9 +10,12 @@
 #import "KSPremissionAlert.h"
 #import "OnlineClassManager.h"
 #import "HomeworkDetailModel.h"
+#import "CourseGroupNavView.h"
 
 @interface VIPCourseGroupViewController ()
 
+@property (nonatomic, strong) CourseGroupNavView *navView;
+
 @property (nonatomic, strong) NSString *courseId;
 
 @property (nonatomic, strong) NSString *studentId;
@@ -33,9 +36,27 @@
 - (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
+    self.ks_prefersNavigationBarHidden = YES;
+    [self configUI];
 }
 
 
+- (void)configUI {
+    [self.scrollView removeFromSuperview];
+    UIImage *bgImage = [UIImage imageNamed:@"courseDetail_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];
+    
+    [self.view addSubview:self.navView];
+    CGFloat navHeight = [CourseGroupNavView getViewHeight];
+    [self.navView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.mas_equalTo(self.view);
+        make.height.mas_equalTo(navHeight);
+    }];
+}
+
 - (void)tryJoinRoom {
     
     NSDateFormatter *dateFormatter = [NSObject getDateformatter];
@@ -113,6 +134,18 @@
     }
     return _classManager;
 }
+
+- (CourseGroupNavView *)navView {
+    if (!_navView) {
+        _navView = [CourseGroupNavView sharedInstance];
+        MJWeakSelf;
+        [_navView configWithNavTitle:@"VIP定制课详情" callback:^{
+            [weakSelf backAction];
+        }];
+    }
+    return _navView;
+}
+
 /*
 #pragma mark - Navigation
 

+ 30 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseGroupDetailModel.h

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

+ 169 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseGroupDetailModel.m

@@ -0,0 +1,169 @@
+//
+//  CourseGroupDetailModel.m
+//
+//  Created by Steven  on 2024/11/22
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import "CourseGroupDetailModel.h"
+
+
+NSString *const kCourseGroupDetailModelStatus = @"status";
+NSString *const kCourseGroupDetailModelCoursePlan = @"coursePlan";
+NSString *const kCourseGroupDetailModelCourseGroupId = @"courseGroupId";
+NSString *const kCourseGroupDetailModelCourseGroupName = @"courseGroupName";
+NSString *const kCourseGroupDetailModelCompleteCourseNum = @"completeCourseNum";
+NSString *const kCourseGroupDetailModelSubjectId = @"subjectId";
+NSString *const kCourseGroupDetailModelStudentNum = @"studentNum";
+NSString *const kCourseGroupDetailModelSubjectName = @"subjectName";
+NSString *const kCourseGroupDetailModelStudentName = @"studentName";
+NSString *const kCourseGroupDetailModelCourseNum = @"courseNum";
+NSString *const kCourseGroupDetailModelStudentAvatar = @"studentAvatar";
+
+
+@interface CourseGroupDetailModel ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation CourseGroupDetailModel
+
+@synthesize status = _status;
+@synthesize coursePlan = _coursePlan;
+@synthesize courseGroupId = _courseGroupId;
+@synthesize courseGroupName = _courseGroupName;
+@synthesize completeCourseNum = _completeCourseNum;
+@synthesize subjectId = _subjectId;
+@synthesize studentNum = _studentNum;
+@synthesize subjectName = _subjectName;
+@synthesize studentName = _studentName;
+@synthesize courseNum = _courseNum;
+@synthesize studentAvatar = _studentAvatar;
+
+
++ (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:kCourseGroupDetailModelStatus fromDictionary:dict];
+            self.coursePlan = [self objectOrNilForKey:kCourseGroupDetailModelCoursePlan fromDictionary:dict];
+            self.courseGroupId = [self objectOrNilForKey:kCourseGroupDetailModelCourseGroupId fromDictionary:dict];
+            self.courseGroupName = [self objectOrNilForKey:kCourseGroupDetailModelCourseGroupName fromDictionary:dict];
+            self.completeCourseNum = [[self objectOrNilForKey:kCourseGroupDetailModelCompleteCourseNum fromDictionary:dict] doubleValue];
+            self.subjectId = [self objectOrNilForKey:kCourseGroupDetailModelSubjectId fromDictionary:dict];
+            self.studentNum = [[self objectOrNilForKey:kCourseGroupDetailModelStudentNum fromDictionary:dict] doubleValue];
+            self.subjectName = [self objectOrNilForKey:kCourseGroupDetailModelSubjectName fromDictionary:dict];
+            self.studentName = [self objectOrNilForKey:kCourseGroupDetailModelStudentName fromDictionary:dict];
+            self.courseNum = [[self objectOrNilForKey:kCourseGroupDetailModelCourseNum fromDictionary:dict] doubleValue];
+            self.studentAvatar = [self objectOrNilForKey:kCourseGroupDetailModelStudentAvatar fromDictionary:dict];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.status forKey:kCourseGroupDetailModelStatus];
+    [mutableDict setValue:self.coursePlan forKey:kCourseGroupDetailModelCoursePlan];
+    [mutableDict setValue:self.courseGroupId forKey:kCourseGroupDetailModelCourseGroupId];
+    [mutableDict setValue:self.courseGroupName forKey:kCourseGroupDetailModelCourseGroupName];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.completeCourseNum] forKey:kCourseGroupDetailModelCompleteCourseNum];
+    [mutableDict setValue:self.subjectId forKey:kCourseGroupDetailModelSubjectId];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.studentNum] forKey:kCourseGroupDetailModelStudentNum];
+    [mutableDict setValue:self.subjectName forKey:kCourseGroupDetailModelSubjectName];
+    [mutableDict setValue:self.studentName forKey:kCourseGroupDetailModelStudentName];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.courseNum] forKey:kCourseGroupDetailModelCourseNum];
+    [mutableDict setValue:self.studentAvatar forKey:kCourseGroupDetailModelStudentAvatar];
+
+    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:kCourseGroupDetailModelStatus];
+    self.coursePlan = [aDecoder decodeObjectForKey:kCourseGroupDetailModelCoursePlan];
+    self.courseGroupId = [aDecoder decodeObjectForKey:kCourseGroupDetailModelCourseGroupId];
+    self.courseGroupName = [aDecoder decodeObjectForKey:kCourseGroupDetailModelCourseGroupName];
+    self.completeCourseNum = [aDecoder decodeDoubleForKey:kCourseGroupDetailModelCompleteCourseNum];
+    self.subjectId = [aDecoder decodeObjectForKey:kCourseGroupDetailModelSubjectId];
+    self.studentNum = [aDecoder decodeDoubleForKey:kCourseGroupDetailModelStudentNum];
+    self.subjectName = [aDecoder decodeObjectForKey:kCourseGroupDetailModelSubjectName];
+    self.studentName = [aDecoder decodeObjectForKey:kCourseGroupDetailModelStudentName];
+    self.courseNum = [aDecoder decodeDoubleForKey:kCourseGroupDetailModelCourseNum];
+    self.studentAvatar = [aDecoder decodeObjectForKey:kCourseGroupDetailModelStudentAvatar];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_status forKey:kCourseGroupDetailModelStatus];
+    [aCoder encodeObject:_coursePlan forKey:kCourseGroupDetailModelCoursePlan];
+    [aCoder encodeObject:_courseGroupId forKey:kCourseGroupDetailModelCourseGroupId];
+    [aCoder encodeObject:_courseGroupName forKey:kCourseGroupDetailModelCourseGroupName];
+    [aCoder encodeDouble:_completeCourseNum forKey:kCourseGroupDetailModelCompleteCourseNum];
+    [aCoder encodeObject:_subjectId forKey:kCourseGroupDetailModelSubjectId];
+    [aCoder encodeDouble:_studentNum forKey:kCourseGroupDetailModelStudentNum];
+    [aCoder encodeObject:_subjectName forKey:kCourseGroupDetailModelSubjectName];
+    [aCoder encodeObject:_studentName forKey:kCourseGroupDetailModelStudentName];
+    [aCoder encodeDouble:_courseNum forKey:kCourseGroupDetailModelCourseNum];
+    [aCoder encodeObject:_studentAvatar forKey:kCourseGroupDetailModelStudentAvatar];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    CourseGroupDetailModel *copy = [[CourseGroupDetailModel alloc] init];
+    
+    if (copy) {
+
+        copy.status = [self.status copyWithZone:zone];
+        copy.coursePlan = [self.coursePlan copyWithZone:zone];
+        copy.courseGroupId = [self.courseGroupId copyWithZone:zone];
+        copy.courseGroupName = [self.courseGroupName copyWithZone:zone];
+        copy.completeCourseNum = self.completeCourseNum;
+        copy.subjectId = [self.subjectId copyWithZone:zone];
+        copy.studentNum = self.studentNum;
+        copy.subjectName = [self.subjectName copyWithZone:zone];
+        copy.studentName = [self.studentName copyWithZone:zone];
+        copy.courseNum = self.courseNum;
+        copy.studentAvatar = [self.studentAvatar copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 23 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseStudentVos.h

@@ -0,0 +1,23 @@
+//
+//  CourseStudentVos.h
+//
+//  Created by Steven  on 2024/11/22
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+
+@interface CourseStudentVos : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, strong) NSString *avatar;
+@property (nonatomic, strong) NSString *userId;
+@property (nonatomic, strong) NSString *imUserId;
+@property (nonatomic, strong) NSString *userName;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 120 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/CourseStudentVos.m

@@ -0,0 +1,120 @@
+//
+//  CourseStudentVos.m
+//
+//  Created by Steven  on 2024/11/22
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import "CourseStudentVos.h"
+
+
+NSString *const kCourseStudentVosAvatar = @"avatar";
+NSString *const kCourseStudentVosUserId = @"userId";
+NSString *const kCourseStudentVosImUserId = @"imUserId";
+NSString *const kCourseStudentVosUserName = @"userName";
+
+
+@interface CourseStudentVos ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation CourseStudentVos
+
+@synthesize avatar = _avatar;
+@synthesize userId = _userId;
+@synthesize imUserId = _imUserId;
+@synthesize userName = _userName;
+
+
++ (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.avatar = [self objectOrNilForKey:kCourseStudentVosAvatar fromDictionary:dict];
+            self.userId = [self objectOrNilForKey:kCourseStudentVosUserId fromDictionary:dict];
+            self.imUserId = [self objectOrNilForKey:kCourseStudentVosImUserId fromDictionary:dict];
+            self.userName = [self objectOrNilForKey:kCourseStudentVosUserName fromDictionary:dict];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.avatar forKey:kCourseStudentVosAvatar];
+    [mutableDict setValue:self.userId forKey:kCourseStudentVosUserId];
+    [mutableDict setValue:self.imUserId forKey:kCourseStudentVosImUserId];
+    [mutableDict setValue:self.userName forKey:kCourseStudentVosUserName];
+
+    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.avatar = [aDecoder decodeObjectForKey:kCourseStudentVosAvatar];
+    self.userId = [aDecoder decodeObjectForKey:kCourseStudentVosUserId];
+    self.imUserId = [aDecoder decodeObjectForKey:kCourseStudentVosImUserId];
+    self.userName = [aDecoder decodeObjectForKey:kCourseStudentVosUserName];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_avatar forKey:kCourseStudentVosAvatar];
+    [aCoder encodeObject:_userId forKey:kCourseStudentVosUserId];
+    [aCoder encodeObject:_imUserId forKey:kCourseStudentVosImUserId];
+    [aCoder encodeObject:_userName forKey:kCourseStudentVosUserName];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    CourseStudentVos *copy = [[CourseStudentVos alloc] init];
+    
+    if (copy) {
+
+        copy.avatar = [self.avatar copyWithZone:zone];
+        copy.userId = [self.userId copyWithZone:zone];
+        copy.imUserId = [self.imUserId copyWithZone:zone];
+        copy.userName = [self.userName copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 28 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/GroupCourseListModel.h

@@ -0,0 +1,28 @@
+//
+//  GroupCourseListModel.h
+//
+//  Created by Steven  on 2024/11/22
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "CourseStudentVos.h"
+
+
+@interface GroupCourseListModel : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, strong) NSString *status;
+@property (nonatomic, strong) NSString *classDate;
+@property (nonatomic, strong) NSString *endTime;
+@property (nonatomic, strong) NSString *courseId;
+@property (nonatomic, strong) NSArray *courseStudentVos;
+@property (nonatomic, strong) NSString *courseGoupId;
+@property (nonatomic, strong) NSString *startTime;
+@property (nonatomic, strong) NSString *courseGroupName;
+@property (nonatomic, assign) BOOL attendanceStatus;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 177 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/Model/GroupCourseListModel.m

@@ -0,0 +1,177 @@
+//
+//  GroupCourseListModel.m
+//
+//  Created by Steven  on 2024/11/22
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import "GroupCourseListModel.h"
+
+
+NSString *const kGroupCourseListModelStatus = @"status";
+NSString *const kGroupCourseListModelClassDate = @"classDate";
+NSString *const kGroupCourseListModelEndTime = @"endTime";
+NSString *const kGroupCourseListModelCourseId = @"courseId";
+NSString *const kGroupCourseListModelCourseStudentVos = @"courseStudentVos";
+NSString *const kGroupCourseListModelCourseGoupId = @"courseGoupId";
+NSString *const kGroupCourseListModelStartTime = @"startTime";
+NSString *const kGroupCourseListModelCourseGroupName = @"courseGroupName";
+NSString *const kGroupCourseListModelAttendanceStatus = @"attendanceStatus";
+
+
+@interface GroupCourseListModel ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation GroupCourseListModel
+
+@synthesize status = _status;
+@synthesize classDate = _classDate;
+@synthesize endTime = _endTime;
+@synthesize courseId = _courseId;
+@synthesize courseStudentVos = _courseStudentVos;
+@synthesize courseGoupId = _courseGoupId;
+@synthesize startTime = _startTime;
+@synthesize courseGroupName = _courseGroupName;
+@synthesize attendanceStatus = _attendanceStatus;
+
+
++ (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:kGroupCourseListModelStatus fromDictionary:dict];
+            self.classDate = [self objectOrNilForKey:kGroupCourseListModelClassDate fromDictionary:dict];
+            self.endTime = [self objectOrNilForKey:kGroupCourseListModelEndTime fromDictionary:dict];
+            self.courseId = [self objectOrNilForKey:kGroupCourseListModelCourseId fromDictionary:dict];
+    NSObject *receivedCourseStudentVos = [dict objectForKey:kGroupCourseListModelCourseStudentVos];
+    NSMutableArray *parsedCourseStudentVos = [NSMutableArray array];
+    if ([receivedCourseStudentVos isKindOfClass:[NSArray class]]) {
+        for (NSDictionary *item in (NSArray *)receivedCourseStudentVos) {
+            if ([item isKindOfClass:[NSDictionary class]]) {
+                [parsedCourseStudentVos addObject:[CourseStudentVos modelObjectWithDictionary:item]];
+            }
+       }
+    } else if ([receivedCourseStudentVos isKindOfClass:[NSDictionary class]]) {
+       [parsedCourseStudentVos addObject:[CourseStudentVos modelObjectWithDictionary:(NSDictionary *)receivedCourseStudentVos]];
+    }
+
+    self.courseStudentVos = [NSArray arrayWithArray:parsedCourseStudentVos];
+            self.courseGoupId = [self objectOrNilForKey:kGroupCourseListModelCourseGoupId fromDictionary:dict];
+            self.startTime = [self objectOrNilForKey:kGroupCourseListModelStartTime fromDictionary:dict];
+            self.courseGroupName = [self objectOrNilForKey:kGroupCourseListModelCourseGroupName fromDictionary:dict];
+            self.attendanceStatus = [[self objectOrNilForKey:kGroupCourseListModelAttendanceStatus fromDictionary:dict] boolValue];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.status forKey:kGroupCourseListModelStatus];
+    [mutableDict setValue:self.classDate forKey:kGroupCourseListModelClassDate];
+    [mutableDict setValue:self.endTime forKey:kGroupCourseListModelEndTime];
+    [mutableDict setValue:self.courseId forKey:kGroupCourseListModelCourseId];
+    NSMutableArray *tempArrayForCourseStudentVos = [NSMutableArray array];
+    for (NSObject *subArrayObject in self.courseStudentVos) {
+        if([subArrayObject respondsToSelector:@selector(dictionaryRepresentation)]) {
+            // This class is a model object
+            [tempArrayForCourseStudentVos addObject:[subArrayObject performSelector:@selector(dictionaryRepresentation)]];
+        } else {
+            // Generic object
+            [tempArrayForCourseStudentVos addObject:subArrayObject];
+        }
+    }
+    [mutableDict setValue:[NSArray arrayWithArray:tempArrayForCourseStudentVos] forKey:kGroupCourseListModelCourseStudentVos];
+    [mutableDict setValue:self.courseGoupId forKey:kGroupCourseListModelCourseGoupId];
+    [mutableDict setValue:self.startTime forKey:kGroupCourseListModelStartTime];
+    [mutableDict setValue:self.courseGroupName forKey:kGroupCourseListModelCourseGroupName];
+    [mutableDict setValue:[NSNumber numberWithBool:self.attendanceStatus] forKey:kGroupCourseListModelAttendanceStatus];
+
+    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:kGroupCourseListModelStatus];
+    self.classDate = [aDecoder decodeObjectForKey:kGroupCourseListModelClassDate];
+    self.endTime = [aDecoder decodeObjectForKey:kGroupCourseListModelEndTime];
+    self.courseId = [aDecoder decodeObjectForKey:kGroupCourseListModelCourseId];
+    self.courseStudentVos = [aDecoder decodeObjectForKey:kGroupCourseListModelCourseStudentVos];
+    self.courseGoupId = [aDecoder decodeObjectForKey:kGroupCourseListModelCourseGoupId];
+    self.startTime = [aDecoder decodeObjectForKey:kGroupCourseListModelStartTime];
+    self.courseGroupName = [aDecoder decodeObjectForKey:kGroupCourseListModelCourseGroupName];
+    self.attendanceStatus = [aDecoder decodeBoolForKey:kGroupCourseListModelAttendanceStatus];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_status forKey:kGroupCourseListModelStatus];
+    [aCoder encodeObject:_classDate forKey:kGroupCourseListModelClassDate];
+    [aCoder encodeObject:_endTime forKey:kGroupCourseListModelEndTime];
+    [aCoder encodeObject:_courseId forKey:kGroupCourseListModelCourseId];
+    [aCoder encodeObject:_courseStudentVos forKey:kGroupCourseListModelCourseStudentVos];
+    [aCoder encodeObject:_courseGoupId forKey:kGroupCourseListModelCourseGoupId];
+    [aCoder encodeObject:_startTime forKey:kGroupCourseListModelStartTime];
+    [aCoder encodeObject:_courseGroupName forKey:kGroupCourseListModelCourseGroupName];
+    [aCoder encodeBool:_attendanceStatus forKey:kGroupCourseListModelAttendanceStatus];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    GroupCourseListModel *copy = [[GroupCourseListModel alloc] init];
+    
+    if (copy) {
+
+        copy.status = [self.status copyWithZone:zone];
+        copy.classDate = [self.classDate copyWithZone:zone];
+        copy.endTime = [self.endTime copyWithZone:zone];
+        copy.courseId = [self.courseId copyWithZone:zone];
+        copy.courseStudentVos = [self.courseStudentVos copyWithZone:zone];
+        copy.courseGoupId = [self.courseGoupId copyWithZone:zone];
+        copy.startTime = [self.startTime copyWithZone:zone];
+        copy.courseGroupName = [self.courseGroupName copyWithZone:zone];
+        copy.attendanceStatus = self.attendanceStatus;
+    }
+    
+    return copy;
+}
+
+
+@end

+ 20 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseGroupBodyView.h

@@ -0,0 +1,20 @@
+//
+//  ProgramCourseGroupBodyView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "KSJXBodyView.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ProgramCourseGroupBodyView : KSJXBodyView
+
+@property (nonatomic, strong) NSString *courseGroupId;
+
+@property (nonatomic, assign) BOOL isVipCourse;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 288 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseGroupBodyView.m

@@ -0,0 +1,288 @@
+//
+//  ProgramCourseGroupBodyView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "ProgramCourseGroupBodyView.h"
+#import "GroupCourseSortView.h"
+#import "StateView.h"
+#import "Reachability.h"
+#import "ProgramCourseListCell.h"
+#import "AccompanyDetailViewController.h"
+#import "VipCouseDetailViewController.h"
+#import "GroupCourseListModel.h"
+
+@interface ProgramCourseGroupBodyView ()<UITableViewDelegate,UITableViewDataSource>
+
+@property (nonatomic, strong) NSMutableArray *dataArray;
+
+@property (nonatomic, strong) StateView *promptView;
+@property (nonatomic, strong) UIView *promptPlaceView;
+
+@property (nonatomic, assign) BOOL networkAvaiable; // 网络是否可用
+
+@property (nonatomic, strong) GroupCourseSortView *sortView;
+
+@property (nonatomic, strong) NSString *classDate;
+
+@property (nonatomic, strong) NSString *attendanceStatus;
+
+@property (nonatomic, strong) NSString *courseStatus;
+
+@end
+
+@implementation ProgramCourseGroupBodyView
+
+- (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:@"ProgramCourseListCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"ProgramCourseListCell"];
+        
+        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];
+        }];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(forceScroll) name:@"UITextViewScroll" object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enableScroll) name:@"UITextViewEndScroll" object:nil];
+    }
+    return self;
+}
+
+- (void)forceScroll {
+    self.tableView.scrollEnabled = NO;
+}
+
+- (void)enableScroll {
+    self.tableView.scrollEnabled = YES;
+}
+
+- (void)refreshAndRequestData {
+    [self resetParamenter];
+    [self requestData];
+}
+
+- (void)resetParamenter {
+    
+    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];
+    });
+}
+
+- (void)requestData {
+    [KSNetworkingManager courseScheduleListRequest:KS_POST courseGroupId:self.courseGroupId classMonth:self.classDate attendanceStatus:self.attendanceStatus courseStatus:self.courseStatus success:^(NSDictionary * _Nonnull dic) {
+        [self endRefresh];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [dic ks_arrayValueForKey:@"data"];
+            for (NSDictionary *parm in sourceArray) {
+                GroupCourseListModel *model = [[GroupCourseListModel alloc] initWithDictionary:parm];
+                [self.dataArray addObject:model];
+            }
+        }
+        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 sortViewHeight = [GroupCourseSortView getViewHeight];
+
+    if (![self.subviews containsObject:self.sortView]) {
+        [self addSubview:self.sortView];
+        [self.sortView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.mas_equalTo(self);
+            make.height.mas_equalTo(sortViewHeight);
+        }];
+    }
+
+    [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.bottom.mas_equalTo(self);
+        make.top.mas_equalTo(self.sortView.mas_bottom);
+    }];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 123.0f;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    GroupCourseListModel *model = self.dataArray[indexPath.row];
+    ProgramCourseListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ProgramCourseListCell"];
+    MJWeakSelf;
+    [cell configWithSource:model callback:^(GroupCourseListModel * _Nonnull model) {
+        [weakSelf enterClassRoom:model];
+    }];
+    return cell;
+}
+
+- (void)enterClassRoom:(GroupCourseListModel *)model {
+    
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    // 课程详情
+    GroupCourseListModel *courseModel = self.dataArray[indexPath.row];
+    CourseStudentVos *studentModel = [courseModel.courseStudentVos lastObject];
+    if (self.isVipCourse) {
+        VipCouseDetailViewController *detailVC = [[VipCouseDetailViewController alloc] init];
+        detailVC.courseId = courseModel.courseId;
+        detailVC.courseGroupId = courseModel.courseGoupId;
+        detailVC.studentId = studentModel.userId;
+        [self.naviController pushViewController:detailVC animated:YES];
+    }
+    else {
+        AccompanyDetailViewController *detailVC = [[AccompanyDetailViewController alloc] init];
+        detailVC.courseId = courseModel.courseId;
+        detailVC.courseGroupId = courseModel.courseGoupId;
+        detailVC.studentId = studentModel.userId;
+        [self.naviController pushViewController:detailVC animated:YES];
+    }
+}
+
+#pragma mark ---- lazying
+- (GroupCourseSortView *)sortView {
+    if (!_sortView) {
+        _sortView = [GroupCourseSortView sharedInstance];
+        
+    }
+    return _sortView;
+}
+
+/**
+ 设置没有数据时的显示
+ 
+ @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;
+}
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 27 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseInfoView.h

@@ -0,0 +1,27 @@
+//
+//  ProgramCourseInfoView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import <UIKit/UIKit.h>
+#import "CourseGroupDetailModel.h"
+
+typedef void(^ProgramPlanAction)();
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ProgramCourseInfoView : UIView
+
++ (instancetype)sharedInstance;
+
+- (void)configWithSource:(CourseGroupDetailModel *)model;
+
+- (void)programActionCallback:(ProgramPlanAction)callback;
+
++ (CGFloat)getViewHeightWithPlanString:(NSString *)planString;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 158 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseInfoView.m

@@ -0,0 +1,158 @@
+//
+//  ProgramCourseInfoView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "ProgramCourseInfoView.h"
+#import "CourseGroupPlanAddView.h"
+#import "CourseGroupPlanDescView.h"
+
+@interface ProgramCourseInfoView ()
+
+@property (weak, nonatomic) IBOutlet UIView *bgView;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseGroupTitle;
+
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+
+@property (weak, nonatomic) IBOutlet UIImageView *avatar;
+
+@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *subjectLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseDesc;
+
+@property (weak, nonatomic) IBOutlet UIView *planContainer;
+
+@property (nonatomic, strong) CourseGroupPlanAddView *addView;
+
+@property (nonatomic, strong) CourseGroupPlanDescView *planDescView;
+
+@property (nonatomic, copy) ProgramPlanAction callback;
+
+@end
+
+@implementation ProgramCourseInfoView
+
++ (instancetype)sharedInstance {
+    
+    ProgramCourseInfoView *view = [[[NSBundle mainBundle] loadNibNamed:@"ProgramCourseInfoView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithSource:(CourseGroupDetailModel *)model {
+    [self.planContainer removeAllSubViews];
+    if ([NSString isEmptyString:model.coursePlan]) {
+        [self.planContainer addSubview:self.addView];
+        CGFloat addViewHeight = [CourseGroupPlanAddView getViewHeight];
+        [self.addView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.top.bottom.right.left.mas_equalTo(self.planContainer);
+            make.height.mas_equalTo(addViewHeight);
+        }];
+        self.bgView.backgroundColor = [UIColor whiteColor];
+    }
+    else {
+        CGFloat planHeight = [CourseGroupPlanDescView getViewHeight:model.coursePlan];
+        self.bgView.backgroundColor = [UIColor clearColor];
+        [self.planContainer addSubview:self.planDescView];
+        [self.planDescView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.bottom.mas_equalTo(self.planContainer);
+            make.height.mas_equalTo(planHeight);
+        }];
+        [self.planDescView configWithPlanDesc:model.coursePlan];
+    }
+    self.courseGroupTitle.text = [NSString returnNoNullStringWithString:model.courseGroupName];
+    /// 状态
+    [self evaluateGroupStatus:model.status];
+    
+    [self.avatar sd_setImageWithURL:[NSURL URLWithString:[model.studentAvatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:STUDENT_AVATAR]];
+    self.nameLabel.text = [NSString returnNoNullStringWithString:model.studentName];
+    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)programActionCallback:(ProgramPlanAction)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    
+}
+
++ (CGFloat)getViewHeightWithPlanString:(NSString *)planString {
+    if ([NSString isEmptyString:planString]) {
+        return 106.0f + [CourseGroupPlanAddView getViewHeight];
+    }
+    else {
+        return 106.0f + [CourseGroupPlanDescView getViewHeight:planString];
+    }
+}
+
+- (CourseGroupPlanAddView *)addView {
+    if (!_addView) {
+        _addView = [CourseGroupPlanAddView sharedInstance];
+        MJWeakSelf;
+        [_addView addPlanAction:^{
+            [weakSelf showPlanView];
+        }];
+    }
+    return _addView;
+}
+
+- (CourseGroupPlanDescView *)planDescView {
+    if (!_planDescView) {
+        _planDescView = [CourseGroupPlanDescView sharedInstance];
+        MJWeakSelf;
+        [_planDescView modifyPlanAction:^{
+            [weakSelf showPlanView];
+        }];
+    }
+    return _planDescView;
+}
+
+- (void)showPlanView {
+    if (self.callback) {
+        self.callback();
+    }
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 166 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseInfoView.xib

@@ -0,0 +1,166 @@
+<?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="ProgramCourseInfoView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="150"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0qi-vD-Oua">
+                    <rect key="frame" x="14" y="12" width="365" height="138"/>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="10"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TTp-sQ-B0k">
+                    <rect key="frame" x="14" y="12" width="365" 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="Qdk-Iv-HHj">
+                            <rect key="frame" x="12" y="12" width="130.33333333333334" height="22"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="22" id="Kha-MR-xBB"/>
+                            </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="CAz-5b-toA">
+                            <rect key="frame" x="311" 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="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" image="student_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="Rai-VY-YLo">
+                            <rect key="frame" x="12" y="42" width="40" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="40" id="8DA-BV-8bO"/>
+                                <constraint firstAttribute="height" constant="40" id="QOM-dg-D6z"/>
+                            </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="J5P-Tl-Nui">
+                            <rect key="frame" x="62" y="43" width="39" height="17"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="17" id="bRJ-dW-7MW"/>
+                            </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="XT8-k1-pUz">
+                            <rect key="frame" x="63" y="68" width="12" height="14"/>
+                        </imageView>
+                        <view contentMode="scaleToFill" horizontalCompressionResistancePriority="752" translatesAutoresizingMaskIntoConstraints="NO" id="ERt-aV-DBH">
+                            <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="mAJ-jN-D5e">
+                                    <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="C22-aR-RpW"/>
+                                <constraint firstItem="mAJ-jN-D5e" firstAttribute="leading" secondItem="ERt-aV-DBH" secondAttribute="leading" constant="4" id="CC9-1M-6oE"/>
+                                <constraint firstAttribute="trailing" secondItem="mAJ-jN-D5e" secondAttribute="trailing" constant="4" id="KEw-Zn-4A8"/>
+                                <constraint firstItem="mAJ-jN-D5e" firstAttribute="centerY" secondItem="ERt-aV-DBH" secondAttribute="centerY" id="Tpv-Ne-nBQ"/>
+                            </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="Oly-2P-Xkc">
+                            <rect key="frame" x="79" y="67" width="129" height="16"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="16" id="eDB-zy-wct"/>
+                            </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 firstAttribute="trailing" secondItem="CAz-5b-toA" secondAttribute="trailing" constant="12" id="62C-yK-QC9"/>
+                        <constraint firstItem="ERt-aV-DBH" firstAttribute="leading" secondItem="J5P-Tl-Nui" secondAttribute="trailing" constant="5" id="8Er-0C-7BN"/>
+                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Oly-2P-Xkc" secondAttribute="trailing" constant="12" id="BZC-m7-J5U"/>
+                        <constraint firstItem="XT8-k1-pUz" firstAttribute="top" secondItem="J5P-Tl-Nui" secondAttribute="bottom" constant="8" id="CoR-b0-0sW"/>
+                        <constraint firstItem="CAz-5b-toA" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Qdk-Iv-HHj" secondAttribute="trailing" constant="10" id="Gb3-QX-dbH"/>
+                        <constraint firstItem="Qdk-Iv-HHj" firstAttribute="leading" secondItem="TTp-sQ-B0k" secondAttribute="leading" constant="12" id="IIc-Jh-oNg"/>
+                        <constraint firstItem="XT8-k1-pUz" firstAttribute="leading" secondItem="Rai-VY-YLo" secondAttribute="trailing" constant="11" id="IhI-s9-e47"/>
+                        <constraint firstItem="CAz-5b-toA" firstAttribute="top" secondItem="TTp-sQ-B0k" secondAttribute="top" constant="12" id="Ipx-qZ-nB7"/>
+                        <constraint firstItem="Oly-2P-Xkc" firstAttribute="centerY" secondItem="XT8-k1-pUz" secondAttribute="centerY" id="Lq5-mC-qTV"/>
+                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="ERt-aV-DBH" secondAttribute="trailing" constant="12" id="Tmv-2u-dev"/>
+                        <constraint firstItem="Qdk-Iv-HHj" firstAttribute="top" secondItem="TTp-sQ-B0k" secondAttribute="top" constant="12" id="Tsv-yc-kpD"/>
+                        <constraint firstItem="Rai-VY-YLo" firstAttribute="leading" secondItem="TTp-sQ-B0k" secondAttribute="leading" constant="12" id="UXu-Pn-bKK"/>
+                        <constraint firstItem="J5P-Tl-Nui" firstAttribute="top" secondItem="Qdk-Iv-HHj" secondAttribute="bottom" constant="9" id="d9U-0l-oCX"/>
+                        <constraint firstAttribute="height" constant="94" id="fku-rU-8na"/>
+                        <constraint firstItem="Rai-VY-YLo" firstAttribute="top" secondItem="Qdk-Iv-HHj" secondAttribute="bottom" constant="8" id="gFs-Gy-Jsh"/>
+                        <constraint firstItem="Oly-2P-Xkc" firstAttribute="leading" secondItem="XT8-k1-pUz" secondAttribute="trailing" constant="4" id="pxe-EP-4rh"/>
+                        <constraint firstItem="J5P-Tl-Nui" firstAttribute="leading" secondItem="Rai-VY-YLo" secondAttribute="trailing" constant="10" id="sHB-UT-QED"/>
+                        <constraint firstItem="ERt-aV-DBH" firstAttribute="centerY" secondItem="J5P-Tl-Nui" secondAttribute="centerY" id="yTp-TD-ifl"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="10"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gsx-fa-Tcd">
+                    <rect key="frame" x="14" y="106" width="365" height="44"/>
+                    <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"/>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="TTp-sQ-B0k" secondAttribute="trailing" constant="14" id="2fm-xo-bkO"/>
+                <constraint firstItem="0qi-vD-Oua" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="12" id="7Hc-MS-0a3"/>
+                <constraint firstItem="TTp-sQ-B0k" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="12" id="CYh-Mp-xtb"/>
+                <constraint firstItem="0qi-vD-Oua" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="MWq-23-xVB"/>
+                <constraint firstItem="gsx-fa-Tcd" firstAttribute="top" secondItem="TTp-sQ-B0k" secondAttribute="bottom" id="QiW-va-YxJ"/>
+                <constraint firstAttribute="trailing" secondItem="gsx-fa-Tcd" secondAttribute="trailing" constant="14" id="T39-15-PVh"/>
+                <constraint firstAttribute="trailing" secondItem="0qi-vD-Oua" secondAttribute="trailing" constant="14" id="aoo-Jk-WcP"/>
+                <constraint firstItem="TTp-sQ-B0k" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="oFM-mO-VSd"/>
+                <constraint firstItem="gsx-fa-Tcd" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="pYh-cr-W5m"/>
+                <constraint firstAttribute="bottom" secondItem="gsx-fa-Tcd" secondAttribute="bottom" id="rIL-hn-g64"/>
+                <constraint firstAttribute="bottom" secondItem="0qi-vD-Oua" secondAttribute="bottom" id="vg2-s2-xDR"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="avatar" destination="Rai-VY-YLo" id="Tzn-mk-ayG"/>
+                <outlet property="bgView" destination="0qi-vD-Oua" id="KlE-17-Ux1"/>
+                <outlet property="courseDesc" destination="Oly-2P-Xkc" id="B4s-bE-y4K"/>
+                <outlet property="courseGroupTitle" destination="Qdk-Iv-HHj" id="82U-Cc-EQr"/>
+                <outlet property="nameLabel" destination="J5P-Tl-Nui" id="0H1-Zi-zbs"/>
+                <outlet property="planContainer" destination="gsx-fa-Tcd" id="Ife-Bl-L6a"/>
+                <outlet property="statusLabel" destination="CAz-5b-toA" id="LEe-vR-eoP"/>
+                <outlet property="subjectLabel" destination="mAJ-jN-D5e" id="yUP-Mv-1nr"/>
+            </connections>
+            <point key="canvasLocation" x="41.984732824427482" y="-138.73239436619718"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="arrange_course_icon" width="12" height="14"/>
+        <image name="student_avatar" width="150" height="150"/>
+    </resources>
+</document>

+ 21 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseListCell.h

@@ -0,0 +1,21 @@
+//
+//  ProgramCourseListCell.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import <UIKit/UIKit.h>
+#import "GroupCourseListModel.h"
+
+typedef void(^GroupListModelCallback)(GroupCourseListModel * _Nonnull model);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ProgramCourseListCell : UITableViewCell
+
+- (void)configWithSource:(GroupCourseListModel *)model callback:(GroupListModelCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 91 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseListCell.m

@@ -0,0 +1,91 @@
+//
+//  ProgramCourseListCell.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "ProgramCourseListCell.h"
+
+@interface ProgramCourseListCell ()
+
+@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *courseGroupName;
+
+@property (weak, nonatomic) IBOutlet UIImageView *avatar;
+
+@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
+
+@property (weak, nonatomic) IBOutlet UIImageView *arriveStatus;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *arriveStatusWidth;
+
+@property (weak, nonatomic) IBOutlet UILabel *subjectLabel;
+
+@property (nonatomic, strong) GroupCourseListModel *sourceModel;
+
+@property (nonatomic, copy) GroupListModelCallback callback;
+
+@end
+
+@implementation ProgramCourseListCell
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    self.selectionStyle = UITableViewCellSelectionStyleNone;
+}
+
+- (void)configWithSource:(GroupCourseListModel *)model callback:(GroupListModelCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    self.sourceModel = model;
+    NSDateFormatter *formatter = [NSObject getDateformatter];
+    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
+    NSDate *startDate = [formatter dateFromString:model.startTime];
+    NSDate *endDate = [formatter dateFromString:model.endTime];
+    [formatter setDateFormat:@"yyyy-MM-dd HH:mm"];
+    NSString *lessonBegin = [formatter stringFromDate:startDate];
+    [formatter setDateFormat:@"HH:mm"];
+    NSString *lessonEnd = [formatter stringFromDate:endDate];
+    self.timeLabel.text = [NSString stringWithFormat:@"%@~%@",[NSString returnNoNullStringWithString:lessonBegin],[NSString returnNoNullStringWithString:lessonEnd]];
+    self.courseGroupName.text = [NSString returnNoNullStringWithString:model.courseGroupName];
+    CourseStudentVos *studentInfo = [model.courseStudentVos lastObject];
+    [self.avatar sd_setImageWithURL:[NSURL URLWithString:[studentInfo.avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:STUDENT_AVATAR]];
+    self.nameLabel.text = [NSString returnNoNullStringWithString:studentInfo.userName];
+    [self evaluateWithSource:model];
+}
+
+- (void)evaluateWithSource:(GroupCourseListModel *)model {
+    NSString *imageName = model.attendanceStatus ? @"course_attendence" : @"course_noArrive";
+    if ([model.status isEqualToString:@"ING"]) {
+        self.statusLabel.text = @"进行中";
+        self.statusLabel.textColor = THEMECOLOR;
+        self.arriveStatus.hidden = NO;
+        self.arriveStatusWidth.constant = 36.0f;
+    }
+    else if ([model.status isEqualToString:@"NOT_START"]) {
+        self.statusLabel.text = @"未开始";
+        self.statusLabel.textColor = HexRGB(0xFF802C);
+        self.arriveStatus.hidden = YES;
+        self.arriveStatusWidth.constant = 0.0f;
+    }
+    else if ([model.status isEqualToString:@"COMPLETE"]) {
+        self.statusLabel.text = @"已结束";
+        self.statusLabel.textColor = HexRGB(0x999999);
+        self.arriveStatus.hidden = NO;
+        self.arriveStatusWidth.constant = 36.0f;
+    }
+    [self.arriveStatus setImage:[UIImage imageNamed:imageName]];
+}
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+@end

+ 189 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseListCell.xib

@@ -0,0 +1,189 @@
+<?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="129" id="KGk-i7-Jjw" customClass="ProgramCourseListCell">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="123"/>
+            <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="123"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DbI-ca-fVq">
+                        <rect key="frame" x="14" y="0.0" width="292" height="111"/>
+                        <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cms-Uu-AjN">
+                                <rect key="frame" x="10" y="46" width="272" height="1"/>
+                                <color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="1" id="cxi-5O-CuU"/>
+                                </constraints>
+                            </view>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" image="course_time" translatesAutoresizingMaskIntoConstraints="NO" id="zF6-bQ-6kl">
+                                <rect key="frame" x="12" y="15" width="16" height="16"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="16" id="EOd-pk-RGo"/>
+                                    <constraint firstAttribute="height" constant="16" id="um2-KO-HvN"/>
+                                </constraints>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="2024-10-30 15:00~15:45" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IZA-Ec-v3k">
+                                <rect key="frame" x="35" y="14" width="162" height="18"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="efI-vt-L5E"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" 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="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2NK-NE-SfV">
+                                <rect key="frame" x="224" y="12" width="42" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="22" id="Jye-K4-VKj"/>
+                                </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="student_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="fC0-s3-zGf">
+                                <rect key="frame" x="12" y="59" width="40" height="40"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="40" id="44E-TM-UhJ"/>
+                                    <constraint firstAttribute="height" constant="40" id="TFm-z7-8Kk"/>
+                                </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" horizontalCompressionResistancePriority="749" text="VIP定制课-张涵宇" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="n5o-cB-ZAV">
+                                <rect key="frame" x="62" y="58" width="121" height="21"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="21" id="ohl-08-mEU"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                <color key="textColor" red="0.074509803921568626" green="0.078431372549019607" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" image="merge_next" translatesAutoresizingMaskIntoConstraints="NO" id="qS2-Zu-yal">
+                                <rect key="frame" x="268" y="17" width="12" height="12"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="12" id="G2z-Hu-GQl"/>
+                                    <constraint firstAttribute="height" constant="12" id="fMg-wX-e8L"/>
+                                </constraints>
+                            </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="VwE-ev-4NJ">
+                                <rect key="frame" x="62" y="83" width="39" height="17"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="17" id="Vmz-gh-Vrv"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <view contentMode="scaleToFill" horizontalCompressionResistancePriority="752" translatesAutoresizingMaskIntoConstraints="NO" id="IN8-fl-KKM">
+                                <rect key="frame" x="106" y="83" 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="Uk4-i9-HBZ">
+                                        <rect key="frame" x="4" y="2.6666666666666714" 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 firstItem="Uk4-i9-HBZ" firstAttribute="centerY" secondItem="IN8-fl-KKM" secondAttribute="centerY" id="Afl-dU-Iqo"/>
+                                    <constraint firstItem="Uk4-i9-HBZ" firstAttribute="leading" secondItem="IN8-fl-KKM" secondAttribute="leading" constant="4" id="mXI-kd-vdQ"/>
+                                    <constraint firstAttribute="trailing" secondItem="Uk4-i9-HBZ" secondAttribute="trailing" constant="4" id="uLk-w6-yIl"/>
+                                    <constraint firstAttribute="height" constant="17" id="yWL-aA-QpW"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="4"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="nM7-0u-1Vp">
+                                <rect key="frame" x="188" y="59.666666666666657" width="36" height="18"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="JoD-PD-ToL"/>
+                                    <constraint firstAttribute="width" constant="36" id="gMd-pw-6Q3"/>
+                                </constraints>
+                            </imageView>
+                        </subviews>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <constraints>
+                            <constraint firstItem="n5o-cB-ZAV" firstAttribute="leading" secondItem="fC0-s3-zGf" secondAttribute="trailing" constant="10" id="7Hn-gP-Gfh"/>
+                            <constraint firstAttribute="trailing" secondItem="cms-Uu-AjN" secondAttribute="trailing" constant="10" id="9bT-Vd-f8p"/>
+                            <constraint firstAttribute="bottom" secondItem="fC0-s3-zGf" secondAttribute="bottom" constant="12" id="Ah1-VO-xwc"/>
+                            <constraint firstItem="qS2-Zu-yal" firstAttribute="leading" secondItem="2NK-NE-SfV" secondAttribute="trailing" constant="2" id="Cct-nq-47C"/>
+                            <constraint firstItem="2NK-NE-SfV" firstAttribute="centerY" secondItem="IZA-Ec-v3k" secondAttribute="centerY" id="EMl-9N-RG5"/>
+                            <constraint firstAttribute="trailing" secondItem="qS2-Zu-yal" secondAttribute="trailing" constant="12" id="EVJ-Qc-kNM"/>
+                            <constraint firstItem="VwE-ev-4NJ" firstAttribute="leading" secondItem="n5o-cB-ZAV" secondAttribute="leading" id="Ehn-EO-ici"/>
+                            <constraint firstItem="fC0-s3-zGf" firstAttribute="top" secondItem="cms-Uu-AjN" secondAttribute="bottom" constant="12" id="F67-Fp-zCL"/>
+                            <constraint firstItem="2NK-NE-SfV" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="IZA-Ec-v3k" secondAttribute="trailing" constant="10" id="FeT-Zz-TRG"/>
+                            <constraint firstItem="cms-Uu-AjN" firstAttribute="top" secondItem="zF6-bQ-6kl" secondAttribute="bottom" constant="15" id="Guj-pG-kNB"/>
+                            <constraint firstItem="nM7-0u-1Vp" firstAttribute="leading" secondItem="n5o-cB-ZAV" secondAttribute="trailing" constant="5" id="Quj-Mk-SRG"/>
+                            <constraint firstItem="IN8-fl-KKM" firstAttribute="leading" secondItem="VwE-ev-4NJ" secondAttribute="trailing" constant="5" id="S5x-NE-bKj"/>
+                            <constraint firstItem="fC0-s3-zGf" firstAttribute="leading" secondItem="DbI-ca-fVq" secondAttribute="leading" constant="12" id="Uo9-fx-EKh"/>
+                            <constraint firstItem="VwE-ev-4NJ" firstAttribute="top" secondItem="n5o-cB-ZAV" secondAttribute="bottom" constant="4" id="VY7-N5-kOX"/>
+                            <constraint firstItem="IN8-fl-KKM" firstAttribute="centerY" secondItem="VwE-ev-4NJ" secondAttribute="centerY" id="Xfo-bh-3Dl"/>
+                            <constraint firstItem="n5o-cB-ZAV" firstAttribute="top" secondItem="fC0-s3-zGf" secondAttribute="top" constant="-1" id="Zf7-e6-HR1"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="nM7-0u-1Vp" secondAttribute="trailing" constant="12" id="hZM-Q4-zRW"/>
+                            <constraint firstItem="nM7-0u-1Vp" firstAttribute="centerY" secondItem="n5o-cB-ZAV" secondAttribute="centerY" id="iKM-Qu-8QT"/>
+                            <constraint firstItem="zF6-bQ-6kl" firstAttribute="top" secondItem="DbI-ca-fVq" secondAttribute="top" constant="15" id="k8n-KT-orp"/>
+                            <constraint firstItem="IZA-Ec-v3k" firstAttribute="centerY" secondItem="zF6-bQ-6kl" secondAttribute="centerY" id="nL8-bs-J29"/>
+                            <constraint firstItem="zF6-bQ-6kl" firstAttribute="leading" secondItem="DbI-ca-fVq" secondAttribute="leading" constant="12" id="nNW-ef-6OP"/>
+                            <constraint firstItem="cms-Uu-AjN" firstAttribute="leading" secondItem="DbI-ca-fVq" secondAttribute="leading" constant="10" id="pGW-8N-GaP"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="IN8-fl-KKM" secondAttribute="trailing" constant="12" id="pXV-tJ-Mtf"/>
+                            <constraint firstItem="qS2-Zu-yal" firstAttribute="top" secondItem="DbI-ca-fVq" secondAttribute="top" constant="17" id="vPT-HL-Lfs"/>
+                            <constraint firstItem="IZA-Ec-v3k" firstAttribute="leading" secondItem="zF6-bQ-6kl" secondAttribute="trailing" constant="7" id="z5j-XG-UJ1"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="10"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="bottom" secondItem="DbI-ca-fVq" secondAttribute="bottom" constant="12" id="Gum-lh-wy7"/>
+                    <constraint firstAttribute="trailing" secondItem="DbI-ca-fVq" secondAttribute="trailing" constant="14" id="KJf-W8-8pJ"/>
+                    <constraint firstItem="DbI-ca-fVq" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="VBR-sN-KEK"/>
+                    <constraint firstItem="DbI-ca-fVq" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="iVf-sb-Hba"/>
+                </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="arriveStatus" destination="nM7-0u-1Vp" id="dGM-jD-dZB"/>
+                <outlet property="arriveStatusWidth" destination="gMd-pw-6Q3" id="BSA-9V-x7b"/>
+                <outlet property="avatar" destination="fC0-s3-zGf" id="eQU-zt-sOx"/>
+                <outlet property="courseGroupName" destination="n5o-cB-ZAV" id="02s-Db-N24"/>
+                <outlet property="nameLabel" destination="VwE-ev-4NJ" id="MOV-h8-dpI"/>
+                <outlet property="statusLabel" destination="2NK-NE-SfV" id="uu3-nS-teP"/>
+                <outlet property="subjectLabel" destination="Uk4-i9-HBZ" id="xbf-8n-kcl"/>
+                <outlet property="timeLabel" destination="IZA-Ec-v3k" id="oiu-tG-ipj"/>
+            </connections>
+            <point key="canvasLocation" x="39.694656488549619" y="49.647887323943664"/>
+        </tableViewCell>
+    </objects>
+    <resources>
+        <image name="course_time" width="16" height="16"/>
+        <image name="merge_next" width="14" height="14"/>
+        <image name="student_avatar" width="150" height="150"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 24 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupNavView.h

@@ -0,0 +1,24 @@
+//
+//  CourseGroupNavView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef void(^CourseGroupNavCallback)(void);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CourseGroupNavView : UIView
+
++ (instancetype)sharedInstance;
+
+- (void)configWithNavTitle:(NSString *)navTitle callback:(CourseGroupNavCallback)callback;
+
++ (CGFloat)getViewHeight;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 51 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupNavView.m

@@ -0,0 +1,51 @@
+//
+//  CourseGroupNavView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "CourseGroupNavView.h"
+
+@interface CourseGroupNavView ()
+
+@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
+
+@property (nonatomic, copy) CourseGroupNavCallback callback;
+
+@end
+
+@implementation CourseGroupNavView
+
+
++ (instancetype)sharedInstance {
+    CourseGroupNavView *view = [[[NSBundle mainBundle] loadNibNamed:@"CourseGroupNavView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithNavTitle:(NSString *)navTitle callback:(CourseGroupNavCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    self.titleLabel.text = [NSString returnNoNullStringWithString:navTitle];
+}
+
+- (IBAction)backAction:(id)sender {
+    if (self.callback) {
+        self.callback();
+    }
+}
+
++ (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

+ 70 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupNavView.xib

@@ -0,0 +1,70 @@
+<?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="CourseGroupNavView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="100"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IZU-kJ-vdx">
+                    <rect key="frame" x="0.0" y="56" width="393" height="44"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="back_black" translatesAutoresizingMaskIntoConstraints="NO" id="h4o-PW-QRb">
+                            <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="NQi-ZX-f8h">
+                            <rect key="frame" x="0.0" y="0.0" width="44" height="44"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="44" id="f0m-aT-yWJ"/>
+                            </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="BvX-eN-dun"/>
+                            </connections>
+                        </button>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="VIP定制课详情" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fok-Mj-6d9">
+                            <rect key="frame" x="136.66666666666666" y="11" width="119.99999999999997" 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="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="NQi-ZX-f8h" firstAttribute="top" secondItem="IZU-kJ-vdx" secondAttribute="top" id="0OO-Hb-fnE"/>
+                        <constraint firstItem="Fok-Mj-6d9" firstAttribute="centerY" secondItem="IZU-kJ-vdx" secondAttribute="centerY" id="5uQ-9y-fY7"/>
+                        <constraint firstAttribute="bottom" secondItem="NQi-ZX-f8h" secondAttribute="bottom" id="E8x-ll-Cld"/>
+                        <constraint firstItem="Fok-Mj-6d9" firstAttribute="centerX" secondItem="IZU-kJ-vdx" secondAttribute="centerX" id="MUP-yd-kTl"/>
+                        <constraint firstItem="NQi-ZX-f8h" firstAttribute="leading" secondItem="IZU-kJ-vdx" secondAttribute="leading" id="fFI-Ea-Wao"/>
+                        <constraint firstAttribute="height" constant="44" id="fkZ-cn-gsY"/>
+                        <constraint firstItem="h4o-PW-QRb" firstAttribute="leading" secondItem="IZU-kJ-vdx" secondAttribute="leading" constant="15" id="ihx-d9-9d5"/>
+                        <constraint firstItem="h4o-PW-QRb" firstAttribute="centerY" secondItem="IZU-kJ-vdx" secondAttribute="centerY" id="p5Y-Ng-77Q"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstAttribute="bottom" secondItem="IZU-kJ-vdx" secondAttribute="bottom" id="ZaP-e3-Ifq"/>
+                <constraint firstAttribute="trailing" secondItem="IZU-kJ-vdx" secondAttribute="trailing" id="bOV-Sr-khy"/>
+                <constraint firstItem="IZU-kJ-vdx" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="maz-sq-QWG"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="titleLabel" destination="Fok-Mj-6d9" id="Lvl-y1-QrB"/>
+            </connections>
+            <point key="canvasLocation" x="34.351145038167935" y="-42.253521126760567"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="back_black" width="12" height="20"/>
+    </resources>
+</document>

+ 24 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAddView.h

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

+ 54 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAddView.m

@@ -0,0 +1,54 @@
+//
+//  CourseGroupPlanAddView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "CourseGroupPlanAddView.h"
+
+@interface CourseGroupPlanAddView ()
+
+@property (weak, nonatomic) IBOutlet UIView *colorBg;
+
+@property (nonatomic, copy) AddGroupPlanCallback callback;
+
+@end
+
+@implementation CourseGroupPlanAddView
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    CAGradientLayer *colorLayer = [UIView createGradientLayerFromColor:HexRGBAlpha(0x2DC7AA, 0.1f) startPoint:CGPointMake(0.54, 0) endColor:HexRGBAlpha(0x2DC7AA, 0.0f) endPoint:CGPointMake(0.54, 1) bounds:CGRectMake(0, 0, KPortraitWidth - 26, 36)];
+    [self.colorBg.layer addSublayer:colorLayer];
+}
+
++ (instancetype)sharedInstance {
+    CourseGroupPlanAddView *view = [[[NSBundle mainBundle] loadNibNamed:@"CourseGroupPlanAddView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)addPlanAction:(AddGroupPlanCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+}
+
+- (IBAction)buttonAction:(id)sender {
+    if (self.callback) {
+        self.callback();
+    }
+}
+
++ (CGFloat)getViewHeight {
+    return 60.0f;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 89 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAddView.xib

@@ -0,0 +1,89 @@
+<?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"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CourseGroupPlanAddView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="60"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8Aa-kp-bYI">
+                    <rect key="frame" x="12" y="12" width="369" height="36"/>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                            <color key="value" red="0.1764705882" green="0.78039215689999997" blue="0.66666666669999997" alpha="0.40000000000000002" colorSpace="custom" customColorSpace="sRGB"/>
+                        </userDefinedRuntimeAttribute>
+                        <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                            <real key="value" value="1"/>
+                        </userDefinedRuntimeAttribute>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="6"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hTw-6B-RQf">
+                    <rect key="frame" x="12" y="12" width="369" height="36"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="group_addPlan" translatesAutoresizingMaskIntoConstraints="NO" id="zZL-6i-GRC">
+                            <rect key="frame" x="127.66666666666666" y="8" width="22" height="20"/>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="添加课程规划" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wvq-0R-j6d">
+                            <rect key="frame" x="151.66666666666666" y="9" width="90" height="18"/>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="c7A-Hr-wRT">
+                            <rect key="frame" x="0.0" y="0.0" width="369" height="36"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="buttonAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="4JR-qG-yqX"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="c7A-Hr-wRT" firstAttribute="leading" secondItem="hTw-6B-RQf" secondAttribute="leading" id="G5B-Oy-WRC"/>
+                        <constraint firstItem="Wvq-0R-j6d" firstAttribute="centerY" secondItem="hTw-6B-RQf" secondAttribute="centerY" id="HQT-Yg-whk"/>
+                        <constraint firstItem="c7A-Hr-wRT" firstAttribute="top" secondItem="hTw-6B-RQf" secondAttribute="top" id="WAm-6h-1Bx"/>
+                        <constraint firstAttribute="bottom" secondItem="c7A-Hr-wRT" secondAttribute="bottom" id="lGw-Zm-vyN"/>
+                        <constraint firstItem="Wvq-0R-j6d" firstAttribute="centerX" secondItem="hTw-6B-RQf" secondAttribute="centerX" constant="12" id="lPb-wr-J1K"/>
+                        <constraint firstItem="Wvq-0R-j6d" firstAttribute="leading" secondItem="zZL-6i-GRC" secondAttribute="trailing" constant="2" id="wOB-7P-0VW"/>
+                        <constraint firstAttribute="trailing" secondItem="c7A-Hr-wRT" secondAttribute="trailing" id="xdD-8m-RPB"/>
+                        <constraint firstItem="Wvq-0R-j6d" firstAttribute="centerY" secondItem="zZL-6i-GRC" secondAttribute="centerY" id="zVc-rj-3ZG"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="8Aa-kp-bYI" firstAttribute="bottom" secondItem="hTw-6B-RQf" secondAttribute="bottom" id="35i-G3-qUh"/>
+                <constraint firstItem="hTw-6B-RQf" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="12" id="4hF-Ht-R4Y"/>
+                <constraint firstItem="8Aa-kp-bYI" firstAttribute="trailing" secondItem="hTw-6B-RQf" secondAttribute="trailing" id="Nph-aE-9YU"/>
+                <constraint firstItem="hTw-6B-RQf" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="12" id="cC9-8l-Qeq"/>
+                <constraint firstItem="8Aa-kp-bYI" firstAttribute="leading" secondItem="hTw-6B-RQf" secondAttribute="leading" id="hGh-n2-ygv"/>
+                <constraint firstAttribute="bottom" secondItem="hTw-6B-RQf" secondAttribute="bottom" constant="12" id="j6u-AX-i9J"/>
+                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="hTw-6B-RQf" secondAttribute="trailing" constant="12" id="pUv-Te-Kkt"/>
+                <constraint firstItem="8Aa-kp-bYI" firstAttribute="top" secondItem="hTw-6B-RQf" secondAttribute="top" id="zCo-UK-6DO"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="colorBg" destination="8Aa-kp-bYI" id="pCY-Y0-BxF"/>
+            </connections>
+            <point key="canvasLocation" x="41.984732824427482" y="-57.74647887323944"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="group_addPlan" width="22" height="20"/>
+    </resources>
+</document>

+ 24 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAlertView.h

@@ -0,0 +1,24 @@
+//
+//  CourseGroupPlanAlertView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef void(^PlanModifyCallback)(NSString * _Nullable planString);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CourseGroupPlanAlertView : UIView
+
++ (instancetype)sharedInstance;
+
+- (void)configWithDesc:(NSString *)planString callback:(PlanModifyCallback)callback;
+
+- (void)showInView:(UIView *)displayView;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 166 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAlertView.m

@@ -0,0 +1,166 @@
+//
+//  CourseGroupPlanAlertView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "CourseGroupPlanAlertView.h"
+
+@interface CourseGroupPlanAlertView ()<UITextViewDelegate>
+
+@property (weak, nonatomic) IBOutlet UIView *bgView;
+
+@property (weak, nonatomic) IBOutlet UITextView *textView;
+
+@property (weak, nonatomic) IBOutlet UILabel *tipsLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *countLabel;
+
+@property (nonatomic, copy) PlanModifyCallback callback;
+
+@end
+
+@implementation CourseGroupPlanAlertView
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    self.textView.delegate = self;
+    self.textView.textContainer.lineFragmentPadding = 0;
+    self.textView.textContainerInset = UIEdgeInsetsZero;
+    self.bgView.layer.cornerRadius = 12.0f;
+    self.bgView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
+}
+
++ (instancetype)sharedInstance {
+    CourseGroupPlanAlertView *view = [[[NSBundle mainBundle] loadNibNamed:@"CourseGroupPlanAlertView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithDesc:(NSString *)planString callback:(PlanModifyCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    self.countLabel.text = [NSString stringWithFormat:@"%zd/200",planString.length];
+    self.tipsLabel.hidden = [NSString isEmptyString:planString] ? NO : YES;
+    
+    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
+    paragraphStyle.lineSpacing = 4.0f;
+    UIFont *font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
+    
+    NSDictionary *attributes = @{NSFontAttributeName:font,NSParagraphStyleAttributeName:paragraphStyle,NSForegroundColorAttributeName:HexRGBAlpha(0x000000, 0.9)};
+    
+        self.textView.attributedText = [[NSAttributedString alloc] initWithString:planString attributes:attributes];
+}
+
+- (void)showInView:(UIView *)displayView {
+    if (!displayView) {
+        displayView = [NSObject getKeyWindow];
+    }
+    if (![displayView.subviews containsObject:self]) {
+        [displayView addSubview:self];
+        [self mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.left.right.top.bottom.mas_equalTo(displayView);
+        }];
+    }
+}
+
+- (IBAction)cancelAction:(id)sender {
+    [self endEditing:YES];
+    [self removeFromSuperview];
+}
+
+- (IBAction)sureAction:(id)sender {
+    [self endEditing:YES];
+    [self removeFromSuperview];
+    if (self.callback) {
+        self.callback(self.textView.text);
+    }
+}
+
+#pragma mark   ---- delegate
+
+- (void)textViewDidBeginEditing:(UITextView *)textView {
+    
+    self.tipsLabel.hidden = YES;
+}
+
+
+- (void)textViewDidEndEditing:(UITextView *)textView {
+    if ([NSString isEmptyString:textView.text]) {
+        self.tipsLabel.hidden = NO;
+    }
+}
+
+- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
+    UITextRange *markedTextRange = textView.markedTextRange;
+    if (markedTextRange) {
+        // 当前处于拼音输入状态,暂不更新 attributedText
+        return YES;
+    }
+    NSInteger limitCount = 200;
+
+    NSString *newText = [[textView text] stringByReplacingCharactersInRange:range withString:text];
+    if (newText.length > limitCount) {
+        newText = [newText substringWithRange:NSMakeRange(0, limitCount)];
+        textView.text = newText;
+    }
+    return YES;
+}
+
+- (void)updateTextViewLineHeight:(UITextView *)textView {
+    UITextRange *markedTextRange = textView.markedTextRange;
+    if (markedTextRange) {
+        // 当前处于拼音输入状态,暂不更新 attributedText
+        return;
+    }
+    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+    paragraphStyle.lineSpacing = 4.0f;
+    UIFont *font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
+    [UIView setAnimationsEnabled:NO];
+    NSRange selectedRange = textView.selectedRange;
+    NSMutableAttributedString *attrs = [[NSMutableAttributedString alloc] initWithString:textView.text attributes:@{NSParagraphStyleAttributeName:paragraphStyle,NSFontAttributeName:font, NSForegroundColorAttributeName:HexRGBAlpha(0x000000, 0.9)}];
+    textView.attributedText = attrs;
+    textView.selectedRange = selectedRange;
+    [UIView setAnimationsEnabled:YES];
+}
+
+- (void)textViewDidChange:(UITextView *)textView {
+    // 获取当前高亮的部分(如果正在拼音输入状态)
+    UITextRange *selectedRange = [textView markedTextRange];
+    UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0];
+    
+    // 如果没有高亮选择的文本,说明不是拼音输入状态
+    if (!position) {
+        // 获取当前textView的内容
+        NSInteger limitCount = 200;
+        NSString *currentText = textView.text;
+        
+        // 如果文本超出最大长度,进行截取
+        if (currentText.length > limitCount) {
+            NSString *limitedText = [currentText substringToIndex:limitCount];
+            textView.text = limitedText;
+        }
+        
+        self.countLabel.text = [NSString stringWithFormat:@"%zd/200",textView.text.length];
+    }
+    [self updateTextViewLineHeight:textView];
+}
+
+- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
+    [self endEditing:YES];
+    return YES;
+}
+
+- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
+    [self endEditing:YES];
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 157 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanAlertView.xib

@@ -0,0 +1,157 @@
+<?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="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"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CourseGroupPlanAlertView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DQA-Yl-R8S">
+                    <rect key="frame" x="0.0" y="526" width="393" height="326"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="添加课程规划" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1QL-rw-ewk">
+                            <rect key="frame" x="142.66666666666666" y="18" width="108" height="22"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="22" id="hX4-6a-Zj4"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
+                            <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="cancle_button" translatesAutoresizingMaskIntoConstraints="NO" id="Y1F-10-7UQ">
+                            <rect key="frame" x="365" y="22" width="16" height="16"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="16" id="EG8-Ky-7Sd"/>
+                                <constraint firstAttribute="height" constant="16" id="FkL-Xu-D9p"/>
+                            </constraints>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zSN-d7-MKE">
+                            <rect key="frame" x="349" y="5" width="44" height="44"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="44" id="9Jv-Jv-EAx"/>
+                                <constraint firstAttribute="width" constant="44" id="hMm-g7-FOv"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="cancelAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="fap-2U-u0a"/>
+                            </connections>
+                        </button>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KlC-4W-rhW">
+                            <rect key="frame" x="14" y="58" width="365" height="164"/>
+                            <subviews>
+                                <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="ozS-Ji-bWH">
+                                    <rect key="frame" x="12" y="13" width="341" height="117"/>
+                                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                                    <color key="textColor" systemColor="labelColor"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <textInputTraits key="textInputTraits" autocapitalizationType="sentences" smartInsertDeleteType="no"/>
+                                </textView>
+                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0/500" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="G0D-65-phx">
+                                    <rect key="frame" x="314" y="130" width="39" height="22"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="22" id="yPF-OZ-aOh"/>
+                                    </constraints>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.29999999999999999" 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="dyn-hF-Vp7">
+                                    <rect key="frame" x="12" y="12" width="134" height="22"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="22" id="SoL-Bj-P4o"/>
+                                    </constraints>
+                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                    <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.29999999999999999" colorSpace="custom" customColorSpace="sRGB"/>
+                                    <nil key="highlightedColor"/>
+                                </label>
+                            </subviews>
+                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstAttribute="trailing" secondItem="G0D-65-phx" secondAttribute="trailing" constant="12" id="71Q-c4-eXa"/>
+                                <constraint firstAttribute="bottom" secondItem="G0D-65-phx" secondAttribute="bottom" constant="12" id="8Wg-1x-pHO"/>
+                                <constraint firstAttribute="trailing" secondItem="ozS-Ji-bWH" secondAttribute="trailing" constant="12" id="8e6-SR-s73"/>
+                                <constraint firstItem="G0D-65-phx" firstAttribute="top" secondItem="ozS-Ji-bWH" secondAttribute="bottom" id="Iso-mr-f0P"/>
+                                <constraint firstItem="ozS-Ji-bWH" firstAttribute="leading" secondItem="KlC-4W-rhW" secondAttribute="leading" constant="12" id="LZC-VX-mmd"/>
+                                <constraint firstItem="dyn-hF-Vp7" firstAttribute="top" secondItem="KlC-4W-rhW" secondAttribute="top" constant="12" id="MpQ-9w-EIp"/>
+                                <constraint firstAttribute="height" constant="164" id="cGh-hR-PH0"/>
+                                <constraint firstItem="dyn-hF-Vp7" firstAttribute="leading" secondItem="KlC-4W-rhW" secondAttribute="leading" constant="12" id="ds5-kN-W89"/>
+                                <constraint firstItem="ozS-Ji-bWH" firstAttribute="top" secondItem="KlC-4W-rhW" secondAttribute="top" constant="13" id="ndy-E0-arG"/>
+                            </constraints>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="10"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                        </view>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bSw-AS-d2f">
+                            <rect key="frame" x="28" y="252" width="337" height="44"/>
+                            <color key="backgroundColor" red="0.1764705882352941" green="0.7803921568627451" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="44" id="nZe-p3-TfW"/>
+                            </constraints>
+                            <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="9Fs-C3-Wg6"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <color key="backgroundColor" red="0.97254901960784312" green="0.97647058823529409" blue="0.9882352941176471" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="326" id="624-Qs-q1U"/>
+                        <constraint firstAttribute="trailing" secondItem="zSN-d7-MKE" secondAttribute="trailing" id="Epz-qx-RsF"/>
+                        <constraint firstAttribute="trailing" secondItem="bSw-AS-d2f" secondAttribute="trailing" constant="28" id="MVV-Rp-CSe"/>
+                        <constraint firstItem="KlC-4W-rhW" firstAttribute="leading" secondItem="DQA-Yl-R8S" secondAttribute="leading" constant="14" id="Q3H-6K-oko"/>
+                        <constraint firstAttribute="trailing" secondItem="KlC-4W-rhW" secondAttribute="trailing" constant="14" id="WRg-YL-ErL"/>
+                        <constraint firstItem="KlC-4W-rhW" firstAttribute="top" secondItem="1QL-rw-ewk" secondAttribute="bottom" constant="18" id="Z2e-fu-vi5"/>
+                        <constraint firstItem="Y1F-10-7UQ" firstAttribute="top" secondItem="DQA-Yl-R8S" secondAttribute="top" constant="22" id="aG1-xd-gZH"/>
+                        <constraint firstAttribute="trailing" secondItem="Y1F-10-7UQ" secondAttribute="trailing" constant="12" id="kqU-8h-Js2"/>
+                        <constraint firstItem="1QL-rw-ewk" firstAttribute="centerX" secondItem="DQA-Yl-R8S" secondAttribute="centerX" id="luJ-zE-jqI"/>
+                        <constraint firstItem="bSw-AS-d2f" firstAttribute="leading" secondItem="DQA-Yl-R8S" secondAttribute="leading" constant="28" id="nZY-Dj-LfI"/>
+                        <constraint firstItem="zSN-d7-MKE" firstAttribute="top" secondItem="DQA-Yl-R8S" secondAttribute="top" constant="5" id="qAE-lY-A6C"/>
+                        <constraint firstItem="1QL-rw-ewk" firstAttribute="top" secondItem="DQA-Yl-R8S" secondAttribute="top" constant="18" id="qR3-ln-1dr"/>
+                        <constraint firstItem="bSw-AS-d2f" firstAttribute="top" secondItem="KlC-4W-rhW" secondAttribute="bottom" constant="30" id="vcv-8u-U0A"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
+            <constraints>
+                <constraint firstAttribute="trailing" secondItem="DQA-Yl-R8S" secondAttribute="trailing" id="AKz-ei-ODR"/>
+                <constraint firstItem="DQA-Yl-R8S" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="atY-XB-bLV"/>
+                <constraint firstAttribute="bottom" secondItem="DQA-Yl-R8S" secondAttribute="bottom" id="ynd-t1-AZ3"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="bgView" destination="DQA-Yl-R8S" id="f1A-iE-nz9"/>
+                <outlet property="countLabel" destination="G0D-65-phx" id="yDz-EG-MmP"/>
+                <outlet property="textView" destination="ozS-Ji-bWH" id="r4e-Xa-fMb"/>
+                <outlet property="tipsLabel" destination="dyn-hF-Vp7" id="lRV-me-VWS"/>
+            </connections>
+            <point key="canvasLocation" x="9.9236641221374047" y="19.718309859154932"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="cancle_button" width="20" height="20"/>
+        <systemColor name="labelColor">
+            <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 26 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanDescView.h

@@ -0,0 +1,26 @@
+//
+//  CourseGroupPlanDescView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef void(^ModifyGroupPlanCallback)(void);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CourseGroupPlanDescView : UIView
+
++ (instancetype)sharedInstance;
+
+- (void)configWithPlanDesc:(NSString *)planDesc;
+
+- (void)modifyPlanAction:(ModifyGroupPlanCallback)callback;
+
++ (CGFloat)getViewHeight:(NSString *)planString;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 100 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanDescView.m

@@ -0,0 +1,100 @@
+//
+//  CourseGroupPlanDescView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "CourseGroupPlanDescView.h"
+
+@interface CourseGroupPlanDescView ()<UITextViewDelegate>
+
+@property (weak, nonatomic) IBOutlet UITextView *textView;
+
+@property (nonatomic, copy) ModifyGroupPlanCallback callback;
+
+@end
+
+@implementation CourseGroupPlanDescView
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    self.textView.delegate = self;
+    self.textView.textContainer.lineFragmentPadding = 0;
+    self.textView.textContainerInset = UIEdgeInsetsZero;
+}
++ (instancetype)sharedInstance {
+    CourseGroupPlanDescView *view = [[[NSBundle mainBundle] loadNibNamed:@"CourseGroupPlanDescView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithPlanDesc:(NSString *)planDesc {
+    
+    NSMutableParagraphStyle *paragraphStyle = [CourseGroupPlanDescView getParagraphStyleWithFont:[UIFont systemFontOfSize:13.0f] lineHeight:22.0f];
+    CGFloat baselineOffset = [CourseGroupPlanDescView getBaseOffline:[UIFont systemFontOfSize:13.0f] lineHeight:22.0f];
+    NSMutableAttributedString *attrs = [[NSMutableAttributedString alloc] initWithString:planDesc attributes:@{NSParagraphStyleAttributeName:paragraphStyle, NSBaselineOffsetAttributeName:@(baselineOffset),NSFontAttributeName:[UIFont systemFontOfSize:13.0f], NSForegroundColorAttributeName:HexRGB(0x777777)}];
+    self.textView.attributedText = attrs;
+}
+
+- (void)modifyPlanAction:(ModifyGroupPlanCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+}
+
+- (IBAction)buttonAction:(id)sender {
+    if (self.callback) {
+        self.callback();
+    }
+}
+
+
++ (CGFloat)getBaseOffline:(UIFont *)font lineHeight:(CGFloat)lineHeight {
+    CGFloat baselineOffset = (lineHeight - font.lineHeight) / 4;
+    return baselineOffset;
+}
+
++ (NSMutableParagraphStyle *)getParagraphStyleWithFont:(UIFont *)font lineHeight:(CGFloat)lineHeigh {
+    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+    paragraphStyle.maximumLineHeight = lineHeigh;
+    paragraphStyle.minimumLineHeight = lineHeigh;
+    return paragraphStyle;
+}
+
+
++ (CGFloat)getViewHeight:(NSString *)planString {
+    NSMutableParagraphStyle *paragraphStyle = [self getParagraphStyleWithFont:[UIFont systemFontOfSize:13.0f] lineHeight:22.0f];
+    CGFloat baselineOffset = [self getBaseOffline:[UIFont systemFontOfSize:13.0f] lineHeight:22.0f];
+    CGFloat height = [planString boundingRectWithSize:CGSizeMake(KPortraitWidth - 26, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSParagraphStyleAttributeName:paragraphStyle, NSBaselineOffsetAttributeName:@(baselineOffset),NSFontAttributeName:[UIFont systemFontOfSize:13.0f]} context:nil].size.height + 1 + 42 + 10 + 12;
+    if (height < 96) {
+        height = 96.0f;
+    }
+    if (height > 152) {
+        height = 152.0f;
+    }
+    return height;
+}
+
+// 在 UITextView 滚动开始时禁用 UITableView 滚动
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"UITextViewScroll" object:nil];
+}
+
+// 在 UITextView 停止滚动后恢复 UITableView 滚动
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"UITextViewEndScroll" object:nil];
+}
+
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"UITextViewEndScroll" object:nil];
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 111 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/CourseGroupPlanDescView.xib

@@ -0,0 +1,111 @@
+<?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="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"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CourseGroupPlanDescView">
+            <rect key="frame" x="0.0" y="0.0" width="393" height="145"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7vY-rm-il4">
+                    <rect key="frame" x="0.0" y="12" width="393" height="133"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="course_plan_icon" translatesAutoresizingMaskIntoConstraints="NO" id="0CG-ac-gwS">
+                            <rect key="frame" x="12" y="12" width="18" height="18"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="18" id="TiP-dm-FSr"/>
+                                <constraint firstAttribute="width" constant="18" id="zCt-qc-sAF"/>
+                            </constraints>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="课程规划" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ext-kp-pD1">
+                            <rect key="frame" x="36" y="12" width="60" height="18"/>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
+                            <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="plan_edit" translatesAutoresizingMaskIntoConstraints="NO" id="I6t-ba-QZt">
+                            <rect key="frame" x="339" y="14" width="14" height="14"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="14" id="Ssd-tX-Qpj"/>
+                                <constraint firstAttribute="height" constant="14" id="bQq-ov-G2J"/>
+                            </constraints>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="修改" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="17Y-QM-ifr">
+                            <rect key="frame" x="355" y="13" width="26" height="16"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                            <color key="textColor" red="0.46666666666666667" green="0.46666666666666667" blue="0.46666666666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gyP-HZ-5E0">
+                            <rect key="frame" x="333" y="5" width="60" height="34"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="60" id="kQn-sa-5Qa"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="buttonAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="7O5-OQ-PEc"/>
+                            </connections>
+                        </button>
+                        <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="djD-FS-SLG">
+                            <rect key="frame" x="12" y="42" width="369" height="81"/>
+                            <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                            <color key="textColor" red="0.46666666666666667" green="0.46666666666666667" blue="0.46666666666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                            <textInputTraits key="textInputTraits" autocapitalizationType="sentences" smartInsertDeleteType="no"/>
+                        </textView>
+                    </subviews>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <constraints>
+                        <constraint firstItem="17Y-QM-ifr" firstAttribute="leading" secondItem="I6t-ba-QZt" secondAttribute="trailing" constant="2" id="6tq-hO-O19"/>
+                        <constraint firstAttribute="trailing" secondItem="gyP-HZ-5E0" secondAttribute="trailing" id="8h7-nk-xKs"/>
+                        <constraint firstAttribute="trailing" secondItem="17Y-QM-ifr" secondAttribute="trailing" constant="12" id="HQk-s5-KMm"/>
+                        <constraint firstItem="djD-FS-SLG" firstAttribute="top" secondItem="0CG-ac-gwS" secondAttribute="bottom" constant="12" id="O2v-6x-zf5"/>
+                        <constraint firstItem="0CG-ac-gwS" firstAttribute="leading" secondItem="7vY-rm-il4" secondAttribute="leading" constant="12" id="Zco-rw-GXs"/>
+                        <constraint firstItem="djD-FS-SLG" firstAttribute="leading" secondItem="7vY-rm-il4" secondAttribute="leading" constant="12" id="aeJ-Cj-3JN"/>
+                        <constraint firstItem="gyP-HZ-5E0" firstAttribute="top" secondItem="7vY-rm-il4" secondAttribute="top" constant="5" id="cqp-5F-Lnx"/>
+                        <constraint firstItem="0CG-ac-gwS" firstAttribute="top" secondItem="7vY-rm-il4" secondAttribute="top" constant="12" id="fFp-ya-en1"/>
+                        <constraint firstAttribute="trailing" secondItem="djD-FS-SLG" secondAttribute="trailing" constant="12" id="hNV-TX-AfM"/>
+                        <constraint firstItem="Ext-kp-pD1" firstAttribute="leading" secondItem="0CG-ac-gwS" secondAttribute="trailing" constant="6" id="jhx-Yc-Zkl"/>
+                        <constraint firstItem="Ext-kp-pD1" firstAttribute="centerY" secondItem="0CG-ac-gwS" secondAttribute="centerY" id="msL-eA-jvm"/>
+                        <constraint firstItem="17Y-QM-ifr" firstAttribute="centerY" secondItem="Ext-kp-pD1" secondAttribute="centerY" id="mvg-ov-0fM"/>
+                        <constraint firstItem="I6t-ba-QZt" firstAttribute="centerY" secondItem="Ext-kp-pD1" secondAttribute="centerY" id="nM8-HE-qkG"/>
+                        <constraint firstAttribute="bottom" secondItem="djD-FS-SLG" secondAttribute="bottom" constant="10" id="yPj-fN-IJf"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="10"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="7vY-rm-il4" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="9Y6-W1-3Sp"/>
+                <constraint firstAttribute="bottom" secondItem="7vY-rm-il4" secondAttribute="bottom" id="mAf-kq-7c6"/>
+                <constraint firstAttribute="trailing" secondItem="7vY-rm-il4" secondAttribute="trailing" id="nxI-wi-jUn"/>
+                <constraint firstItem="7vY-rm-il4" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="12" id="per-Lb-guY"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="textView" destination="djD-FS-SLG" id="3te-uV-dmn"/>
+            </connections>
+            <point key="canvasLocation" x="75.572519083969468" y="45.422535211267608"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="course_plan_icon" width="18" height="18"/>
+        <image name="plan_edit" width="14" height="14"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 20 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/GroupCourseSortView.h

@@ -0,0 +1,20 @@
+//
+//  GroupCourseSortView.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface GroupCourseSortView : UIView
+
++ (instancetype)sharedInstance;
+
++ (CGFloat)getViewHeight;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 35 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/GroupCourseSortView.m

@@ -0,0 +1,35 @@
+//
+//  GroupCourseSortView.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/22.
+//
+
+#import "GroupCourseSortView.h"
+
+@interface GroupCourseSortView ()
+
+
+
+@end
+
+@implementation GroupCourseSortView
+
+
++ (instancetype)sharedInstance {
+    GroupCourseSortView *view = [[[NSBundle mainBundle] loadNibNamed:@"GroupCourseSortView" owner:nil options:nil] firstObject];
+    return view;
+}
+
++ (CGFloat)getViewHeight {
+    return 50.0f;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 175 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/View/CourseGroupView/GroupCourseSortView.xib

@@ -0,0 +1,175 @@
+<?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="GroupCourseSortView">
+            <rect key="frame" x="0.0" y="0.0" width="385" height="55"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nUQ-28-ciH">
+                    <rect key="frame" x="0.0" y="0.0" width="385" height="55"/>
+                    <subviews>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3ud-K6-gBw">
+                            <rect key="frame" x="0.0" y="0.0" width="121.66666666666667" height="55"/>
+                            <subviews>
+                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="XXXX年XX月" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cfT-LB-SNv">
+                                    <rect key="frame" x="12" y="19" width="90" height="17"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <color key="textColor" red="0.074509803921568626" green="0.078431372549019607" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                    <nil key="highlightedColor"/>
+                                </label>
+                                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sort_down_grey" translatesAutoresizingMaskIntoConstraints="NO" id="aFu-Ok-mVy">
+                                    <rect key="frame" x="107" y="25" width="9" height="5"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="5" id="f2v-0M-H3l"/>
+                                        <constraint firstAttribute="width" constant="9" id="zTE-EP-L2e"/>
+                                    </constraints>
+                                </imageView>
+                                <button opaque="NO" tag="1001" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ac9-lB-T0k">
+                                    <rect key="frame" x="0.0" y="0.0" width="121.66666666666667" height="55"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <state key="normal">
+                                        <color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                    </state>
+                                </button>
+                            </subviews>
+                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstItem="cfT-LB-SNv" firstAttribute="centerX" secondItem="3ud-K6-gBw" secondAttribute="centerX" constant="-4" id="6fu-Rx-39P"/>
+                                <constraint firstAttribute="bottom" secondItem="Ac9-lB-T0k" secondAttribute="bottom" id="FjI-Y5-7yE"/>
+                                <constraint firstItem="cfT-LB-SNv" firstAttribute="centerY" secondItem="3ud-K6-gBw" secondAttribute="centerY" id="J0t-LD-eL1"/>
+                                <constraint firstItem="Ac9-lB-T0k" firstAttribute="leading" secondItem="3ud-K6-gBw" secondAttribute="leading" id="g1O-Id-15a"/>
+                                <constraint firstItem="aFu-Ok-mVy" firstAttribute="centerY" secondItem="3ud-K6-gBw" secondAttribute="centerY" id="gDl-5L-mjU"/>
+                                <constraint firstItem="aFu-Ok-mVy" firstAttribute="leading" secondItem="cfT-LB-SNv" secondAttribute="trailing" constant="5" id="llT-OJ-w6i"/>
+                                <constraint firstItem="Ac9-lB-T0k" firstAttribute="top" secondItem="3ud-K6-gBw" secondAttribute="top" id="ofj-Sg-mn8"/>
+                                <constraint firstAttribute="trailing" secondItem="Ac9-lB-T0k" secondAttribute="trailing" id="tlR-cR-LCw"/>
+                            </constraints>
+                        </view>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Z8Q-fT-2Vr">
+                            <rect key="frame" x="131.66666666666666" y="0.0" width="121.66666666666666" height="55"/>
+                            <subviews>
+                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="全部状态" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vxK-r7-9sg">
+                                    <rect key="frame" x="29" y="19" width="56" height="17"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <color key="textColor" red="0.074509803921568626" green="0.078431372549019607" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                    <nil key="highlightedColor"/>
+                                </label>
+                                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sort_down_grey" translatesAutoresizingMaskIntoConstraints="NO" id="idf-14-rMz">
+                                    <rect key="frame" x="90" y="25" width="9" height="5"/>
+                                    <constraints>
+                                        <constraint firstAttribute="width" constant="9" id="2rB-eK-C35"/>
+                                        <constraint firstAttribute="height" constant="5" id="PIL-WN-xkd"/>
+                                    </constraints>
+                                </imageView>
+                                <button opaque="NO" tag="1002" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="j1t-mT-XyA">
+                                    <rect key="frame" x="0.0" y="0.0" width="121.66666666666667" height="55"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <state key="normal">
+                                        <color key="titleColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="calibratedRGB"/>
+                                    </state>
+                                </button>
+                            </subviews>
+                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstItem="j1t-mT-XyA" firstAttribute="leading" secondItem="Z8Q-fT-2Vr" secondAttribute="leading" id="0ib-n1-ca3"/>
+                                <constraint firstAttribute="bottom" secondItem="j1t-mT-XyA" secondAttribute="bottom" id="FZL-fn-2Dt"/>
+                                <constraint firstItem="vxK-r7-9sg" firstAttribute="centerX" secondItem="Z8Q-fT-2Vr" secondAttribute="centerX" constant="-4" id="MaH-dZ-7ix"/>
+                                <constraint firstItem="vxK-r7-9sg" firstAttribute="centerY" secondItem="Z8Q-fT-2Vr" secondAttribute="centerY" id="VqG-LO-GJj"/>
+                                <constraint firstAttribute="trailing" secondItem="j1t-mT-XyA" secondAttribute="trailing" id="VxY-bB-unG"/>
+                                <constraint firstItem="j1t-mT-XyA" firstAttribute="top" secondItem="Z8Q-fT-2Vr" secondAttribute="top" id="cMc-ie-YnM"/>
+                                <constraint firstItem="idf-14-rMz" firstAttribute="leading" secondItem="vxK-r7-9sg" secondAttribute="trailing" constant="5" id="dLB-Vt-NCZ"/>
+                                <constraint firstItem="idf-14-rMz" firstAttribute="centerY" secondItem="Z8Q-fT-2Vr" secondAttribute="centerY" id="yDm-pc-vUp"/>
+                            </constraints>
+                        </view>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yMy-1B-zxV">
+                            <rect key="frame" x="263.33333333333331" y="0.0" width="121.66666666666669" height="55"/>
+                            <subviews>
+                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="全部考勤" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Xc-2m-8mt">
+                                    <rect key="frame" x="29" y="19" width="56" height="17"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <color key="textColor" red="0.074509803921568626" green="0.078431372549019607" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                    <nil key="highlightedColor"/>
+                                </label>
+                                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sort_down_grey" translatesAutoresizingMaskIntoConstraints="NO" id="grW-VA-qlz">
+                                    <rect key="frame" x="90" y="25" width="9" height="5"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="5" id="hAG-sG-mv7"/>
+                                        <constraint firstAttribute="width" constant="9" id="sqn-jl-TbO"/>
+                                    </constraints>
+                                </imageView>
+                                <button opaque="NO" tag="1003" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5J6-Qp-5o7">
+                                    <rect key="frame" x="0.0" y="0.0" width="121.66666666666667" height="55"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                    <state key="normal">
+                                        <color key="titleColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                    </state>
+                                </button>
+                            </subviews>
+                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstItem="5J6-Qp-5o7" firstAttribute="leading" secondItem="yMy-1B-zxV" secondAttribute="leading" id="0pe-f0-slu"/>
+                                <constraint firstItem="grW-VA-qlz" firstAttribute="centerY" secondItem="yMy-1B-zxV" secondAttribute="centerY" id="47f-2b-PEp"/>
+                                <constraint firstItem="9Xc-2m-8mt" firstAttribute="centerX" secondItem="yMy-1B-zxV" secondAttribute="centerX" constant="-4" id="4bT-SA-PhH"/>
+                                <constraint firstAttribute="trailing" secondItem="5J6-Qp-5o7" secondAttribute="trailing" id="8jw-zM-6iK"/>
+                                <constraint firstItem="5J6-Qp-5o7" firstAttribute="top" secondItem="yMy-1B-zxV" secondAttribute="top" id="HUX-nk-toA"/>
+                                <constraint firstAttribute="bottom" secondItem="5J6-Qp-5o7" secondAttribute="bottom" id="SLT-UZ-dPb"/>
+                                <constraint firstItem="9Xc-2m-8mt" firstAttribute="centerY" secondItem="yMy-1B-zxV" secondAttribute="centerY" id="jhO-f9-KY6"/>
+                                <constraint firstItem="grW-VA-qlz" firstAttribute="leading" secondItem="9Xc-2m-8mt" secondAttribute="trailing" constant="5" id="m1B-rA-bFZ"/>
+                            </constraints>
+                        </view>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="Z8Q-fT-2Vr" firstAttribute="top" secondItem="3ud-K6-gBw" secondAttribute="top" id="7Vc-Lw-Cz5"/>
+                        <constraint firstItem="yMy-1B-zxV" firstAttribute="top" secondItem="3ud-K6-gBw" secondAttribute="top" id="7vF-v2-rbp"/>
+                        <constraint firstItem="3ud-K6-gBw" firstAttribute="top" secondItem="nUQ-28-ciH" secondAttribute="top" id="Kwb-PF-i4E"/>
+                        <constraint firstAttribute="trailing" secondItem="yMy-1B-zxV" secondAttribute="trailing" id="a8j-cM-Bk3"/>
+                        <constraint firstItem="Z8Q-fT-2Vr" firstAttribute="width" secondItem="3ud-K6-gBw" secondAttribute="width" id="dvD-UR-61H"/>
+                        <constraint firstItem="Z8Q-fT-2Vr" firstAttribute="leading" secondItem="3ud-K6-gBw" secondAttribute="trailing" constant="10" id="g49-fx-rbj"/>
+                        <constraint firstAttribute="bottom" secondItem="3ud-K6-gBw" secondAttribute="bottom" id="jS1-OF-iaY"/>
+                        <constraint firstItem="yMy-1B-zxV" firstAttribute="leading" secondItem="Z8Q-fT-2Vr" secondAttribute="trailing" constant="10" id="obg-cI-Ey6"/>
+                        <constraint firstItem="3ud-K6-gBw" firstAttribute="leading" secondItem="nUQ-28-ciH" secondAttribute="leading" id="pPn-cT-EMU"/>
+                        <constraint firstItem="Z8Q-fT-2Vr" firstAttribute="bottom" secondItem="3ud-K6-gBw" secondAttribute="bottom" id="s1y-gn-zl5"/>
+                        <constraint firstItem="yMy-1B-zxV" firstAttribute="width" secondItem="3ud-K6-gBw" secondAttribute="width" id="uUy-6G-XIb"/>
+                        <constraint firstItem="yMy-1B-zxV" firstAttribute="bottom" secondItem="3ud-K6-gBw" secondAttribute="bottom" id="yBY-DV-CGv"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="size" keyPath="shadowOffset">
+                            <size key="value" width="0.0" height="2"/>
+                        </userDefinedRuntimeAttribute>
+                        <userDefinedRuntimeAttribute type="number" keyPath="shadowOpacity">
+                            <real key="value" value="1"/>
+                        </userDefinedRuntimeAttribute>
+                        <userDefinedRuntimeAttribute type="number" keyPath="shadowRadius">
+                            <real key="value" value="7"/>
+                        </userDefinedRuntimeAttribute>
+                        <userDefinedRuntimeAttribute type="color" keyPath="shadowUIColor">
+                            <color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.070000000000000007" colorSpace="calibratedRGB"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstAttribute="bottom" secondItem="nUQ-28-ciH" secondAttribute="bottom" id="8Ge-mS-YzV"/>
+                <constraint firstAttribute="trailing" secondItem="nUQ-28-ciH" secondAttribute="trailing" id="9yc-y0-4fF"/>
+                <constraint firstItem="nUQ-28-ciH" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="igM-Q3-fAI"/>
+                <constraint firstItem="nUQ-28-ciH" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="yVO-Aa-YHu"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <point key="canvasLocation" x="41.984732824427482" y="-148.94366197183101"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="sort_down_grey" width="9" height="5"/>
+    </resources>
+</document>

+ 1 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/Controller/MyCourseViewController.m

@@ -318,6 +318,7 @@
 - (CourseDescAlertView *)tipsAlert {
     if (!_tipsAlert) {
         _tipsAlert = [CourseDescAlertView sharedInstance];
+        _tipsAlert.showType = SHOWTYPE_ALL;
         [_tipsAlert refreshView];
     }
     return _tipsAlert;

+ 5 - 1
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/AccompanyCourseGroup/MyAccompanyCourseGroupView.m

@@ -12,6 +12,7 @@
 #import "Reachability.h"
 #import "ProgramCourseGroupModel.h"
 #import "MyCourseRankSortView.h"
+#import "AccompanyCourseGroupViewController.h"
 
 @interface MyAccompanyCourseGroupView ()<UITableViewDelegate,UITableViewDataSource>
 
@@ -198,7 +199,10 @@
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     // 课程详情
-    
+    ProgramCourseGroupModel *model = self.dataArray[indexPath.row];
+    AccompanyCourseGroupViewController *ctrl = [[AccompanyCourseGroupViewController alloc] init];
+    ctrl.courseGroupId = [NSString stringWithFormat:@"%.0f",model.courseGroupId];
+    [self.naviController pushViewController:ctrl animated:YES];
 }
 
 #pragma mark ------ lazying

+ 9 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/CourseGroupAlertView/CourseDescAlertView.h

@@ -7,17 +7,26 @@
 
 #import <UIKit/UIKit.h>
 
+typedef NS_ENUM(NSInteger, SHOWTYPE) {
+    SHOWTYPE_ALL = 0,
+    SHOWTYPE_SKIPMUIC,
+    SHOWTYPE_SINGLE_VIP,
+};
+
 typedef NS_ENUM(NSInteger, COURSE_DISPLAY_INDEX) {
     COURSE_DISPLAY_INDEX_VIP = 0,
     COURSE_DISPLAY_INDEX_ACCOMPANY,
     COURSE_DISPLAY_INDEX_LIVE,
     COURSE_DISPLAY_INDEX_VIDEO,
+    COURSE_DISPLAY_INDEX_MUSICROOM,
 };
 
 NS_ASSUME_NONNULL_BEGIN
 
 @interface CourseDescAlertView : UIView
 
+@property (nonatomic, assign) SHOWTYPE showType;
+
 + (instancetype)sharedInstance;
 
 - (void)refreshView;

+ 36 - 3
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/CourseGroupAlertView/CourseDescAlertView.m

@@ -22,6 +22,8 @@
 
 @property (nonatomic, strong) TYPageControl *pageControl;
 
+@property (nonatomic, strong) NSMutableArray *showArray;
+
 @end
 
 @implementation CourseDescAlertView
@@ -74,11 +76,11 @@
 
 #pragma mark - TYCyclePagerViewDataSource代理
 - (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView {
-    return self.bannerArray.count;
+    return self.showArray.count;
 }
 
 - (UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index {
-    NSDictionary *parm = self.bannerArray[index];
+    NSDictionary *parm = self.showArray[index];
     CourseDescAlertCell *cell = [pagerView dequeueReusableCellWithReuseIdentifier:@"CourseDescAlertCell" forIndex:index];
     [cell configWithTitle:[parm ks_stringValueForKey:@"title"] desc:[parm ks_stringValueForKey:@"desc"]];
     return cell;
@@ -127,7 +129,7 @@
         _pageControl = [[TYPageControl alloc] init];
         _pageControl.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
         _pageControl.pageIndicatorSpaing = 6.0f;
-        _pageControl.numberOfPages = self.bannerArray.count;
+        _pageControl.numberOfPages = self.showArray.count;
         _pageControl.currentPageIndicatorTintColor = THEMECOLOR;
         _pageControl.pageIndicatorTintColor = HexRGB(0xDFDFDF);
         _pageControl.pageIndicatorSize = CGSizeMake(6, 6);
@@ -142,6 +144,37 @@
     }
     return _bannerArray;
 }
+
+- (void)setShowType:(SHOWTYPE)showType {
+    _showType = showType;
+    switch (showType) {
+        case SHOWTYPE_ALL:
+        {
+            self.showArray = [NSMutableArray arrayWithArray:self.bannerArray];
+        }
+            break;
+        case SHOWTYPE_SKIPMUIC:
+        {
+            self.showArray = [NSMutableArray arrayWithArray:[self.bannerArray subarrayWithRange:NSMakeRange(0, 4)]];
+        }
+            break;
+        case SHOWTYPE_SINGLE_VIP:
+        {
+            self.showArray = [NSMutableArray arrayWithArray:[self.bannerArray subarrayWithRange:NSMakeRange(0, 1)]];
+        }
+            break;
+        default:
+            break;
+    }
+    
+    self.pageControl.numberOfPages = self.showArray.count;
+    if (self.showArray.count > 1) {
+        self.pageControl.hidden = NO;
+    }
+    else {
+        self.pageControl.hidden = YES;
+    }
+}
 /*
 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.

+ 1 - 8
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/VIPCourseGroup/MyProgramCourseGroupCell.m

@@ -34,15 +34,8 @@
 }
 
 - (void)configWithSource:(ProgramCourseGroupModel *)model isVipCourse:(BOOL)isVipCourse {
-    NSString *courseGroupTitle = @"";
-    if (isVipCourse) {
-        courseGroupTitle = [NSString stringWithFormat:@"VIP定制课-%@", model.studentName];
-    }
-    else {
-        courseGroupTitle = [NSString stringWithFormat:@"趣纠课-%@", model.studentName];
-    }
     
-    self.programTitle.text = courseGroupTitle;
+    self.programTitle.text = [NSString returnNoNullStringWithString:model.courseGroupName];
     /// 状态
     [self evaluateGroupStatus:model.status];
     

+ 5 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Home/MyCourse/View/VIPCourseGroup/MyVipCourseGroupView.m

@@ -12,6 +12,7 @@
 #import "Reachability.h"
 #import "ProgramCourseGroupModel.h"
 #import "MyCourseRankSortView.h"
+#import "VIPCourseGroupViewController.h"
 
 @interface MyVipCourseGroupView ()<UITableViewDelegate,UITableViewDataSource>
 
@@ -199,6 +200,10 @@
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     // 课程详情
+    ProgramCourseGroupModel *model = self.dataArray[indexPath.row];
+    VIPCourseGroupViewController *ctrl = [[VIPCourseGroupViewController alloc] init];
+    ctrl.courseGroupId = [NSString stringWithFormat:@"%.0f",model.courseGroupId];
+    [self.naviController pushViewController:ctrl animated:YES];
 }
 
 #pragma mark ------ lazying

+ 24 - 2
KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/Controller/MineVipProgramViewController.m

@@ -8,6 +8,7 @@
 #import "MineVipProgramViewController.h"
 #import "MineVipProgramNavView.h"
 #import "MineVipProgramMainView.h"
+#import "CourseDescAlertView.h"
 
 @interface MineVipProgramViewController ()
 
@@ -31,6 +32,8 @@
 
 @property (nonatomic, assign) NSInteger dayConfig;
 
+@property (nonatomic, strong) CourseDescAlertView *tipsAlert;
+
 @end
 
 @implementation MineVipProgramViewController
@@ -159,13 +162,19 @@
     if (!_navView) {
         _navView = [MineVipProgramNavView sharedInstance];
         MJWeakSelf;
-        [_navView navActionCallback:^{
-            [weakSelf backAction];
+        [_navView navActionCallback:^(BOOL isBack) {
+            if (isBack) {
+                [weakSelf backAction];
+            }
+            else {
+                [weakSelf showTipsAlert:0];
+            }
         }];
     }
     return _navView;
 }
 
+
 - (MineVipProgramMainView *)settingView {
     if (!_settingView) {
         _settingView = [MineVipProgramMainView sharedInstanace];
@@ -199,6 +208,19 @@
     }];
 }
 
+- (void)showTipsAlert:(NSInteger)displayIndex {
+    [self.tipsAlert displayCourseTypeIndex:displayIndex];
+    [self.tipsAlert showInView:[NSObject getKeyWindow]];
+}
+
+- (CourseDescAlertView *)tipsAlert {
+    if (!_tipsAlert) {
+        _tipsAlert = [CourseDescAlertView sharedInstance];
+        _tipsAlert.showType = SHOWTYPE_SINGLE_VIP;
+        [_tipsAlert refreshView];
+    }
+    return _tipsAlert;
+}
 /*
 #pragma mark - Navigation
 

+ 1 - 1
KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/View/VIPProgramCreate/MineVipProgramNavView.h

@@ -7,7 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-typedef void(^ProgramNavCallback)(void);
+typedef void(^ProgramNavCallback)(BOOL isBack);
 
 NS_ASSUME_NONNULL_BEGIN
 

+ 6 - 1
KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/View/VIPProgramCreate/MineVipProgramNavView.m

@@ -34,10 +34,15 @@
 
 - (IBAction)backAction:(id)sender {
     if (self.callback) {
-        self.callback();
+        self.callback(YES);
     }
 }
 
+- (IBAction)showAlert:(id)sender {
+    if (self.callback) {
+        self.callback(NO);
+    }
+}
 
 + (CGFloat)getViewHeight {
     return kNaviBarHeight;

+ 19 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Mine/MinePage/View/VIPProgramCreate/MineVipProgramNavView.xib

@@ -35,6 +35,19 @@
                             <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
                             <nil key="highlightedColor"/>
                         </label>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="program_tips" translatesAutoresizingMaskIntoConstraints="NO" id="cJr-fO-ayi">
+                            <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="xvL-gk-hcc">
+                            <rect key="frame" x="349" y="0.0" width="44" height="44"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="44" id="WF7-AJ-jpr"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="showAlert:" destination="iN0-l3-epB" eventType="touchUpInside" id="Sc7-Ek-NFu"/>
+                            </connections>
+                        </button>
                     </subviews>
                     <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                     <constraints>
@@ -42,10 +55,15 @@
                         <constraint firstItem="oLK-ro-388" firstAttribute="centerY" secondItem="bc8-oD-lqn" secondAttribute="centerY" id="2C5-dW-BEo"/>
                         <constraint firstItem="snd-KJ-Hzd" firstAttribute="top" secondItem="bc8-oD-lqn" secondAttribute="top" id="4Z0-Er-nuF"/>
                         <constraint firstItem="XN8-cR-W0z" firstAttribute="leading" secondItem="bc8-oD-lqn" secondAttribute="leading" constant="15" id="EYt-Au-4jZ"/>
+                        <constraint firstAttribute="trailing" secondItem="xvL-gk-hcc" secondAttribute="trailing" id="Es7-KP-0Zf"/>
                         <constraint firstAttribute="bottom" secondItem="snd-KJ-Hzd" secondAttribute="bottom" id="Ff6-PX-bm9"/>
+                        <constraint firstAttribute="trailing" secondItem="cJr-fO-ayi" secondAttribute="trailing" constant="14" id="VT7-x2-dq5"/>
+                        <constraint firstAttribute="bottom" secondItem="xvL-gk-hcc" secondAttribute="bottom" id="W6o-F4-R68"/>
                         <constraint firstItem="XN8-cR-W0z" firstAttribute="centerY" secondItem="bc8-oD-lqn" secondAttribute="centerY" id="eD9-g7-IPT"/>
                         <constraint firstAttribute="height" constant="44" id="jAP-eQ-wgr"/>
+                        <constraint firstItem="cJr-fO-ayi" firstAttribute="centerY" secondItem="bc8-oD-lqn" secondAttribute="centerY" id="mmA-d6-fda"/>
                         <constraint firstItem="oLK-ro-388" firstAttribute="centerX" secondItem="bc8-oD-lqn" secondAttribute="centerX" id="qM6-qg-08d"/>
+                        <constraint firstItem="xvL-gk-hcc" firstAttribute="top" secondItem="bc8-oD-lqn" secondAttribute="top" id="uYP-7a-lVo"/>
                     </constraints>
                 </view>
             </subviews>
@@ -66,5 +84,6 @@
     </objects>
     <resources>
         <image name="back_black" width="12" height="20"/>
+        <image name="program_tips" width="20" height="20"/>
     </resources>
 </document>