Steven před 2 roky
rodič
revize
a1cc4abd45
25 změnil soubory, kde provedl 1334 přidání a 75 odebrání
  1. 46 0
      KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj
  2. binární
      KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate
  3. 16 16
      KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  4. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/Contents.json
  5. binární
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@2x.png
  6. binární
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@3x.png
  7. 12 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.h
  8. 23 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.m
  9. 1 0
      KulexiuForStudent/KulexiuForStudent/Module/Course/AccompanyCourse/View/AccompanyCourseInfoCell.xib
  10. 13 1
      KulexiuForStudent/KulexiuForStudent/Module/Course/Controller/CourseViewController.m
  11. 28 0
      KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/Controller/MusicRoomDetailViewController.h
  12. 528 0
      KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/Controller/MusicRoomDetailViewController.m
  13. 27 0
      KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.h
  14. 82 0
      KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.m
  15. 184 0
      KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.xib
  16. 29 9
      KulexiuForStudent/KulexiuForStudent/Module/Course/View/MusicRoomCourseCell.m
  17. 13 38
      KulexiuForStudent/KulexiuForStudent/Module/Course/View/MusicRoomCourseCell.xib
  18. 10 2
      KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m
  19. 1 0
      KulexiuForStudent/KulexiuForStudent/Module/Home/View/HomeCourseTipsView.h
  20. 11 1
      KulexiuForStudent/KulexiuForStudent/Module/Home/View/HomeCourseTipsView.m
  21. 3 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/Homework/Model/HomeworkDetailModel.h
  22. 2 2
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Controller/MyCourseViewController.m
  23. 33 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/MusicRoomListModel.h
  24. 190 0
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/MusicRoomListModel.m
  25. 60 6
      KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLessonBodyView.m

+ 46 - 0
KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj

@@ -442,6 +442,10 @@
 		BC40BA23281255F700DEC0D1 /* HomeCourseTipsView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC40BA22281255F700DEC0D1 /* HomeCourseTipsView.m */; };
 		BC40BA252812560100DEC0D1 /* HomeCourseTipsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC40BA242812560100DEC0D1 /* HomeCourseTipsView.xib */; };
 		BC48C3A92828FC7D00EE65C5 /* KSUploadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BC48C3A82828FC7D00EE65C5 /* KSUploadManager.m */; };
+		BC494A77286952B500CCD343 /* MusicRoomDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC494A76286952B500CCD343 /* MusicRoomDetailViewController.m */; };
+		BC494A7C286958EC00CCD343 /* MusicRoomCourseInfoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC494A7A286958EC00CCD343 /* MusicRoomCourseInfoCell.m */; };
+		BC494A7D286958EC00CCD343 /* MusicRoomCourseInfoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC494A7B286958EC00CCD343 /* MusicRoomCourseInfoCell.xib */; };
+		BC494A8028696BC300CCD343 /* MusicRoomListModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC494A7F28696BC300CCD343 /* MusicRoomListModel.m */; };
 		BC50171227FC0D5600F8BCBC /* SubjectChooseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC50171127FC0D5600F8BCBC /* SubjectChooseViewController.m */; };
 		BC50171527FC0D8300F8BCBC /* SubjectChooseBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC50171427FC0D8300F8BCBC /* SubjectChooseBodyView.m */; };
 		BC50171727FC0D8E00F8BCBC /* SubjectChooseBodyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC50171627FC0D8D00F8BCBC /* SubjectChooseBodyView.xib */; };
@@ -1548,6 +1552,13 @@
 		BC48C3A72828FC7D00EE65C5 /* KSUploadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSUploadManager.h; sourceTree = "<group>"; };
 		BC48C3A82828FC7D00EE65C5 /* KSUploadManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSUploadManager.m; sourceTree = "<group>"; };
 		BC48C3AB2829184C00EE65C5 /* KulexiuForStudent.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = KulexiuForStudent.entitlements; sourceTree = "<group>"; };
+		BC494A75286952B500CCD343 /* MusicRoomDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicRoomDetailViewController.h; sourceTree = "<group>"; };
+		BC494A76286952B500CCD343 /* MusicRoomDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MusicRoomDetailViewController.m; sourceTree = "<group>"; };
+		BC494A79286958EC00CCD343 /* MusicRoomCourseInfoCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicRoomCourseInfoCell.h; sourceTree = "<group>"; };
+		BC494A7A286958EC00CCD343 /* MusicRoomCourseInfoCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MusicRoomCourseInfoCell.m; sourceTree = "<group>"; };
+		BC494A7B286958EC00CCD343 /* MusicRoomCourseInfoCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MusicRoomCourseInfoCell.xib; sourceTree = "<group>"; };
+		BC494A7E28696BC300CCD343 /* MusicRoomListModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MusicRoomListModel.h; sourceTree = "<group>"; };
+		BC494A7F28696BC300CCD343 /* MusicRoomListModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MusicRoomListModel.m; sourceTree = "<group>"; };
 		BC50171027FC0D5600F8BCBC /* SubjectChooseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubjectChooseViewController.h; sourceTree = "<group>"; };
 		BC50171127FC0D5600F8BCBC /* SubjectChooseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SubjectChooseViewController.m; sourceTree = "<group>"; };
 		BC50171327FC0D8300F8BCBC /* SubjectChooseBodyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubjectChooseBodyView.h; sourceTree = "<group>"; };
@@ -2456,6 +2467,7 @@
 		275FA1F727E7356A00CFEA2E /* Course */ = {
 			isa = PBXGroup;
 			children = (
+				BC494A73286952A200CCD343 /* MusicRoom */,
 				BC11923B280ED9CC00A716F7 /* AccompanyCourse */,
 				275FA1F827E7356A00CFEA2E /* Controller */,
 				275FA1FB27E7356B00CFEA2E /* Model */,
@@ -3678,6 +3690,8 @@
 				BC11921E280ED6F400A716F7 /* LiveLessonModel.m */,
 				BC0D1F732810165400C5D9E5 /* VideoCourseModel.h */,
 				BC0D1F742810165400C5D9E5 /* VideoCourseModel.m */,
+				BC494A7E28696BC300CCD343 /* MusicRoomListModel.h */,
+				BC494A7F28696BC300CCD343 /* MusicRoomListModel.m */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -3873,6 +3887,34 @@
 			path = View;
 			sourceTree = "<group>";
 		};
+		BC494A73286952A200CCD343 /* MusicRoom */ = {
+			isa = PBXGroup;
+			children = (
+				BC494A74286952A200CCD343 /* Controller */,
+				BC494A78286958C700CCD343 /* View */,
+			);
+			path = MusicRoom;
+			sourceTree = "<group>";
+		};
+		BC494A74286952A200CCD343 /* Controller */ = {
+			isa = PBXGroup;
+			children = (
+				BC494A75286952B500CCD343 /* MusicRoomDetailViewController.h */,
+				BC494A76286952B500CCD343 /* MusicRoomDetailViewController.m */,
+			);
+			path = Controller;
+			sourceTree = "<group>";
+		};
+		BC494A78286958C700CCD343 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				BC494A79286958EC00CCD343 /* MusicRoomCourseInfoCell.h */,
+				BC494A7A286958EC00CCD343 /* MusicRoomCourseInfoCell.m */,
+				BC494A7B286958EC00CCD343 /* MusicRoomCourseInfoCell.xib */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		BC8A4545283DC33400094BBB /* CloudEngine */ = {
 			isa = PBXGroup;
 			children = (
@@ -5034,6 +5076,7 @@
 				BCFE53F22812898700AD6786 /* HomeVideoCourseCell.xib in Resources */,
 				2723B5BA27F157B100E0B90B /* ChatAddressHeaderView.xib in Resources */,
 				BC8C2C7F28265D8E00FBA5D5 /* KSNewsAlert.xib in Resources */,
+				BC494A7D286958EC00CCD343 /* MusicRoomCourseInfoCell.xib in Resources */,
 				BC119235280ED97C00A716F7 /* CourseForLiveCell.xib in Resources */,
 				2723B62E27F157D500E0B90B /* GroupApplyChooseAllCell.xib in Resources */,
 				275FA23A27E7356B00CFEA2E /* VefiBodyView.xib in Resources */,
@@ -5396,6 +5439,7 @@
 				BC8A45AA283DC33400094BBB /* TrackChooseView.m in Sources */,
 				BC8A45B2283DC33400094BBB /* CloudFeedbackView.m in Sources */,
 				BCB6355A27F6D2A300ACFDCF /* KSRemoteUserManager.m in Sources */,
+				BC494A7C286958EC00CCD343 /* MusicRoomCourseInfoCell.m in Sources */,
 				BCB6347127F6D29600ACFDCF /* KSChatEmojiBoardView.m in Sources */,
 				2779354527E324A60010E277 /* UIImage+UIImageScale.m in Sources */,
 				2723B66427F15CFC00E0B90B /* VeriCheckView.m in Sources */,
@@ -5649,6 +5693,7 @@
 				2779356727E324A70010E277 /* UIColor+Hex.m in Sources */,
 				BCB6345E27F6D29600ACFDCF /* KSLiveChatroomLeave.m in Sources */,
 				BC11929B280FD2E800A716F7 /* HomeworkBottomView.m in Sources */,
+				BC494A77286952B500CCD343 /* MusicRoomDetailViewController.m in Sources */,
 				BC8C2C602823F57100FBA5D5 /* AddressBottomView.m in Sources */,
 				275FA1E727E7351900CFEA2E /* KSWebSocketManager.m in Sources */,
 				277935AE27E324A80010E277 /* MSSBrowseRemindView.m in Sources */,
@@ -5699,6 +5744,7 @@
 				BCFE53F12812898700AD6786 /* HomeVideoCourseCell.m in Sources */,
 				BCB908F02850B08D00F5FF69 /* KSChatLiveShareCell.m in Sources */,
 				277935C027E324A90010E277 /* FSCalendarTransitionCoordinator.m in Sources */,
+				BC494A8028696BC300CCD343 /* MusicRoomListModel.m in Sources */,
 				2779355B27E324A70010E277 /* KSStatusView.m in Sources */,
 				2779355227E324A70010E277 /* VoMemoryCache.m in Sources */,
 				2779352A27E324A60010E277 /* UIView+Dealloc.m in Sources */,

binární
KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate


+ 16 - 16
KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -7,22 +7,6 @@
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "822F0FEC-1359-41D0-B1A2-66E94C0891D0"
-            shouldBeEnabled = "Yes"
-            ignoreCount = "0"
-            continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Common/Base/KSNetworkingManager.m"
-            startingColumnNumber = "9223372036854775807"
-            endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "784"
-            endingLineNumber = "784"
-            landmarkName = "+queryGroupDetail:groupId:success:faliure:"
-            landmarkType = "7">
-         </BreakpointContent>
-      </BreakpointProxy>
-      <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
-         <BreakpointContent
             uuid = "1810CE7E-B98C-4855-A767-4FD2705B3141"
             shouldBeEnabled = "No"
             ignoreCount = "0"
@@ -52,5 +36,21 @@
             landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "359CE66E-FE29-4D79-98E0-8D745D9E0DEB"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "KulexiuForStudent/Module/Course/MusicRoom/Controller/MusicRoomDetailViewController.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "88"
+            endingLineNumber = "88"
+            landmarkName = "-requestHomeworkMessage"
+            landmarkType = "7">
+         </BreakpointContent>
+      </BreakpointProxy>
    </Breakpoints>
 </Bucket>

+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/Contents.json

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

binární
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@2x.png


binární
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Course/course_musicRoom.imageset/course_musicRoom@3x.png


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

@@ -532,6 +532,18 @@ NS_ASSUME_NONNULL_BEGIN
 /// @param faliure 失败
 + (void)videoLessonGroupRequest:(NSString *)post page:(NSInteger)page rows:(NSInteger)rows success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
 
+// /api-student/courseSchedule/queryPianoClass
+
+/// 我的课程-琴房课
+/// @param post post
+/// @param classMonth 月份 yyyy-MM
+/// @param status 课程状态(NOT_START:未开始 ING:进行中 COMPLETE:已完成 CANCEL:已取消)
+/// @param subjectId 声部id
+/// @param page 页数
+/// @param rows 跳树
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryPianoClassRequest:(NSString *)post classMonth:(NSString *)classMonth status:(NSString *)status subjectId:(NSString *)subjectId page:(NSInteger)page rows:(NSInteger)rows success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
 
 #pragma mark ---- 首页-老师风采
 // /api-student/teacher/stylePage

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

@@ -1116,6 +1116,29 @@
     [self request:post andWithUrl:url and:parm success:success faliure:faliure];
 }
 
+// /api-student/courseSchedule/queryPianoClass
+
+/// 我的课程-琴房课
+/// @param post post
+/// @param classMonth 月份 yyyy-MM
+/// @param status 课程状态(NOT_START:未开始 ING:进行中 COMPLETE:已完成 CANCEL:已取消)
+/// @param subjectId 声部id
+/// @param page 页数
+/// @param rows 跳树
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryPianoClassRequest:(NSString *)post classMonth:(NSString *)classMonth status:(NSString *)status subjectId:(NSString *)subjectId page:(NSInteger)page rows:(NSInteger)rows success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    [self configRequestMethodJSON];
+    NSString *url = [NSString stringWithFormat:@"%@%@", hostURL, @"/api-student/courseSchedule/queryPianoClass"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:classMonth forKey:@"classMonth"];
+    [parm setValue:status forKey:@"status"];
+    [parm setValue:subjectId forKey:@"subjectId"];
+    [parm setValue:@(page) forKey:@"page"];
+    [parm setValue:@(rows) forKey:@"rows"];
+    [self request:post andWithUrl:url and:parm success:success faliure:faliure];
+}
+
 #pragma mark ---- 首页-老师风采
 
 // /api-student/teacher/stylePage

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Module/Course/AccompanyCourse/View/AccompanyCourseInfoCell.xib

@@ -127,6 +127,7 @@
                             <constraint firstAttribute="bottom" secondItem="s7E-Da-TcK" secondAttribute="bottom" constant="20" id="a6x-Et-6cK"/>
                             <constraint firstItem="s7E-Da-TcK" firstAttribute="leading" secondItem="Me9-vj-Fhq" secondAttribute="leading" constant="11" id="dAu-VP-8Cy"/>
                             <constraint firstItem="mNS-6d-8wr" firstAttribute="leading" secondItem="s7E-Da-TcK" secondAttribute="trailing" constant="10" id="dm3-Jc-bB0"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="dZv-fL-5CE" secondAttribute="trailing" constant="10" id="gPp-hR-Lcf"/>
                             <constraint firstItem="2RD-hr-hLB" firstAttribute="leading" secondItem="mNS-6d-8wr" secondAttribute="leading" id="iOB-o4-an5"/>
                             <constraint firstItem="dZv-fL-5CE" firstAttribute="centerY" secondItem="mNS-6d-8wr" secondAttribute="centerY" id="iZq-rI-A9M"/>
                             <constraint firstAttribute="trailing" secondItem="09K-c6-xYX" secondAttribute="trailing" constant="10" id="p00-p1-Cqn"/>

+ 13 - 1
KulexiuForStudent/KulexiuForStudent/Module/Course/Controller/CourseViewController.m

@@ -18,6 +18,7 @@
 #import "CourseForLiveCell.h"
 #import "AccompanyDetailViewController.h"
 #import "MusicRoomCourseCell.h"
+#import "MusicRoomDetailViewController.h"
 
 @interface CourseViewController ()<UITableViewDataSource,UITableViewDelegate,FSCalendarDataSource,FSCalendarDelegate,UIGestureRecognizerDelegate>
 {
@@ -434,6 +435,9 @@
     else if ([model.courseType isEqualToString:@"LIVE"]) { // 直播课详情
         [self liveCourseDetail:model.courseId courseGroupId:model.courseGoupId];
     }
+    else if ([model.courseType isEqualToString:@"PIANO_ROOM_CLASS"]) { // 琴房课详情
+        [self showMusicRoomDetail:model];
+    }
     else {
         [self showAccompanyDetailAction:model];
     }
@@ -464,6 +468,14 @@
     [self.navigationController pushViewController:detailVC animated:YES];
 }
 
+- (void)showMusicRoomDetail:(TableCourseModel *)source {
+    MusicRoomDetailViewController *detailVC = [[MusicRoomDetailViewController alloc] init];
+    detailVC.courseId = source.courseId;
+    detailVC.courseGroupId = source.courseGoupId;
+    detailVC.teacherId = source.userId;
+    [self.navigationController pushViewController:detailVC animated:YES];
+}
+
 - (void)liveCourseAction:(LIVECOURSEACTION)action source:(TableCourseModel *)source {
     switch (action) {
         case LIVECOURSEACTION_CHAT:  // 聊天
@@ -491,7 +503,7 @@
 
 - (void)liveCourseDetail:(NSString *)courseId courseGroupId:(NSString *)courseGroupId {
     KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
-    NSString *url = [NSString stringWithFormat:@"%@/#/liveDetail?groupId=%@&classId=%@", WEBHOST, courseGroupId,courseId];
+    NSString *url = [NSString stringWithFormat:@"%@/#/liveDetail?joinRoom=1&groupId=%@&classId=%@", WEBHOST, courseGroupId,courseId];
     ctrl.url = url;
     [self.navigationController pushViewController:ctrl animated:YES];
 }

+ 28 - 0
KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/Controller/MusicRoomDetailViewController.h

@@ -0,0 +1,28 @@
+//
+//  MusicRoomDetailViewController.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/6/27.
+//
+
+#import "KSBaseViewController.h"
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// 琴房课详情
+@interface MusicRoomDetailViewController : KSBaseViewController
+
+@property (nonatomic, strong) NSString *courseId;
+
+@property (nonatomic, strong) NSString *courseGroupId;
+
+@property (nonatomic, strong) NSString *teacherId;
+
+@property (nonatomic, assign) NSInteger joinRoomBeforeTime; // 上课开始时间
+
+@property (nonatomic, assign) NSInteger quitRomeEndTime;    // 下课截止时间
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 528 - 0
KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/Controller/MusicRoomDetailViewController.m

@@ -0,0 +1,528 @@
+//
+//  MusicRoomDetailViewController.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/6/27.
+//
+
+#import "MusicRoomDetailViewController.h"
+#import "AccompanyArrangeCell.h"
+#import "AccompanyHomeworkCell.h"
+#import "AccompanyRemarkCell.h"
+#import "AccompanyDetailBottomView.h"
+#import "HomeworkDetailModel.h"
+#import "EvaluateDetailModel.h"
+#import "AccompanyAlertView.h"
+#import "KSChatConversationViewController.h"
+#import "WMPlayer.h"
+#import "RecordCheckManager.h"
+#import "KSPremissionAlert.h"
+#import "KSMediaManager.h"
+#import "OnlineClassManager.h"
+#import "MusicRoomCourseInfoCell.h"
+
+@interface MusicRoomDetailViewController ()<UITableViewDelegate,UITableViewDataSource,WMPlayerDelegate>
+{
+    WMPlayer *_wmPlayer;
+    CGRect _playerFrame;
+}
+@property (nonatomic, strong) UIView *bgView;
+
+@property (nonatomic, assign) BOOL isRatation;
+
+@property (nonatomic, strong) UITableView *tableView;
+
+@property (nonatomic, strong) AccompanyAlertView *alertView;
+
+@property (nonatomic, strong) NSMutableArray *fileArray;
+
+@property (nonatomic, strong) KSMediaManager *mediaManager;
+
+@property (nonatomic, strong) HomeworkDetailModel *homeworkModel;
+@property (strong, nonatomic) MBProgressHUD *HUD;
+
+@property (nonatomic, strong) AccompanyDetailBottomView *bottomView;
+
+@property (nonatomic, strong) OnlineClassManager *classManager;
+
+@property (nonatomic, assign) BOOL canModify;
+
+@property (nonatomic, assign) BOOL isModify; // 是否修改作业
+@end
+
+@implementation MusicRoomDetailViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self allocTitle:@"课程详情"];
+    [self configUI];
+    [self requestCourseInfoMessage];
+    self.isModify = NO;
+}
+
+- (void)requestCourseInfoMessage {
+    [self requestHomeworkMessage];
+    [self requestRoomConfig];
+}
+
+- (void)requestRoomConfig {
+    [KSNetworkingManager selectRoomConfigRequest:KS_GET success:^(NSDictionary * _Nonnull dic) {
+        if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
+            NSDictionary *result = [dic dictionaryValueForKey:@"data"];
+            self.joinRoomBeforeTime = [result integerValueForKey:@"practiceStartTime"];
+            self.quitRomeEndTime = [result integerValueForKey:@"practiceEndTime"];
+        }
+        else {
+            [self MBPShow:MESSAGEKEY];
+        }
+    } faliure:^(NSError * _Nonnull error) {
+        
+    }];
+}
+
+- (void)requestHomeworkMessage {
+    [self showhud];
+    [KSNetworkingManager homeworkDetailRequest:KS_GET courseId:self.courseId success:^(NSDictionary * _Nonnull dic) {
+        [self removehub];
+        if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
+            self.homeworkModel = [[HomeworkDetailModel alloc] initWithDictionary:[dic dictionaryValueForKey:@"data"]];
+            if (self.homeworkModel.submitHomework == 1) {
+                if (![NSString isEmptyString:self.homeworkModel.studentAttachments]) {
+                    self.fileArray = [NSMutableArray arrayWithArray:[self.homeworkModel.studentAttachments componentsSeparatedByString:@","]];
+                }
+                else {
+                    self.fileArray = [NSMutableArray array];
+                }
+            }
+            else {
+                self.fileArray = [NSMutableArray array];
+            }
+        }
+        else {
+            [self MBPShow:MESSAGEKEY];
+        }
+        [self evaluateViewDisplay];
+        [self.tableView reloadData];
+    } faliure:^(NSError * _Nonnull error) {
+        [self removehub];
+    }];
+}
+
+- (void)evaluateViewDisplay {
+    // 老师布置过作业且没有点评 可以点击
+    if (self.homeworkModel.reviewHomework == 1 || self.homeworkModel.decorateHomework == 0) {
+        self.canModify = NO;
+        self.bottomView.actionButton.userInteractionEnabled = NO;
+        self.bottomView.actionButton.backgroundColor = HexRGB(0xe5e5e5);
+        [self.bottomView.actionButton setTitleColor:HexRGB(0x666666) forState:UIControlStateNormal];
+    }
+    else {
+        self.canModify = YES;
+        self.bottomView.actionButton.userInteractionEnabled = YES;
+        self.bottomView.actionButton.backgroundColor = THEMECOLOR;
+        [self.bottomView.actionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+    }
+}
+
+- (void)configUI {
+    [self.scrollView removeFromSuperview];
+    [self.view addSubview:self.tableView];
+    [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.mas_equalTo(self.view);
+        make.top.mas_equalTo(self.view.mas_top);
+        make.bottom.mas_equalTo(self.view.mas_bottom).offset(-iPhoneXSafeBottomMargin);
+    }];
+}
+
+- (void)evaluateWithStatusLabel:(UILabel *)statusLabel {
+    if ([self.homeworkModel.courseStatus isEqualToString:@"COMPLETE"]) {
+        statusLabel.text = @"已结束";
+        statusLabel.textColor = HexRGB(0x999999);
+        // 老师已点评作业 或者老师未布置作业
+        if (self.homeworkModel.reviewHomework == 1 || self.homeworkModel.decorateHomework == 0) {
+            self.bottomView.actionButton.userInteractionEnabled = NO;
+            [self.bottomView.actionButton setTitle:@"确认提交" forState:UIControlStateNormal];
+            [self.bottomView.actionButton setBackgroundColor:HexRGB(0xe5e5e5)];
+            [self.bottomView.actionButton setTitleColor:HexRGB(0x666666) forState:UIControlStateNormal];
+        }
+        else {
+            self.bottomView.actionButton.userInteractionEnabled = YES;
+            [self.bottomView.actionButton setTitle:@"确认提交" forState:UIControlStateNormal];
+            [self.bottomView.actionButton setBackgroundColor:THEMECOLOR];
+            [self.bottomView.actionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+        }
+    }
+    else if ([self.homeworkModel.courseStatus isEqualToString:@"ING"]) {
+        statusLabel.text = @"进行中";
+        statusLabel.textColor = THEMECOLOR;
+        self.bottomView.actionButton.userInteractionEnabled = YES;
+        [self.bottomView.actionButton setTitle:@"进入教室" forState:UIControlStateNormal];
+        [self.bottomView.actionButton setBackgroundColor:THEMECOLOR];
+        [self.bottomView.actionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+    }
+    else {
+        statusLabel.text = @"未开始";
+        statusLabel.textColor = HexRGB(0xff802c);
+        self.bottomView.actionButton.userInteractionEnabled = YES;
+        [self.bottomView.actionButton setTitle:@"进入教室" forState:UIControlStateNormal];
+        [self.bottomView.actionButton setBackgroundColor:THEMECOLOR];
+        [self.bottomView.actionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+    }
+}
+
+#pragma mark --- table data source
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return 4;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    if (indexPath.row == 0) {
+        MusicRoomCourseInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MusicRoomCourseInfoCell"];
+        [self evaluateWithStatusLabel:cell.statusLabel];
+        [cell configWithStartTime:self.homeworkModel.startTime endTime:self.homeworkModel.endTime courseName:self.homeworkModel.courseName chatGroupId:self.homeworkModel.imGroupId courseSubject:self.homeworkModel.subjectName];
+        cell.hideChatButton = YES;
+        return cell;
+    }
+    else if (indexPath.row == 1) {
+        AccompanyArrangeCell *cell  = [tableView dequeueReusableCellWithIdentifier:@"AccompanyArrangeCell"];
+        BOOL hasArrange = self.homeworkModel.decorateHomework == 1 ? YES : NO;
+        [cell configWithHomeworkContent:self.homeworkModel.content hasArrangeHomework:hasArrange];
+        return cell;
+    }
+    else if (indexPath.row == 2) {
+        // studentAttachments
+        BOOL canDisplay = self.homeworkModel.decorateHomework == 1 ? YES : NO;
+        AccompanyHomeworkCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AccompanyHomeworkCell"];
+        cell.canSubmit = self.canModify;
+        MJWeakSelf;
+        [cell configWithAttachmentArray:self.fileArray canDisplaySubmitView:canDisplay callback:^(HOMEWORKACTION action, NSInteger viewIndex) {
+            [weakSelf operationActionWithType:action index:viewIndex];
+        }];
+        
+        return cell;
+    }
+    else  {
+        AccompanyRemarkCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AccompanyRemarkCell"];
+        BOOL hasEvaluate = self.homeworkModel.reviewHomework == 1? YES : NO;
+        [cell configWithRemarkMessage:self.homeworkModel.teacherReplied hasEvaluate:hasEvaluate];
+        return cell;
+    }
+}
+
+- (void)operationActionWithType:(HOMEWORKACTION)action index:(NSInteger)viewIndex {
+    switch (action) {
+        case HOMEWORKACTION_PLAY:
+        {
+            [self playVideoIndex:viewIndex];
+        }
+            break;
+        case HOMEWORKACTION_DELETE:
+        {
+            [self deleteVideoIndex:viewIndex];
+        }
+            break;
+        case HOMEWORKACTION_ADD: // 选择视频作业
+        {
+            // 调用相册
+            self.mediaManager = [[KSMediaManager alloc] init];
+            self.mediaManager.mediaType = MEDIATYPE_VIDEO;
+            self.mediaManager.maxPhotoNumber = 1;
+            self.mediaManager.baseCtrl = self;
+            self.mediaManager.needCropImage = NO;
+            MJWeakSelf;
+            [self.mediaManager noAlertCallback:^(NSString * _Nullable videoUrl, NSMutableArray * _Nullable imageArray, NSMutableArray * _Nullable imageAsset) {
+                NSLog(@"%@", videoUrl);
+                // 上传视频
+                [weakSelf uploadVideoWithUrl:videoUrl];
+            }];
+            [self.mediaManager pushImagePickerController];
+        }
+        default:
+            break;
+    }
+}
+
+#pragma mark --- 上传视频文件
+- (void)uploadVideoWithUrl:(NSString *)videoUrl {
+    [self hudTipWillShow:YES];
+    
+    NSURL *uploadFileUrl = [NSURL fileURLWithPath:videoUrl];
+    NSData *fileData = [NSData dataWithContentsOfURL:uploadFileUrl];
+    NSString *suffix = [NSString stringWithFormat:@".%@",[uploadFileUrl pathExtension]];
+    [[KSUploadManager shareInstance] configBucketName:@"homework"];
+    [[KSUploadManager shareInstance] videoUpload:fileData fileName:@"video" fileSuffix:suffix progress:^(int64_t bytesWritten, int64_t totalBytes) {
+        dispatch_main_async_safe(^{
+            // 显示进度
+            if (self.HUD) {
+                self.HUD.progress = bytesWritten / totalBytes;// progress是回调进度
+            }
+        });
+    } successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
+        [self hudTipWillShow:NO];
+        NSString *fileUrl = [fileUrlArray lastObject];
+        self.isModify = YES;
+        // 删除文件
+        [self removeVideoWithPath:videoUrl];
+        [self.fileArray addObject:fileUrl];
+        [self.tableView reloadData];
+    } faliure:^(NSError * _Nullable error, NSString * _Nullable descMessaeg) {
+        [self hudTipWillShow:NO];
+        if ([NSString isEmptyString:descMessaeg]) {
+            [self MBPShow:descMessaeg];
+        }
+    }];
+}
+
+- (void)removeVideoWithPath:(NSString *)videoUrl {
+    NSFileManager *fileMamager = [NSFileManager defaultManager];
+    if ([fileMamager fileExistsAtPath:videoUrl]) {
+        [fileMamager removeItemAtPath:videoUrl error:nil];
+    }
+}
+
+// 播放
+- (void)playVideoIndex:(NSInteger)index {
+    if (self.fileArray.count > index) {
+        NSString *fileUrl = self.fileArray[index];
+        [self playVideoWithUrl:fileUrl];
+    }
+}
+// 删除
+- (void)deleteVideoIndex:(NSInteger)index {
+    if (self.fileArray.count > index) {
+        [self.fileArray removeObjectAtIndex:index];
+        [self.tableView reloadData];
+    }
+    self.isModify = YES;
+}
+
+#pragma mark ------ WMPlayer
+- (void)playVideoWithUrl:(NSString *)fileUrl {
+    fileUrl = [fileUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
+    _playerFrame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
+    _wmPlayer = [[WMPlayer alloc] initWithFrame:_playerFrame];
+    WMPlayerModel *playModel = [[WMPlayerModel alloc] init];
+    playModel.videoURL = [NSURL URLWithString:fileUrl];
+    _wmPlayer.playerModel = playModel;
+    _wmPlayer.delegate = self;
+    _bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
+    _bgView.backgroundColor = [UIColor blackColor];
+    [[UIApplication sharedApplication].keyWindow addSubview:_bgView];
+    [[UIApplication sharedApplication].keyWindow addSubview:_wmPlayer];
+    [[UIApplication sharedApplication].keyWindow bringSubviewToFront:_wmPlayer];
+    
+    [_wmPlayer play];
+}
+
+- (void)wmplayer:(WMPlayer *)wmplayer clickedCloseButton:(UIButton *)backBtn {
+    [wmplayer removePlayer];
+    [_bgView removeFromSuperview];
+    [self setNeedsStatusBarAppearanceUpdate];
+}
+
+- (void)wmplayer:(WMPlayer *)wmplayer clickedFullScreenButton:(UIButton *)fullScreenBtn {
+    self.isRatation = !self.isRatation;
+    
+    if (self.isRatation) {
+        [wmplayer removeFromSuperview];
+        [UIView animateWithDuration:1.0f animations:^{
+            wmplayer.transform = CGAffineTransformMakeRotation(M_PI_2);
+            
+        } completion:^(BOOL finished) {
+            wmplayer.frame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
+            [[UIApplication sharedApplication].keyWindow addSubview:wmplayer];
+            [[UIApplication sharedApplication].keyWindow bringSubviewToFront:wmplayer];
+        }];
+    }
+    else {
+        [wmplayer removeFromSuperview];
+        
+        [UIView animateWithDuration:1.0f animations:^{
+            //        复原
+            wmplayer.transform = CGAffineTransformIdentity;
+            
+        } completion:^(BOOL finished) {
+            wmplayer.frame = CGRectMake(0, iPhoneXSafeTopMargin, kScreenWidth, kScreenHeight - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin);
+            [[UIApplication sharedApplication].keyWindow addSubview:wmplayer];
+            [[UIApplication sharedApplication].keyWindow bringSubviewToFront:wmplayer];
+        }];
+    }
+}
+
+- (void)bottomButtonAction {
+    // 判断
+    if ([self.homeworkModel.courseStatus isEqualToString:@"COMPLETE"]) { // 判断是否能提交作业
+        if (self.fileArray.count == 0 || self.homeworkModel.reviewHomework == 1 || self.homeworkModel.decorateHomework == 0) {
+            return;
+        }
+        else { // 提交作业
+            [self submitHomeworkAction];
+        }
+    }
+    else {
+        [self tryJoinRoom];
+    }
+}
+
+- (void)submitHomeworkAction {
+    if (self.isModify == NO) {
+        [self MBPShow:@"请先选择视频文件"];
+        return;
+    }
+    if (self.fileArray.count == 0) {
+        [self MBPShow:@"请选择作业视频"];
+        return;
+    }
+    NSString *attachment = [self.fileArray componentsJoinedByString:@","];
+    [self showhud];
+    [KSNetworkingManager homeSubmitAction:KS_POST courseScheduleId:self.courseId attachment:attachment success:^(NSDictionary * _Nonnull dic) {
+        [self removehub];
+        if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
+            [self MBPShow:@"作业提交成功"];
+            [self requestCourseInfoMessage];
+            self.isModify = NO;
+        }
+        else {
+            [self MBPShow:MESSAGEKEY];
+        }
+    } faliure:^(NSError * _Nonnull error) {
+        [self removehub];
+    }];
+}
+
+#pragma mark --- lazying
+
+- (OnlineClassManager *)classManager {
+    if (!_classManager) {
+        _classManager = [[OnlineClassManager alloc] init];
+    }
+    return _classManager;
+}
+
+- (AccompanyDetailBottomView *)bottomView {
+    if (!_bottomView) {
+        _bottomView = [AccompanyDetailBottomView shareInstance];
+        _bottomView.frame = CGRectMake(0, 0, kScreenWidth, 70);
+        MJWeakSelf;
+        [_bottomView sureAction:^{
+            [weakSelf bottomButtonAction];
+        }];
+    }
+    return _bottomView;
+}
+- (UITableView *)tableView {
+    if (!_tableView) {
+        _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
+        _tableView.backgroundColor = [UIColor clearColor];
+        _tableView.delegate = self;
+        _tableView.dataSource = self;
+        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+        _tableView.showsHorizontalScrollIndicator = NO;
+        _tableView.showsVerticalScrollIndicator = NO;
+        _tableView.rowHeight = UITableViewAutomaticDimension;
+        _tableView.estimatedRowHeight = 136.0f;
+        [_tableView registerNib:[UINib nibWithNibName:@"MusicRoomCourseInfoCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MusicRoomCourseInfoCell"];
+        [_tableView registerNib:[UINib nibWithNibName:@"AccompanyArrangeCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"AccompanyArrangeCell"];
+        [_tableView registerNib:[UINib nibWithNibName:@"AccompanyHomeworkCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"AccompanyHomeworkCell"];
+        [_tableView registerNib:[UINib nibWithNibName:@"AccompanyRemarkCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"AccompanyRemarkCell"];
+        _tableView.tableFooterView = self.bottomView;
+        
+    }
+    return _tableView;
+}
+- (void)hudTipWillShow:(BOOL)willShow{
+    if (willShow) {
+        [self resignFirstResponder];
+        UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
+        if (!_HUD) {
+            _HUD = [MBProgressHUD showHUDAddedTo:keyWindow animated:YES];
+            _HUD.removeFromSuperViewOnHide = YES;
+            _HUD.mode = MBProgressHUDModeDeterminateHorizontalBar;
+            _HUD.label.text = @"正在上传视频文件...";
+            _HUD.contentColor = [UIColor whiteColor];
+            _HUD.bezelView.style = MBProgressHUDBackgroundStyleSolidColor;
+            _HUD.bezelView.backgroundColor = [UIColor colorWithHexString:@"#000000" alpha:0.8];
+        }else{
+            _HUD.progress = 0;
+            [keyWindow addSubview:_HUD];
+            [_HUD showAnimated:YES];
+        }
+    }else{
+        [_HUD hideAnimated:YES];
+    }
+}
+
+
+
+- (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) {
+        [self MBPShow:@"该课程已结束"];
+    }
+    else {
+        NSString *tipsString = [NSString stringWithFormat:@"课程还未开始,请在上课前%zd分钟进入", self.joinRoomBeforeTime];
+        [self MBPShow:tipsString];
+    }
+}
+
+// 加入房间
+- (void)joinClassRoom {
+    // 加入房间前判断摄像头和麦克风逻辑
+    PREMISSIONTYPE micEnable = [RecordCheckManager checkPermissionShowAlert:NO showInView:nil];
+    PREMISSIONTYPE cameraEnable = [RecordCheckManager checkCameraPremissionAvaiable:NO showInView:nil];
+    if (micEnable == PREMISSIONTYPE_YES && cameraEnable == PREMISSIONTYPE_YES) {
+        // 进入教室
+        // 判断是否进行课前检测
+        [self.classManager joinRoomWithId:self.courseId subjectName:self.homeworkModel.subjectName classEndTime:self.homeworkModel.endTime inViewController:self];
+    }
+    else {
+        if (micEnable == PREMISSIONTYPE_NO && cameraEnable == PREMISSIONTYPE_NO) { // 如果麦克风权限和摄像头权限都没有
+            [self showAlertWithMessage:@"请开启相机和麦克风访问权限" type:CHECKDEVICETYPE_BOTH];
+        }
+        else if (micEnable == PREMISSIONTYPE_NO) { // 如果没有麦克风权限
+            [self showAlertWithMessage:@"请开启麦克风访问权限" type:CHECKDEVICETYPE_MIC];
+        }
+        else if (cameraEnable == PREMISSIONTYPE_NO) { // 如果没有摄像头权限
+            [self showAlertWithMessage:@"请开启相机访问权限" type:CHECKDEVICETYPE_CAMREA];
+        }
+    }
+}
+
+- (void)showAlertWithMessage:(NSString *)message type:(CHECKDEVICETYPE)deviceType {
+    [KSPremissionAlert shareInstanceDisplayImage:deviceType message:message showInView:self.view cancel:^{
+        
+    } confirm:^{
+        [self openSettingView];
+    }];
+    
+}
+
+- (void)openSettingView {
+    if (@available(iOS 10, *)) {
+        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
+    } else {
+        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
+    }
+}
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+@end

+ 27 - 0
KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.h

@@ -0,0 +1,27 @@
+//
+//  MusicRoomCourseInfoCell.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/6/27.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void(^MusicRoomChatCallback)(void);
+
+
+@interface MusicRoomCourseInfoCell : UITableViewCell
+
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+
+@property (nonatomic, assign) BOOL hideChatButton;
+
+- (void)configWithStartTime:(NSString *)beginTime endTime:(NSString *)endTime courseName:(NSString *)courseName chatGroupId:(NSString *)chatGroupId courseSubject:(NSString *)courseSubject;
+
+- (void)chatCalkback:(MusicRoomChatCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 82 - 0
KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.m

@@ -0,0 +1,82 @@
+//
+//  MusicRoomCourseInfoCell.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/6/27.
+//
+
+#import "MusicRoomCourseInfoCell.h"
+
+@interface MusicRoomCourseInfoCell ()
+
+@property (weak, nonatomic) IBOutlet UILabel *courseTime;
+@property (weak, nonatomic) IBOutlet UILabel *courseName;
+@property (weak, nonatomic) IBOutlet UILabel *courseSubject;
+@property (weak, nonatomic) IBOutlet UIView *subjectView;
+@property (weak, nonatomic) IBOutlet UILabel *countLabel;
+
+@property (weak, nonatomic) IBOutlet UIButton *chatButton;
+
+@property (nonatomic, strong) NSString *targetId;
+
+@property (nonatomic, copy) MusicRoomChatCallback callback;
+
+@end
+
+@implementation MusicRoomCourseInfoCell
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    self.selectionStyle = UITableViewCellSelectionStyleNone;
+}
+
+
+- (void)configWithStartTime:(NSString *)beginTime endTime:(NSString *)endTime courseName:(NSString *)courseName chatGroupId:(NSString *)chatGroupId courseSubject:(NSString *)courseSubject {
+    // time
+    NSDateFormatter *formatter = [NSObject getDateformatter];
+    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
+    NSDate *startDate = [formatter dateFromString:beginTime];
+    NSDate *endDate = [formatter dateFromString:endTime];
+    [formatter setDateFormat:@"yyyy/MM/dd HH:mm"];
+    NSString *lessonBegin = [formatter stringFromDate:startDate];
+    [formatter setDateFormat:@"HH:mm"];
+    NSString *lessonEnd = [formatter stringFromDate:endDate];
+    self.courseTime.text = [NSString stringWithFormat:@"%@~%@",[NSString returnNoNullStringWithString:lessonBegin],[NSString returnNoNullStringWithString:lessonEnd]];
+    self.courseName.text = [NSString returnNoNullStringWithString:courseName];
+    if (![NSString isEmptyString:courseSubject]) {
+        self.subjectView.hidden = NO;
+        self.courseSubject.text = courseSubject;
+    }
+    else {
+        self.subjectView.hidden = YES;
+    }
+}
+
+- (void)setHideChatButton:(BOOL)hideChatButton {
+    _hideChatButton = hideChatButton;
+    if (hideChatButton) {
+        self.chatButton.hidden = YES;
+        self.chatButton.userInteractionEnabled = NO;
+    }
+    else {
+        self.chatButton.hidden = NO;
+        self.chatButton.userInteractionEnabled = YES;
+    }
+}
+
+
+- (void)chatCalkback:(MusicRoomChatCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+}
+
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+@end

+ 184 - 0
KulexiuForStudent/KulexiuForStudent/Module/Course/MusicRoom/View/MusicRoomCourseInfoCell.xib

@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <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="148" id="KGk-i7-Jjw" customClass="MusicRoomCourseInfoCell">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="148"/>
+            <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="148"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lZc-0i-RlV">
+                        <rect key="frame" x="14" y="10" width="292" height="126"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="course_time" translatesAutoresizingMaskIntoConstraints="NO" id="NaF-iy-iW5">
+                                <rect key="frame" x="11" y="12" width="16" height="16"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="16" id="L9r-Gs-c84"/>
+                                    <constraint firstAttribute="height" constant="16" id="xRM-dX-EXd"/>
+                                </constraints>
+                            </imageView>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="AIK-oQ-G54">
+                                <rect key="frame" x="10" y="38" 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="fiS-aA-9mc"/>
+                                </constraints>
+                            </view>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5TG-5t-3Vw">
+                                <rect key="frame" x="231" y="20" width="50" height="0.0"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="50" id="yzq-8h-DAm"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
+                                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                <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="DZc-wF-kiD">
+                                <rect key="frame" x="34" y="11" width="0.0" height="18"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="30U-f6-m6b"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                <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="09N-Zc-juN">
+                                <rect key="frame" x="68" y="51" width="98" height="28"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="28" id="0sK-eg-OVB"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
+                                <color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oPF-d8-FLk">
+                                <rect key="frame" x="68" y="79" width="10" height="20"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kbx-pS-TGd">
+                                        <rect key="frame" x="5" y="0.0" width="0.0" height="20"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="11"/>
+                                        <color key="textColor" red="1" green="0.54901960780000003" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="1" green="0.94509803920000002" blue="0.87058823529999996" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstItem="kbx-pS-TGd" firstAttribute="leading" secondItem="oPF-d8-FLk" secondAttribute="leading" constant="5" id="3Om-TX-Ngj"/>
+                                    <constraint firstAttribute="height" constant="20" id="Sio-ne-hD4"/>
+                                    <constraint firstAttribute="trailing" secondItem="kbx-pS-TGd" secondAttribute="trailing" constant="5" id="XAn-b2-9jp"/>
+                                    <constraint firstAttribute="bottom" secondItem="kbx-pS-TGd" secondAttribute="bottom" id="ZGw-ui-jdM"/>
+                                    <constraint firstItem="kbx-pS-TGd" firstAttribute="top" secondItem="oPF-d8-FLk" secondAttribute="top" id="e9A-zk-12Y"/>
+                                </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" image="course_musicRoom" translatesAutoresizingMaskIntoConstraints="NO" id="qgw-qJ-GKe">
+                                <rect key="frame" x="11" y="53" width="47" height="51"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="51" id="6Lb-fR-aUr"/>
+                                    <constraint firstAttribute="width" constant="47" id="eIR-Ch-GVU"/>
+                                </constraints>
+                            </imageView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WC4-RO-cvp">
+                                <rect key="frame" x="166" y="45" width="40" height="40"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="40" id="8bd-oD-mGh"/>
+                                    <constraint firstAttribute="height" constant="40" id="rtv-FP-E11"/>
+                                </constraints>
+                                <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                                <state key="normal" image="course_chat"/>
+                            </button>
+                            <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Nc9-wd-2bK">
+                                <rect key="frame" x="86" y="83.5" width="1" height="11"/>
+                                <color key="backgroundColor" red="0.82745098039999998" green="0.82745098039999998" blue="0.82745098039999998" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="1" id="Rg2-Wr-nWo"/>
+                                    <constraint firstAttribute="height" constant="11" id="avf-90-4F7"/>
+                                </constraints>
+                            </view>
+                            <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="6人" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jid-Tm-C6f">
+                                <rect key="frame" x="95" y="82" width="20" height="14.5"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                <color key="textColor" red="0.41568627450000001" green="0.41568627450000001" blue="0.41568627450000001" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="WC4-RO-cvp" secondAttribute="trailing" constant="10" id="0E1-B1-wW8"/>
+                            <constraint firstAttribute="trailing" secondItem="5TG-5t-3Vw" secondAttribute="trailing" constant="11" id="1Wd-Tp-p7M"/>
+                            <constraint firstAttribute="trailing" secondItem="AIK-oQ-G54" secondAttribute="trailing" constant="10" id="8zL-c6-KGD"/>
+                            <constraint firstItem="Nc9-wd-2bK" firstAttribute="leading" secondItem="oPF-d8-FLk" secondAttribute="trailing" constant="8" id="BOa-k6-wQe"/>
+                            <constraint firstItem="oPF-d8-FLk" firstAttribute="top" secondItem="09N-Zc-juN" secondAttribute="bottom" id="BzL-ZV-YYc"/>
+                            <constraint firstItem="09N-Zc-juN" firstAttribute="top" secondItem="qgw-qJ-GKe" secondAttribute="top" constant="-2" id="K2w-tb-k6a"/>
+                            <constraint firstItem="NaF-iy-iW5" firstAttribute="top" secondItem="lZc-0i-RlV" secondAttribute="top" constant="12" id="MOg-56-mCo"/>
+                            <constraint firstItem="DZc-wF-kiD" firstAttribute="centerY" secondItem="NaF-iy-iW5" secondAttribute="centerY" id="MWw-Pm-PJF"/>
+                            <constraint firstItem="Jid-Tm-C6f" firstAttribute="leading" secondItem="Nc9-wd-2bK" secondAttribute="trailing" constant="8" id="NCl-z1-WpE"/>
+                            <constraint firstAttribute="bottom" secondItem="qgw-qJ-GKe" secondAttribute="bottom" constant="22" id="SSA-Vy-TQu"/>
+                            <constraint firstItem="09N-Zc-juN" firstAttribute="leading" secondItem="qgw-qJ-GKe" secondAttribute="trailing" constant="10" id="T34-Yi-fep"/>
+                            <constraint firstItem="WC4-RO-cvp" firstAttribute="leading" secondItem="09N-Zc-juN" secondAttribute="trailing" id="U8W-aJ-XUT"/>
+                            <constraint firstItem="WC4-RO-cvp" firstAttribute="centerY" secondItem="09N-Zc-juN" secondAttribute="centerY" id="Zg5-sn-kjb"/>
+                            <constraint firstItem="NaF-iy-iW5" firstAttribute="leading" secondItem="lZc-0i-RlV" secondAttribute="leading" constant="11" id="ar8-fs-QfO"/>
+                            <constraint firstItem="oPF-d8-FLk" firstAttribute="leading" secondItem="09N-Zc-juN" secondAttribute="leading" id="bu6-OM-pMD"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Jid-Tm-C6f" secondAttribute="trailing" constant="10" id="ff3-GG-IIS"/>
+                            <constraint firstItem="DZc-wF-kiD" firstAttribute="leading" secondItem="NaF-iy-iW5" secondAttribute="trailing" constant="7" id="g44-RU-uqQ"/>
+                            <constraint firstItem="qgw-qJ-GKe" firstAttribute="top" secondItem="AIK-oQ-G54" secondAttribute="bottom" constant="14" id="huZ-8L-qxR"/>
+                            <constraint firstItem="5TG-5t-3Vw" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="DZc-wF-kiD" secondAttribute="trailing" constant="10" id="i68-vw-1Eq"/>
+                            <constraint firstItem="AIK-oQ-G54" firstAttribute="top" secondItem="NaF-iy-iW5" secondAttribute="bottom" constant="10" id="lRY-Po-XuH"/>
+                            <constraint firstItem="qgw-qJ-GKe" firstAttribute="leading" secondItem="lZc-0i-RlV" secondAttribute="leading" constant="11" id="nuC-M7-gbM"/>
+                            <constraint firstItem="5TG-5t-3Vw" firstAttribute="centerY" secondItem="DZc-wF-kiD" secondAttribute="centerY" id="oMD-LX-U73"/>
+                            <constraint firstItem="AIK-oQ-G54" firstAttribute="leading" secondItem="lZc-0i-RlV" secondAttribute="leading" constant="10" id="uqQ-LW-t3l"/>
+                            <constraint firstItem="Nc9-wd-2bK" firstAttribute="centerY" secondItem="oPF-d8-FLk" secondAttribute="centerY" id="uzp-sj-YUu"/>
+                            <constraint firstItem="Jid-Tm-C6f" firstAttribute="centerY" secondItem="Nc9-wd-2bK" secondAttribute="centerY" id="zjj-WE-oJD"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="10"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="trailing" secondItem="lZc-0i-RlV" secondAttribute="trailing" constant="14" id="3Ae-xb-ufC"/>
+                    <constraint firstAttribute="bottom" secondItem="lZc-0i-RlV" secondAttribute="bottom" constant="12" id="CEa-4n-D2U"/>
+                    <constraint firstItem="lZc-0i-RlV" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="WRM-7h-DC7"/>
+                    <constraint firstItem="lZc-0i-RlV" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="nqf-oV-7Tu"/>
+                </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="chatButton" destination="WC4-RO-cvp" id="5WL-cb-3wc"/>
+                <outlet property="countLabel" destination="Jid-Tm-C6f" id="TsY-VH-vS3"/>
+                <outlet property="courseName" destination="09N-Zc-juN" id="X1d-qP-Lz2"/>
+                <outlet property="courseSubject" destination="kbx-pS-TGd" id="bmc-zg-wR2"/>
+                <outlet property="courseTime" destination="DZc-wF-kiD" id="T4x-I1-8LT"/>
+                <outlet property="statusLabel" destination="5TG-5t-3Vw" id="kIA-0J-Nom"/>
+                <outlet property="subjectView" destination="oPF-d8-FLk" id="Zz3-Ne-2ix"/>
+            </connections>
+            <point key="canvasLocation" x="131.8840579710145" y="118.19196428571428"/>
+        </tableViewCell>
+    </objects>
+    <resources>
+        <image name="course_chat" width="19" height="18"/>
+        <image name="course_musicRoom" width="47" height="51"/>
+        <image name="course_time" width="16" height="16"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 29 - 9
KulexiuForStudent/KulexiuForStudent/Module/Course/View/MusicRoomCourseCell.m

@@ -7,10 +7,10 @@
 
 #import "MusicRoomCourseCell.h"
 #import "TableCourseModel.h"
+#import "MusicRoomListModel.h"
 
 @interface MusicRoomCourseCell ()
 
-@property (weak, nonatomic) IBOutlet UILabel *courseDesc;
 
 @property (weak, nonatomic) IBOutlet UILabel *courseTimeLabel;
 @property (weak, nonatomic) IBOutlet UILabel *courseName;
@@ -18,7 +18,6 @@
 @property (weak, nonatomic) IBOutlet UILabel *subjectName;
 @property (weak, nonatomic) IBOutlet UIButton *statusButton;
 
-@property (weak, nonatomic) IBOutlet UIView *colorView;
 
 @property (nonatomic, strong) NSString *targetId;
 
@@ -32,13 +31,6 @@
     [super awakeFromNib];
     // Initialization code
     self.selectionStyle = UITableViewCellSelectionStyleNone;
-    CAGradientLayer * gradientLayer = [CAGradientLayer layer];
-    gradientLayer.colors = @[(__bridge id)HexRGB(0xFFBC90).CGColor,(__bridge id)HexRGB(0xFF7021).CGColor];
-    gradientLayer.startPoint = CGPointMake(0, 0);
-    gradientLayer.endPoint = CGPointMake(0, 1);
-    gradientLayer.frame = CGRectMake(0, 0, 42, 42);
-    [self.colorView.layer addSublayer:gradientLayer];
-    [self.colorView bringSubviewToFront:self.courseDesc];
 }
 
 - (void)configWithSource:(id)source callback:(MusicRoomChatAction)callback {
@@ -73,6 +65,34 @@
             self.statusButton.layer.borderColor = HexRGB(0xe5e5e5).CGColor;
         }
     }
+    else if ([source isKindOfClass:[MusicRoomListModel class]]) {
+        MusicRoomListModel *model = (MusicRoomListModel *)source;
+        self.targetId = model.imGroupId;
+        // time
+        [self evaluateTimeLabelWithBeginTime:model.startTime endTime:model.endTime];
+        self.courseName.text = [NSString returnNoNullStringWithString:model.courseGroupName];
+        self.subjectName.text = [NSString returnNoNullStringWithString:model.subjectName];
+        
+        if ([model.status isEqualToString:@"NOT_START"]) {
+            [self.statusButton setTitle:@"未开始" forState:UIControlStateNormal];
+            self.statusButton.backgroundColor = [UIColor whiteColor];
+            [self.statusButton setTitleColor:HexRGB(0xFF802C) forState:UIControlStateNormal];
+            self.statusButton.layer.borderColor = HexRGB(0xFF802C).CGColor;
+        }
+        else if ([model.status isEqualToString:@"ING"]) {
+            [self.statusButton setTitle:@"进行中" forState:UIControlStateNormal];
+            self.statusButton.backgroundColor = THEMECOLOR;
+            [self.statusButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+            self.statusButton.layer.borderColor = THEMECOLOR.CGColor;
+            
+        }
+        else if ([model.status isEqualToString:@"COMPLETE"]) {
+            [self.statusButton setTitle:@"已结束" forState:UIControlStateNormal];
+            self.statusButton.backgroundColor = [UIColor whiteColor];
+            [self.statusButton setTitleColor:HexRGB(0x999999) forState:UIControlStateNormal];
+            self.statusButton.layer.borderColor = HexRGB(0xe5e5e5).CGColor;
+        }
+    }
 }
 
 - (void)evaluateTimeLabelWithBeginTime:(NSString *)beginTime endTime:(NSString *)endTime {

+ 13 - 38
KulexiuForStudent/KulexiuForStudent/Module/Course/View/MusicRoomCourseCell.xib

@@ -56,31 +56,8 @@
                                     <constraint firstAttribute="height" constant="1" id="NEY-Lz-eiH"/>
                                 </constraints>
                             </view>
-                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4jM-hU-dts">
-                                <rect key="frame" x="12" y="56" width="42" height="42"/>
-                                <subviews>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="小课" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="n6Q-Lb-t2R">
-                                        <rect key="frame" x="6.5" y="12.5" width="29" height="17"/>
-                                        <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
-                                        <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
-                                </subviews>
-                                <color key="backgroundColor" systemColor="systemRedColor"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="42" id="Dzn-HZ-cek"/>
-                                    <constraint firstItem="n6Q-Lb-t2R" firstAttribute="centerY" secondItem="4jM-hU-dts" secondAttribute="centerY" id="Fp2-D0-SRA"/>
-                                    <constraint firstItem="n6Q-Lb-t2R" firstAttribute="centerX" secondItem="4jM-hU-dts" secondAttribute="centerX" id="NuK-i3-hEL"/>
-                                    <constraint firstAttribute="width" constant="42" id="w3s-jj-a5q"/>
-                                </constraints>
-                                <userDefinedRuntimeAttributes>
-                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                        <real key="value" value="21"/>
-                                    </userDefinedRuntimeAttribute>
-                                </userDefinedRuntimeAttributes>
-                            </view>
                             <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="单簧管第一期" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l2B-EY-GWY">
-                                <rect key="frame" x="66" y="56" width="98" height="28"/>
+                                <rect key="frame" x="68" y="53" width="98" height="28"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="28" id="kAd-0f-k5x"/>
                                 </constraints>
@@ -89,7 +66,7 @@
                                 <nil key="highlightedColor"/>
                             </label>
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Dys-CR-rsC">
-                                <rect key="frame" x="66" y="84" width="44" height="20"/>
+                                <rect key="frame" x="68" y="81" width="44" height="20"/>
                                 <subviews>
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="单簧管" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TPd-JA-v98">
                                         <rect key="frame" x="5" y="0.0" width="34" height="20"/>
@@ -113,7 +90,7 @@
                                 </userDefinedRuntimeAttributes>
                             </view>
                             <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Vxw-2k-cqR">
-                                <rect key="frame" x="325" y="63" width="70" height="28"/>
+                                <rect key="frame" x="325" y="66.5" width="70" height="28"/>
                                 <color key="backgroundColor" red="0.1764705882" green="0.78039215689999997" blue="0.66666666669999997" alpha="1" colorSpace="calibratedRGB"/>
                                 <constraints>
                                     <constraint firstAttribute="width" constant="70" id="e5h-nv-3mR"/>
@@ -134,28 +111,30 @@
                                     </userDefinedRuntimeAttribute>
                                 </userDefinedRuntimeAttributes>
                             </button>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="course_musicRoom" translatesAutoresizingMaskIntoConstraints="NO" id="KUE-40-5Jn">
+                                <rect key="frame" x="11" y="55" width="47" height="51"/>
+                            </imageView>
                         </subviews>
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <constraints>
-                            <constraint firstItem="4jM-hU-dts" firstAttribute="leading" secondItem="Wl9-sn-VK0" secondAttribute="leading" constant="12" id="55F-l8-Qg1"/>
-                            <constraint firstItem="4jM-hU-dts" firstAttribute="top" secondItem="89l-Qb-VVR" secondAttribute="bottom" constant="15" id="5TE-2w-8xg"/>
                             <constraint firstItem="VjP-WA-4SG" firstAttribute="leading" secondItem="Wl9-sn-VK0" secondAttribute="leading" constant="12" id="76s-eU-Ril"/>
-                            <constraint firstItem="l2B-EY-GWY" firstAttribute="leading" secondItem="4jM-hU-dts" secondAttribute="trailing" constant="12" id="8wP-id-bji"/>
                             <constraint firstItem="Dys-CR-rsC" firstAttribute="top" secondItem="l2B-EY-GWY" secondAttribute="bottom" id="9Pu-wW-GUr"/>
                             <constraint firstItem="VjP-WA-4SG" firstAttribute="top" secondItem="Wl9-sn-VK0" secondAttribute="top" constant="12" id="B95-QO-f7C"/>
                             <constraint firstItem="UxS-Xs-zTk" firstAttribute="leading" secondItem="VjP-WA-4SG" secondAttribute="trailing" constant="6" id="Ct9-78-SuQ"/>
+                            <constraint firstItem="KUE-40-5Jn" firstAttribute="leading" secondItem="Wl9-sn-VK0" secondAttribute="leading" constant="11" id="Gbj-GO-lRf"/>
                             <constraint firstAttribute="trailing" secondItem="89l-Qb-VVR" secondAttribute="trailing" constant="10" id="J29-HZ-el6"/>
                             <constraint firstAttribute="trailing" secondItem="t3h-kH-4md" secondAttribute="trailing" constant="10" id="Mvo-kN-6G0"/>
                             <constraint firstItem="Vxw-2k-cqR" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="l2B-EY-GWY" secondAttribute="trailing" constant="10" id="PSq-3m-yXX"/>
                             <constraint firstItem="t3h-kH-4md" firstAttribute="top" secondItem="Wl9-sn-VK0" secondAttribute="top" id="UrD-2D-HXJ"/>
+                            <constraint firstItem="KUE-40-5Jn" firstAttribute="top" secondItem="89l-Qb-VVR" secondAttribute="bottom" constant="14" id="Wtf-un-EEq"/>
+                            <constraint firstItem="Vxw-2k-cqR" firstAttribute="centerY" secondItem="KUE-40-5Jn" secondAttribute="centerY" id="YTT-R1-nsh"/>
+                            <constraint firstItem="l2B-EY-GWY" firstAttribute="leading" secondItem="KUE-40-5Jn" secondAttribute="trailing" constant="10" id="cfy-Be-GKk"/>
                             <constraint firstItem="Dys-CR-rsC" firstAttribute="leading" secondItem="l2B-EY-GWY" secondAttribute="leading" id="h8r-WE-IEp"/>
                             <constraint firstItem="t3h-kH-4md" firstAttribute="leading" secondItem="UxS-Xs-zTk" secondAttribute="trailing" constant="10" id="jRb-6e-UMI"/>
-                            <constraint firstAttribute="bottom" secondItem="4jM-hU-dts" secondAttribute="bottom" constant="19" id="kBX-xJ-Bc3"/>
                             <constraint firstItem="89l-Qb-VVR" firstAttribute="leading" secondItem="Wl9-sn-VK0" secondAttribute="leading" constant="10" id="pgO-Fi-Mwz"/>
-                            <constraint firstItem="Vxw-2k-cqR" firstAttribute="centerY" secondItem="4jM-hU-dts" secondAttribute="centerY" id="pln-hz-8jR"/>
+                            <constraint firstItem="l2B-EY-GWY" firstAttribute="top" secondItem="KUE-40-5Jn" secondAttribute="top" constant="-2" id="v6g-OI-y76"/>
                             <constraint firstItem="UxS-Xs-zTk" firstAttribute="centerY" secondItem="VjP-WA-4SG" secondAttribute="centerY" id="vcI-Cy-0Bk"/>
                             <constraint firstAttribute="trailing" secondItem="Vxw-2k-cqR" secondAttribute="trailing" constant="12" id="xYc-E1-jA1"/>
-                            <constraint firstItem="l2B-EY-GWY" firstAttribute="top" secondItem="4jM-hU-dts" secondAttribute="top" id="yVe-vS-w5V"/>
                             <constraint firstItem="89l-Qb-VVR" firstAttribute="top" secondItem="t3h-kH-4md" secondAttribute="bottom" id="zDK-PZ-xfH"/>
                         </constraints>
                         <userDefinedRuntimeAttributes>
@@ -175,24 +154,20 @@
             <viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
             <connections>
-                <outlet property="colorView" destination="4jM-hU-dts" id="Vf2-g7-lUE"/>
-                <outlet property="courseDesc" destination="n6Q-Lb-t2R" id="6EB-Qw-D3R"/>
                 <outlet property="courseName" destination="l2B-EY-GWY" id="D00-Cj-zrr"/>
                 <outlet property="courseTimeLabel" destination="UxS-Xs-zTk" id="dkq-PI-dck"/>
                 <outlet property="statusButton" destination="Vxw-2k-cqR" id="0Ra-cW-84Y"/>
                 <outlet property="subjectName" destination="TPd-JA-v98" id="HaG-Uj-2h3"/>
             </connections>
-            <point key="canvasLocation" x="215.21739130434784" y="107.8125"/>
+            <point key="canvasLocation" x="215.21739130434784" y="107.47767857142857"/>
         </tableViewCell>
     </objects>
     <resources>
         <image name="course_chat" width="19" height="18"/>
+        <image name="course_musicRoom" width="47" height="51"/>
         <image name="course_time" width="16" height="16"/>
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
         </systemColor>
-        <systemColor name="systemRedColor">
-            <color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-        </systemColor>
     </resources>
 </document>

+ 10 - 2
KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m

@@ -56,6 +56,7 @@
 #import "PublicNoticeView.h"
 #import "SDCycleScrollView.h"
 #import "NoticeSourceModel.h"
+#import "MusicRoomDetailViewController.h"
 
 #define BUTTONWIDTH (65)
 #define BUTTONHEIGHT (80)
@@ -1029,9 +1030,16 @@
         detailVC.teacherId = courseModel.teacherId;
         [self.navigationController pushViewController:detailVC animated:YES];
     }
-    else { // 直播课详情
+    else if (type == COURSETYPE_MUSICROOM) { // 琴房课列表
+        MusicRoomDetailViewController *detailVC = [[MusicRoomDetailViewController alloc] init];
+        detailVC.courseId = courseModel.courseId;
+        detailVC.courseGroupId = courseModel.courseGroupId;
+        detailVC.teacherId = courseModel.teacherId;
+        [self.navigationController pushViewController:detailVC animated:YES];
+    }
+    else { // 直播课详情进教室
         KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
-        NSString *url = [NSString stringWithFormat:@"%@%@%@", WEBHOST, @"/#/liveDetail?groupId=",courseModel.courseGroupId];
+        NSString *url = [NSString stringWithFormat:@"%@%@%@", WEBHOST, @"/#/liveDetail?joinRoom=1&groupId=",courseModel.courseGroupId];
         ctrl.url = url;
         [self.navigationController pushViewController:ctrl animated:YES];
     }

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Module/Home/View/HomeCourseTipsView.h

@@ -11,6 +11,7 @@
 typedef NS_ENUM(NSInteger, COURSETYPE) {
     COURSETYPE_ACCOMPANY, // 陪练课
     COURSETYPE_LIVE,      // 直播课
+    COURSETYPE_MUSICROOM, // 琴房课
 };
 
 typedef void(^HomeCourseCallback)(COURSETYPE type, RecentCourseModel * _Nonnull courseModel);

+ 11 - 1
KulexiuForStudent/KulexiuForStudent/Module/Home/View/HomeCourseTipsView.m

@@ -56,7 +56,17 @@
 
 - (IBAction)joinRoomAction:(id)sender {
     if (self.callback) {
-        COURSETYPE type = [self.courseModel.courseType isEqualToString:@"LIVE"] ? COURSETYPE_LIVE : COURSETYPE_ACCOMPANY;
+        COURSETYPE type;
+        if ([self.courseModel.courseType isEqualToString:@"LIVE"]) {
+            type = COURSETYPE_LIVE;
+        }
+        else if ([self.courseModel.courseType isEqualToString:@"PIANO_ROOM_CLASS"]) {
+            type = COURSETYPE_MUSICROOM;
+        }
+        else {
+            type = COURSETYPE_ACCOMPANY;
+        }
+        
         self.callback(type, self.courseModel);
     }
 }

+ 3 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/Homework/Model/HomeworkDetailModel.h

@@ -38,6 +38,9 @@
 @property (nonatomic, strong) NSString *studentId;
 @property (nonatomic, strong) NSString *teacherId;
 
+@property (nonatomic, strong) NSString *courseName;
+@property (nonatomic, strong) NSString *imGroupId;
+
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
 - (instancetype)initWithDictionary:(NSDictionary *)dict;
 - (NSDictionary *)dictionaryRepresentation;

+ 2 - 2
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Controller/MyCourseViewController.m

@@ -30,7 +30,7 @@
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     [self allocTitle:@"我的课程"];
-    self.titles = @[@"陪练课",@"直播课",@"视频课"];
+    self.titles = @[@"陪练课",@"直播课",@"视频课",@"琴房课"];
     [self configUI];
 }
 
@@ -197,7 +197,7 @@
 
 - (NSMutableArray *)listViewArray {
     if (!_listViewArray) {
-        _listViewArray = [NSMutableArray arrayWithArray:@[@"",@"",@""]];
+        _listViewArray = [NSMutableArray arrayWithArray:@[@"",@"",@"",@""]];
     }
     return _listViewArray;
 }

+ 33 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/MusicRoomListModel.h

@@ -0,0 +1,33 @@
+//
+//  MusicRoomListModel.h
+//
+//  Created by Steven  on 2022/6/27
+//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+
+@interface MusicRoomListModel : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, strong) NSString *courseGroupId;
+@property (nonatomic, assign) double studentSign;
+@property (nonatomic, strong) NSString *imGroupId;
+@property (nonatomic, strong) NSString *subjectId;
+@property (nonatomic, strong) NSString *teacherId;
+@property (nonatomic, strong) NSString *courseId;
+@property (nonatomic, strong) NSString *avatar;
+@property (nonatomic, strong) NSString *teacherName;
+@property (nonatomic, strong) NSString *endTime;
+@property (nonatomic, strong) NSString *teacherRealName;
+@property (nonatomic, strong) NSString *subjectName;
+@property (nonatomic, strong) NSString *startTime;
+@property (nonatomic, strong) NSString *status;
+@property (nonatomic, strong) NSString *courseGroupName;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 190 - 0
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/Model/MusicRoomListModel.m

@@ -0,0 +1,190 @@
+//
+//  MusicRoomListModel.m
+//
+//  Created by Steven  on 2022/6/27
+//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//
+
+#import "MusicRoomListModel.h"
+
+
+NSString *const kMusicRoomListModelCourseGroupId = @"courseGroupId";
+NSString *const kMusicRoomListModelStudentSign = @"studentSign";
+NSString *const kMusicRoomListModelImGroupId = @"imGroupId";
+NSString *const kMusicRoomListModelSubjectId = @"subjectId";
+NSString *const kMusicRoomListModelTeacherId = @"teacherId";
+NSString *const kMusicRoomListModelCourseId = @"courseId";
+NSString *const kMusicRoomListModelAvatar = @"avatar";
+NSString *const kMusicRoomListModelTeacherName = @"teacherName";
+NSString *const kMusicRoomListModelEndTime = @"endTime";
+NSString *const kMusicRoomListModelTeacherRealName = @"teacherRealName";
+NSString *const kMusicRoomListModelSubjectName = @"subjectName";
+NSString *const kMusicRoomListModelStartTime = @"startTime";
+NSString *const kMusicRoomListModelStatus = @"status";
+NSString *const kMusicRoomListModelCourseGroupName = @"courseGroupName";
+
+
+@interface MusicRoomListModel ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation MusicRoomListModel
+
+@synthesize courseGroupId = _courseGroupId;
+@synthesize studentSign = _studentSign;
+@synthesize imGroupId = _imGroupId;
+@synthesize subjectId = _subjectId;
+@synthesize teacherId = _teacherId;
+@synthesize courseId = _courseId;
+@synthesize avatar = _avatar;
+@synthesize teacherName = _teacherName;
+@synthesize endTime = _endTime;
+@synthesize teacherRealName = _teacherRealName;
+@synthesize subjectName = _subjectName;
+@synthesize startTime = _startTime;
+@synthesize status = _status;
+@synthesize courseGroupName = _courseGroupName;
+
+
++ (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.courseGroupId = [self objectOrNilForKey:kMusicRoomListModelCourseGroupId fromDictionary:dict];
+            self.studentSign = [[self objectOrNilForKey:kMusicRoomListModelStudentSign fromDictionary:dict] doubleValue];
+            self.imGroupId = [self objectOrNilForKey:kMusicRoomListModelImGroupId fromDictionary:dict];
+            self.subjectId = [self objectOrNilForKey:kMusicRoomListModelSubjectId fromDictionary:dict];
+            self.teacherId = [self objectOrNilForKey:kMusicRoomListModelTeacherId fromDictionary:dict];
+            self.courseId = [self objectOrNilForKey:kMusicRoomListModelCourseId fromDictionary:dict];
+            self.avatar = [self objectOrNilForKey:kMusicRoomListModelAvatar fromDictionary:dict];
+            self.teacherName = [self objectOrNilForKey:kMusicRoomListModelTeacherName fromDictionary:dict];
+            self.endTime = [self objectOrNilForKey:kMusicRoomListModelEndTime fromDictionary:dict];
+            self.teacherRealName = [self objectOrNilForKey:kMusicRoomListModelTeacherRealName fromDictionary:dict];
+            self.subjectName = [self objectOrNilForKey:kMusicRoomListModelSubjectName fromDictionary:dict];
+            self.startTime = [self objectOrNilForKey:kMusicRoomListModelStartTime fromDictionary:dict];
+            self.status = [self objectOrNilForKey:kMusicRoomListModelStatus fromDictionary:dict];
+            self.courseGroupName = [self objectOrNilForKey:kMusicRoomListModelCourseGroupName fromDictionary:dict];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.courseGroupId forKey:kMusicRoomListModelCourseGroupId];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.studentSign] forKey:kMusicRoomListModelStudentSign];
+    [mutableDict setValue:self.imGroupId forKey:kMusicRoomListModelImGroupId];
+    [mutableDict setValue:self.subjectId forKey:kMusicRoomListModelSubjectId];
+    [mutableDict setValue:self.teacherId forKey:kMusicRoomListModelTeacherId];
+    [mutableDict setValue:self.courseId forKey:kMusicRoomListModelCourseId];
+    [mutableDict setValue:self.avatar forKey:kMusicRoomListModelAvatar];
+    [mutableDict setValue:self.teacherName forKey:kMusicRoomListModelTeacherName];
+    [mutableDict setValue:self.endTime forKey:kMusicRoomListModelEndTime];
+    [mutableDict setValue:self.teacherRealName forKey:kMusicRoomListModelTeacherRealName];
+    [mutableDict setValue:self.subjectName forKey:kMusicRoomListModelSubjectName];
+    [mutableDict setValue:self.startTime forKey:kMusicRoomListModelStartTime];
+    [mutableDict setValue:self.status forKey:kMusicRoomListModelStatus];
+    [mutableDict setValue:self.courseGroupName forKey:kMusicRoomListModelCourseGroupName];
+
+    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.courseGroupId = [aDecoder decodeObjectForKey:kMusicRoomListModelCourseGroupId];
+    self.studentSign = [aDecoder decodeDoubleForKey:kMusicRoomListModelStudentSign];
+    self.imGroupId = [aDecoder decodeObjectForKey:kMusicRoomListModelImGroupId];
+    self.subjectId = [aDecoder decodeObjectForKey:kMusicRoomListModelSubjectId];
+    self.teacherId = [aDecoder decodeObjectForKey:kMusicRoomListModelTeacherId];
+    self.courseId = [aDecoder decodeObjectForKey:kMusicRoomListModelCourseId];
+    self.avatar = [aDecoder decodeObjectForKey:kMusicRoomListModelAvatar];
+    self.teacherName = [aDecoder decodeObjectForKey:kMusicRoomListModelTeacherName];
+    self.endTime = [aDecoder decodeObjectForKey:kMusicRoomListModelEndTime];
+    self.teacherRealName = [aDecoder decodeObjectForKey:kMusicRoomListModelTeacherRealName];
+    self.subjectName = [aDecoder decodeObjectForKey:kMusicRoomListModelSubjectName];
+    self.startTime = [aDecoder decodeObjectForKey:kMusicRoomListModelStartTime];
+    self.status = [aDecoder decodeObjectForKey:kMusicRoomListModelStatus];
+    self.courseGroupName = [aDecoder decodeObjectForKey:kMusicRoomListModelCourseGroupName];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_courseGroupId forKey:kMusicRoomListModelCourseGroupId];
+    [aCoder encodeDouble:_studentSign forKey:kMusicRoomListModelStudentSign];
+    [aCoder encodeObject:_imGroupId forKey:kMusicRoomListModelImGroupId];
+    [aCoder encodeObject:_subjectId forKey:kMusicRoomListModelSubjectId];
+    [aCoder encodeObject:_teacherId forKey:kMusicRoomListModelTeacherId];
+    [aCoder encodeObject:_courseId forKey:kMusicRoomListModelCourseId];
+    [aCoder encodeObject:_avatar forKey:kMusicRoomListModelAvatar];
+    [aCoder encodeObject:_teacherName forKey:kMusicRoomListModelTeacherName];
+    [aCoder encodeObject:_endTime forKey:kMusicRoomListModelEndTime];
+    [aCoder encodeObject:_teacherRealName forKey:kMusicRoomListModelTeacherRealName];
+    [aCoder encodeObject:_subjectName forKey:kMusicRoomListModelSubjectName];
+    [aCoder encodeObject:_startTime forKey:kMusicRoomListModelStartTime];
+    [aCoder encodeObject:_status forKey:kMusicRoomListModelStatus];
+    [aCoder encodeObject:_courseGroupName forKey:kMusicRoomListModelCourseGroupName];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    MusicRoomListModel *copy = [[MusicRoomListModel alloc] init];
+    
+    if (copy) {
+
+        copy.courseGroupId = [self.courseGroupId copyWithZone:zone];
+        copy.studentSign = self.studentSign;
+        copy.imGroupId = [self.imGroupId copyWithZone:zone];
+        copy.subjectId = [self.subjectId copyWithZone:zone];
+        copy.teacherId = [self.teacherId copyWithZone:zone];
+        copy.courseId = [self.courseId copyWithZone:zone];
+        copy.avatar = [self.avatar copyWithZone:zone];
+        copy.teacherName = [self.teacherName copyWithZone:zone];
+        copy.endTime = [self.endTime copyWithZone:zone];
+        copy.teacherRealName = [self.teacherRealName copyWithZone:zone];
+        copy.subjectName = [self.subjectName copyWithZone:zone];
+        copy.startTime = [self.startTime copyWithZone:zone];
+        copy.status = [self.status copyWithZone:zone];
+        copy.courseGroupName = [self.courseGroupName copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 60 - 6
KulexiuForStudent/KulexiuForStudent/Module/Mine/MineCourse/View/MyLessonBodyView.m

@@ -17,6 +17,9 @@
 #import "KSFullDatePicker.h"
 #import "AccompanyDetailViewController.h"
 #import "KSChoosePicker.h"
+#import "MusicRoomCourseCell.h"
+#import "MusicRoomListModel.h"
+#import "MusicRoomDetailViewController.h"
 
 @interface MyLessonBodyView ()<UITableViewDelegate,UITableViewDataSource>
 
@@ -77,6 +80,7 @@
         self.tableView.tableFooterView = bottomView;
         [self.tableView registerNib:[UINib nibWithNibName:@"AccompanyCourseCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"AccompanyCourseCell"];
         [self.tableView registerNib:[UINib nibWithNibName:@"MyLiveCourseCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MyLiveCourseCell"];
+        [self.tableView registerNib:[UINib nibWithNibName:@"MusicRoomCourseCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MusicRoomCourseCell"];
         
         [self.dateFormatter setDateFormat:@"yyyy-MM"];
         NSDate *currentDate = [NSDate date];
@@ -152,7 +156,7 @@
             [self changePromptLabelStateWithArray:self.dataArray];
         }];
     }
-    else { // 直播课
+    else if (self.selectIndex == 1) { // 直播课
         [KSNetworkingManager queryMyLiveCourse:KS_POST classDate:self.classDate status:self.status subjectId:self.subjectId page:self.pages rows:self.rows success:^(NSDictionary * _Nonnull dic) {
             [self endRefresh];
             if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
@@ -181,6 +185,35 @@
             [self changePromptLabelStateWithArray:self.dataArray];
         }];
     }
+    else { // 琴房课
+        [KSNetworkingManager queryPianoClassRequest:KS_POST classMonth:self.classDate status:self.status subjectId:self.subjectId page:self.pages rows:self.rows success:^(NSDictionary * _Nonnull dic) {
+            [self endRefresh];
+            if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
+                NSArray *sourceArray = [[dic dictionaryValueForKey:@"data"] arrayValueForKey:@"rows"];
+                for (NSDictionary *parm in sourceArray) {
+                    MusicRoomListModel *model = [[MusicRoomListModel alloc] initWithDictionary:parm];
+                    [self.dataArray addObject:model];
+                }
+                
+                if (sourceArray.count < self.rows) {
+                    self.isLoadMore = NO;
+                }
+            }
+            else {
+                [self MBPShow: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 {
@@ -374,7 +407,7 @@
 }
 
 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
-    if (self.selectIndex == 0) {
+    if (self.selectIndex == 0 || self.selectIndex == 2) {
         return 127.0f;
     }
     else {
@@ -393,7 +426,7 @@
         }];
         return cell;
     }
-    else {
+    else if (self.selectIndex == 1) {
         LiveLessonModel *model = self.dataArray[indexPath.row];
         MyLiveCourseCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyLiveCourseCell"];
         MJWeakSelf;
@@ -402,6 +435,15 @@
         }];
         return cell;
     }
+    else {
+        MusicRoomListModel *model = self.dataArray[indexPath.row];
+        MusicRoomCourseCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MusicRoomCourseCell"];
+        MJWeakSelf;
+        [cell configWithSource:model callback:^(NSString * _Nonnull targetId) {
+            [weakSelf chatAction:targetId];
+        }];
+        return cell;
+    }
 }
 
 - (void)courseOperation:(ACCOMPANY_TYPE)type sourceModel:(AccompanyLessonModel *)model {
@@ -447,14 +489,26 @@
         AccompanyLessonModel *model = self.dataArray[indexPath.row];
         [self showAccompanyDetail:model];
     }
-    else { // 直播课程组详情
+    else if (self.selectIndex == 1) { // 直播课程组详情
         LiveLessonModel *model = self.dataArray[indexPath.row];
         KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
-        NSString *url = [NSString stringWithFormat:@"%@/#/liveDetail?groupId=%@&classId=%@", WEBHOST, model.courseGoupId,model.courseId];
+        NSString *url = [NSString stringWithFormat:@"%@/#/liveDetail?joinRoom=1&groupId=%@&classId=%@", WEBHOST, model.courseGoupId,model.courseId];
         ctrl.url = url;
         [self.naviController pushViewController:ctrl animated:YES];
-        
     }
+    else {
+        MusicRoomListModel *model = self.dataArray[indexPath.row];
+        [self showMusicRoomDetail:model];
+    }
+}
+
+- (void)showMusicRoomDetail:(MusicRoomListModel *)model {
+    MusicRoomDetailViewController *detailVC = [[MusicRoomDetailViewController alloc] init];
+    detailVC.courseId = model.courseId;
+    detailVC.courseGroupId = model.courseGroupId;
+    detailVC.teacherId = model.teacherId;
+    [self.naviController pushViewController:detailVC animated:YES];
+    
 }
 
 /**