Steven преди 5 месеца
родител
ревизия
ea0803110b

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

@@ -1179,6 +1179,9 @@
 		BCF7EB352C856C53006AA38C /* ScanFailBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BCF7EB2F2C856C52006AA38C /* ScanFailBodyView.m */; };
 		BCF7EB362C856C53006AA38C /* ScanOpenAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCF7EB302C856C53006AA38C /* ScanOpenAlert.xib */; };
 		BCF7EB372C856C53006AA38C /* ScanLoginBodyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCF7EB312C856C53006AA38C /* ScanLoginBodyView.xib */; };
+		BCFA12732CF4296E005229AC /* MusicGroupStudenListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BCFA12712CF4296E005229AC /* MusicGroupStudenListCell.m */; };
+		BCFA12742CF4296E005229AC /* MusicGroupStudenListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCFA12722CF4296E005229AC /* MusicGroupStudenListCell.xib */; };
+		BCFA12772CF44C84005229AC /* GroupCourseStudentModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BCFA12762CF44C84005229AC /* GroupCourseStudentModel.m */; };
 		BCFB9B892CE4883100B66BC0 /* VipCouseDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCFB9B882CE4883100B66BC0 /* VipCouseDetailViewController.m */; };
 		BCFB9B8D2CE48D3A00B66BC0 /* VipCouseInfoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BCFB9B8B2CE48D3A00B66BC0 /* VipCouseInfoCell.m */; };
 		BCFB9B8E2CE48D3A00B66BC0 /* VipCouseInfoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCFB9B8C2CE48D3A00B66BC0 /* VipCouseInfoCell.xib */; };
@@ -3151,6 +3154,11 @@
 		BCF880EC2B91C7200007B8F0 /* Config-test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Config-test.xcconfig"; sourceTree = "<group>"; };
 		BCF880EE2B91C7310007B8F0 /* Config-debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Config-debug.xcconfig"; sourceTree = "<group>"; };
 		BCF880F12B91C7580007B8F0 /* Config-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Config-release.xcconfig"; sourceTree = "<group>"; };
+		BCFA12702CF4296E005229AC /* MusicGroupStudenListCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MusicGroupStudenListCell.h; sourceTree = "<group>"; };
+		BCFA12712CF4296E005229AC /* MusicGroupStudenListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MusicGroupStudenListCell.m; sourceTree = "<group>"; };
+		BCFA12722CF4296E005229AC /* MusicGroupStudenListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MusicGroupStudenListCell.xib; sourceTree = "<group>"; };
+		BCFA12752CF44C84005229AC /* GroupCourseStudentModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GroupCourseStudentModel.h; sourceTree = "<group>"; };
+		BCFA12762CF44C84005229AC /* GroupCourseStudentModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GroupCourseStudentModel.m; sourceTree = "<group>"; };
 		BCFB9B872CE4883100B66BC0 /* VipCouseDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VipCouseDetailViewController.h; sourceTree = "<group>"; };
 		BCFB9B882CE4883100B66BC0 /* VipCouseDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VipCouseDetailViewController.m; sourceTree = "<group>"; };
 		BCFB9B8A2CE48D3A00B66BC0 /* VipCouseInfoCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VipCouseInfoCell.h; sourceTree = "<group>"; };
@@ -6726,6 +6734,8 @@
 				BCA353D32858B17E00377661 /* Records.m */,
 				BCA353D02858B17A00377661 /* StudentHomeworkList.h */,
 				BCA353D52858B18100377661 /* StudentHomeworkList.m */,
+				BCFA12752CF44C84005229AC /* GroupCourseStudentModel.h */,
+				BCFA12762CF44C84005229AC /* GroupCourseStudentModel.m */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -6747,6 +6757,9 @@
 				BC5A4B752CF412E8008C2FDD /* MusicRoomGroupHeadView.xib */,
 				BC5A4B782CF41392008C2FDD /* MusicRoomStudentPageView.h */,
 				BC5A4B792CF41392008C2FDD /* MusicRoomStudentPageView.m */,
+				BCFA12702CF4296E005229AC /* MusicGroupStudenListCell.h */,
+				BCFA12712CF4296E005229AC /* MusicGroupStudenListCell.m */,
+				BCFA12722CF4296E005229AC /* MusicGroupStudenListCell.xib */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -8069,6 +8082,7 @@
 				BCC5840928A9FA8100BAB4CF /* cloud_animation_11.png in Resources */,
 				BC02BCE528B324C9005CB483 /* LiveApplyControlView.xib in Resources */,
 				27D83F4E27F3EC2100062476 /* CreateLiveBodyView.xib in Resources */,
+				BCFA12742CF4296E005229AC /* MusicGroupStudenListCell.xib in Resources */,
 				BC5756B328B600A3002302D8 /* HomeAuthAlertView.xib in Resources */,
 				BCF425F42AB9782A00BCD942 /* MineDescView.xib in Resources */,
 				BC31BF8F2B219C5700F7D538 /* TuningForkSettingView.xib in Resources */,
@@ -8669,6 +8683,7 @@
 				BCA9AC4E2CED921E00047BFA /* MyMusicGroupListCell.m in Sources */,
 				BCC5841A28AA36CF00BAB4CF /* BadgeIntroduceView.m in Sources */,
 				27D83F5727F4224F00062476 /* LivePreviewBodyView.m in Sources */,
+				BCFA12732CF4296E005229AC /* MusicGroupStudenListCell.m in Sources */,
 				BC1191F6280EBC7D00A716F7 /* AccompanyDetailBottomView.m in Sources */,
 				BCB909042851E25D00F5FF69 /* KSShareChooseViewController.m in Sources */,
 				BC9EFEB02C0480A500CFA7B1 /* BanStudentListCell.m in Sources */,
@@ -8921,6 +8936,7 @@
 				275FA55827F30AE300EB6240 /* VideoCourseModel.m in Sources */,
 				BC38C47C2AFA1F4B00ABFCC2 /* KSDraftMergeViewController.m in Sources */,
 				BC3BF6462B9FED9B00831494 /* ShareFunctionView.m in Sources */,
+				BCFA12772CF44C84005229AC /* GroupCourseStudentModel.m in Sources */,
 				275B172927EB26920081FDEF /* ChatAddressHeaderView.m in Sources */,
 				BC7CFFA22817D72200CAEB21 /* IncomeListModel.m in Sources */,
 				2755C06C27EC7F0E007D9070 /* KSChatComplainController.m in Sources */,

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

@@ -1661,6 +1661,15 @@ NS_ASSUME_NONNULL_BEGIN
 /// @param faliure 失败
 + (void)courseScheduleListRequest:(NSString *)post courseGroupId:(NSString *)courseGroupId classMonth:(NSString *)classMonth attendanceStatus:(NSString *)attendanceStatus courseStatus:(NSString *)status success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
 
+// /courseGroup/queryStudentByGroupId
+
+/// 查询课程组关联学生
+/// @param post post
+/// @param courseGroupId 课程组ID
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryStudentByGroupIdRequest:(NSString *)post courseGroupId:(NSString *)courseGroupId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
 // courseGroup/updateCoursePlan
 
 /// 更新课程规划

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

@@ -3061,6 +3061,21 @@
     [self request:post andWithUrl:url and:parm success:success faliure:faliure];
 }
 
+// /courseGroup/queryStudentByGroupId
+
+/// 查询课程组关联学生
+/// @param post post
+/// @param courseGroupId 课程组ID
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryStudentByGroupIdRequest:(NSString *)post courseGroupId:(NSString *)courseGroupId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    [self configRequestMethodForm];
+    NSString *url = [NSString stringWithFormat:@"%@%@",hostURL, @"/api-teacher/courseGroup/queryStudentByGroupId"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:courseGroupId forKey:@"groupId"];
+    [self request:post andWithUrl:url and:parm success:success faliure:faliure];
+}
+
 // courseGroup/updateCoursePlan
 
 /// 更新课程规划

+ 24 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/Model/GroupCourseStudentModel.h

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

+ 127 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/Model/GroupCourseStudentModel.m

@@ -0,0 +1,127 @@
+//
+//  GroupCourseStudentModel.m
+//
+//  Created by Steven  on 2024/11/25
+//  Copyright (c) 2024 __MyCompanyName__. All rights reserved.
+//
+
+#import "GroupCourseStudentModel.h"
+
+
+NSString *const kGroupCourseStudentModelUserName = @"userName";
+NSString *const kGroupCourseStudentModelStudentId = @"studentId";
+NSString *const kGroupCourseStudentModelStudentName = @"studentName";
+NSString *const kGroupCourseStudentModelImUserId = @"imUserId";
+NSString *const kGroupCourseStudentModelAvatar = @"avatar";
+
+
+@interface GroupCourseStudentModel ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation GroupCourseStudentModel
+
+@synthesize userName = _userName;
+@synthesize studentId = _studentId;
+@synthesize studentName = _studentName;
+@synthesize imUserId = _imUserId;
+@synthesize avatar = _avatar;
+
+
++ (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.userName = [self objectOrNilForKey:kGroupCourseStudentModelUserName fromDictionary:dict];
+            self.studentId = [self objectOrNilForKey:kGroupCourseStudentModelStudentId fromDictionary:dict];
+            self.studentName = [self objectOrNilForKey:kGroupCourseStudentModelStudentName fromDictionary:dict];
+            self.imUserId = [self objectOrNilForKey:kGroupCourseStudentModelImUserId fromDictionary:dict];
+            self.avatar = [self objectOrNilForKey:kGroupCourseStudentModelAvatar fromDictionary:dict];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.userName forKey:kGroupCourseStudentModelUserName];
+    [mutableDict setValue:self.studentId forKey:kGroupCourseStudentModelStudentId];
+    [mutableDict setValue:self.studentName forKey:kGroupCourseStudentModelStudentName];
+    [mutableDict setValue:self.imUserId forKey:kGroupCourseStudentModelImUserId];
+    [mutableDict setValue:self.avatar forKey:kGroupCourseStudentModelAvatar];
+
+    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.userName = [aDecoder decodeObjectForKey:kGroupCourseStudentModelUserName];
+    self.studentId = [aDecoder decodeObjectForKey:kGroupCourseStudentModelStudentId];
+    self.studentName = [aDecoder decodeObjectForKey:kGroupCourseStudentModelStudentName];
+    self.imUserId = [aDecoder decodeObjectForKey:kGroupCourseStudentModelImUserId];
+    self.avatar = [aDecoder decodeObjectForKey:kGroupCourseStudentModelAvatar];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_userName forKey:kGroupCourseStudentModelUserName];
+    [aCoder encodeObject:_studentId forKey:kGroupCourseStudentModelStudentId];
+    [aCoder encodeObject:_studentName forKey:kGroupCourseStudentModelStudentName];
+    [aCoder encodeObject:_imUserId forKey:kGroupCourseStudentModelImUserId];
+    [aCoder encodeObject:_avatar forKey:kGroupCourseStudentModelAvatar];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    GroupCourseStudentModel *copy = [[GroupCourseStudentModel alloc] init];
+    
+    if (copy) {
+
+        copy.userName = [self.userName copyWithZone:zone];
+        copy.studentId = [self.studentId copyWithZone:zone];
+        copy.studentName = [self.studentName copyWithZone:zone];
+        copy.imUserId = [self.imUserId copyWithZone:zone];
+        copy.avatar = [self.avatar copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 28 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/View/MusicGroupStudenListCell.h

@@ -0,0 +1,28 @@
+//
+//  MusicGroupStudenListCell.h
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/25.
+//
+
+#import <UIKit/UIKit.h>
+#import "GroupCourseStudentModel.h"
+
+typedef NS_ENUM(NSInteger, STUDENTCELL_ROW_INDEX) {
+    STUDENTCELL_ROW_INDEX_TOP,   // 顶部
+    STUDENTCELL_ROW_INDEX_MIDDLE, // 中间
+    STUDENTCELL_ROW_INDEX_BOTTOM, // 底部
+    STUDENTCELL_ROW_INDEX_SINGLE, // 只有一个
+};
+
+typedef void(^ChatStudentCallback)(NSString * _Nonnull imUserId);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MusicGroupStudenListCell : UITableViewCell
+
+- (void)configWithRowIndex:(STUDENTCELL_ROW_INDEX)rowIndex source:(GroupCourseStudentModel *)model callback:(ChatStudentCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 96 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/View/MusicGroupStudenListCell.m

@@ -0,0 +1,96 @@
+//
+//  MusicGroupStudenListCell.m
+//  KulexiuForTeacher
+//
+//  Created by 王智 on 2024/11/25.
+//
+
+#import "MusicGroupStudenListCell.h"
+
+@interface MusicGroupStudenListCell ()
+
+@property (weak, nonatomic) IBOutlet UIView *bgView;
+
+@property (weak, nonatomic) IBOutlet UIView *lineView;
+
+@property (weak, nonatomic) IBOutlet UIImageView *avatar;
+
+@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *subjectView;
+
+@property (weak, nonatomic) IBOutlet UILabel *subjectLabel;
+
+@property (nonatomic, strong) GroupCourseStudentModel *sourceModel;
+
+@property (nonatomic, copy) ChatStudentCallback callback;
+
+@end
+
+@implementation MusicGroupStudenListCell
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    // Initialization code
+    self.selectionStyle = UITableViewCellSelectionStyleNone;
+}
+
+- (void)configWithRowIndex:(STUDENTCELL_ROW_INDEX)rowIndex source:(GroupCourseStudentModel *)model callback:(ChatStudentCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    self.sourceModel = model;
+    [self evaluateWithRowIndex:rowIndex];
+    [self.avatar sd_setImageWithURL:[NSURL URLWithString:[model.avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:STUDENT_AVATAR]];
+    self.nameLabel.text = [NSString returnNoNullStringWithString:model.userName];
+    
+}
+
+- (void)evaluateWithRowIndex:(STUDENTCELL_ROW_INDEX)rowIndex {
+    switch (rowIndex) {
+        case STUDENTCELL_ROW_INDEX_TOP:
+        {
+            self.bgView.layer.cornerRadius = 10.0f;
+            self.bgView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
+            self.lineView.hidden = NO;
+        }
+            break;
+        case STUDENTCELL_ROW_INDEX_MIDDLE:
+        {
+            self.bgView.layer.cornerRadius = 0.0f;
+            self.lineView.hidden = NO;
+        }
+            break;
+        case STUDENTCELL_ROW_INDEX_BOTTOM:
+        {
+            self.bgView.layer.cornerRadius = 10.0f;
+            self.bgView.layer.maskedCorners = kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner;
+            self.lineView.hidden = YES;
+        }
+            break;
+        case STUDENTCELL_ROW_INDEX_SINGLE:
+        {
+            self.bgView.layer.cornerRadius = 10.0f;
+            self.bgView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner |  kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner;
+            self.lineView.hidden = YES;
+        }
+            break;
+        default:
+            break;
+    }
+}
+
+- (IBAction)chat:(id)sender {
+    if (self.callback) {
+        self.callback(self.sourceModel.imUserId);
+    }
+}
+
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+    [super setSelected:selected animated:animated];
+
+    // Configure the view for the selected state
+}
+
+@end

+ 133 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/View/MusicGroupStudenListCell.xib

@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_12" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="111" id="KGk-i7-Jjw" customClass="MusicGroupStudenListCell">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="62"/>
+            <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="62"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="YJa-Sz-dgK">
+                        <rect key="frame" x="14" y="0.0" width="292" height="62"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="student_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="ptD-A6-acq">
+                                <rect key="frame" x="12" y="11" width="40" height="40"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="40" id="JB3-Pb-p94"/>
+                                    <constraint firstAttribute="width" constant="40" id="RNL-Tu-a8Y"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="20"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="向冰冰" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="u7Z-0Z-7wM">
+                                <rect key="frame" x="62" y="11" width="42" height="17"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="17" id="I1E-hY-TXQ"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <view contentMode="scaleToFill" horizontalCompressionResistancePriority="752" translatesAutoresizingMaskIntoConstraints="NO" id="Ied-Eg-5IC">
+                                <rect key="frame" x="62" y="31" width="38" height="17"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="单簧管" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TAr-Dy-ehb">
+                                        <rect key="frame" x="4" y="2.6666666666666643" width="30" height="12"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
+                                        <color key="textColor" red="1" green="0.54901960780000003" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="1" green="0.94509803920000002" blue="0.87058823529999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="17" id="3tt-T6-zqe"/>
+                                    <constraint firstAttribute="trailing" secondItem="TAr-Dy-ehb" secondAttribute="trailing" constant="4" id="5sY-vO-yE2"/>
+                                    <constraint firstItem="TAr-Dy-ehb" firstAttribute="centerY" secondItem="Ied-Eg-5IC" secondAttribute="centerY" id="FA7-Fg-KU7"/>
+                                    <constraint firstItem="TAr-Dy-ehb" firstAttribute="leading" secondItem="Ied-Eg-5IC" secondAttribute="leading" constant="4" id="s4r-TW-L2z"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="4"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </view>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ri9-ZU-k37">
+                                <rect key="frame" x="248" y="9" width="44" height="44"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="44" id="Lf8-uH-Zjc"/>
+                                    <constraint firstAttribute="width" constant="44" id="X2W-PK-9mN"/>
+                                </constraints>
+                                <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                                <state key="normal" image="chat_chat"/>
+                                <connections>
+                                    <action selector="chat:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="CKY-qh-kRY"/>
+                                </connections>
+                            </button>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VJs-9e-FQR">
+                                <rect key="frame" x="12" y="61" width="268" height="1"/>
+                                <color key="backgroundColor" red="0.94901960784313721" green="0.94901960784313721" blue="0.94901960784313721" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="1" id="rEK-A1-dgq"/>
+                                </constraints>
+                            </view>
+                        </subviews>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <constraints>
+                            <constraint firstItem="Ied-Eg-5IC" firstAttribute="top" secondItem="u7Z-0Z-7wM" secondAttribute="bottom" constant="3" id="1Kg-Iv-mr8"/>
+                            <constraint firstItem="u7Z-0Z-7wM" firstAttribute="top" secondItem="ptD-A6-acq" secondAttribute="top" id="7I9-fy-arW"/>
+                            <constraint firstItem="ri9-ZU-k37" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Ied-Eg-5IC" secondAttribute="trailing" id="HJ7-SQ-w12"/>
+                            <constraint firstItem="u7Z-0Z-7wM" firstAttribute="leading" secondItem="ptD-A6-acq" secondAttribute="trailing" constant="10" id="IVR-9L-ADJ"/>
+                            <constraint firstItem="ptD-A6-acq" firstAttribute="centerY" secondItem="YJa-Sz-dgK" secondAttribute="centerY" id="IZu-rg-MOK"/>
+                            <constraint firstAttribute="trailing" secondItem="ri9-ZU-k37" secondAttribute="trailing" id="L8n-Xc-wg6"/>
+                            <constraint firstAttribute="bottom" secondItem="VJs-9e-FQR" secondAttribute="bottom" id="P3t-sh-m7b"/>
+                            <constraint firstAttribute="trailing" secondItem="VJs-9e-FQR" secondAttribute="trailing" constant="12" id="RMD-7M-vuH"/>
+                            <constraint firstItem="ri9-ZU-k37" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="u7Z-0Z-7wM" secondAttribute="trailing" id="Rv9-Rv-lRl"/>
+                            <constraint firstItem="VJs-9e-FQR" firstAttribute="leading" secondItem="YJa-Sz-dgK" secondAttribute="leading" constant="12" id="SLO-NK-06K"/>
+                            <constraint firstItem="ptD-A6-acq" firstAttribute="leading" secondItem="YJa-Sz-dgK" secondAttribute="leading" constant="12" id="gnd-Zm-Kke"/>
+                            <constraint firstItem="Ied-Eg-5IC" firstAttribute="leading" secondItem="u7Z-0Z-7wM" secondAttribute="leading" id="iAK-gb-RHm"/>
+                            <constraint firstItem="ri9-ZU-k37" firstAttribute="centerY" secondItem="YJa-Sz-dgK" secondAttribute="centerY" id="imO-HP-OPG"/>
+                        </constraints>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="bottom" secondItem="YJa-Sz-dgK" secondAttribute="bottom" id="I60-R5-AQz"/>
+                    <constraint firstAttribute="trailing" secondItem="YJa-Sz-dgK" secondAttribute="trailing" constant="14" id="knx-FH-XYZ"/>
+                    <constraint firstItem="YJa-Sz-dgK" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="mhs-Mx-vek"/>
+                    <constraint firstItem="YJa-Sz-dgK" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="qRw-kV-PaR"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="aW0-zy-SZf"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <connections>
+                <outlet property="avatar" destination="ptD-A6-acq" id="GfX-qO-Dtz"/>
+                <outlet property="bgView" destination="YJa-Sz-dgK" id="QA7-a9-4GV"/>
+                <outlet property="lineView" destination="VJs-9e-FQR" id="cvJ-JO-26l"/>
+                <outlet property="nameLabel" destination="u7Z-0Z-7wM" id="1C6-EE-E3V"/>
+                <outlet property="subjectLabel" destination="TAr-Dy-ehb" id="n3a-Pr-h2T"/>
+                <outlet property="subjectView" destination="Ied-Eg-5IC" id="iWz-Tk-fBW"/>
+            </connections>
+            <point key="canvasLocation" x="51.908396946564885" y="43.309859154929576"/>
+        </tableViewCell>
+    </objects>
+    <resources>
+        <image name="chat_chat" width="19" height="18"/>
+        <image name="student_avatar" width="150" height="150"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 229 - 0
KulexiuForTeacher/KulexiuForTeacher/Module/Course/MusicRoom/View/MusicRoomStudentPageView.m

@@ -6,9 +6,238 @@
 //
 
 #import "MusicRoomStudentPageView.h"
+#import "StateView.h"
+#import "Reachability.h"
+#import "MusicGroupStudenListCell.h"
+#import "GroupCourseStudentModel.h"
+#import "KSChatConversationViewController.h"
+
+@interface MusicRoomStudentPageView ()<UITableViewDelegate,UITableViewDataSource>
+
+@property (nonatomic, strong) NSMutableArray *dataArray;
+
+@property (nonatomic, strong) StateView *promptView;
+@property (nonatomic, strong) UIView *promptPlaceView;
+
+@property (nonatomic, assign) BOOL networkAvaiable; // 网络是否可用
+
+@end
 
 @implementation MusicRoomStudentPageView
 
+- (instancetype)initWithFrame:(CGRect)frame {
+    self =  [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) style:UITableViewStylePlain];
+        self.tableView.backgroundColor = [UIColor clearColor];
+        self.tableView.showsVerticalScrollIndicator = NO;
+        
+        self.tableView.dataSource = self;
+        self.tableView.delegate = self;
+        
+        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+        [self addSubview:self.tableView];
+        self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        [self.tableView registerNib:[UINib nibWithNibName:@"MusicGroupStudenListCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"MusicGroupStudenListCell"];
+        
+//        UIView *headView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, 12)];
+//        headView.backgroundColor = [UIColor clearColor];
+//        self.tableView.tableHeaderView = headView;
+        
+        UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, iPhoneXSafeBottomMargin)];
+        bottomView.backgroundColor = [UIColor clearColor];
+        self.tableView.tableFooterView = bottomView;
+        
+        MJWeakSelf;
+        self.tableView.mj_header = [KSGifRefreshHeader headerWithRefreshingBlock:^{
+            [weakSelf resetParamenter];
+            [weakSelf requestData];
+        }];
+    }
+    return self;
+}
+
+- (void)refreshAndRequestData {
+    [self resetParamenter];
+    [self requestData];
+}
+
+- (void)resetParamenter {
+    self.dataArray = [NSMutableArray array];
+    [self.tableView.mj_footer resetNoMoreData];
+    [self setPromptString:@"暂无内容" imageName:@"empty_course" inView:self.tableView];
+    [self.tableView reloadData];
+}
+
+- (void)endRefresh {
+    @weakObj(self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        @strongObj(self);
+        [self.tableView.mj_header endRefreshing];
+    });
+}
+
+
+- (void)requestData {
+    [KSNetworkingManager queryStudentByGroupIdRequest:KS_POST courseGroupId:self.courseGroupId success:^(NSDictionary * _Nonnull dic) {
+        [self endRefresh];
+        if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [dic ks_arrayValueForKey:@"data"];
+            for (NSDictionary *parm in sourceArray) {
+                GroupCourseStudentModel *model = [[GroupCourseStudentModel alloc] initWithDictionary:parm];
+                [self.dataArray addObject:model];
+            }
+        }
+        else {
+            [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
+        }
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    } faliure:^(NSError * _Nonnull error) {
+        [self endRefresh];
+        if (self.networkAvaiable == NO) {
+            [self setPromptString:@"暂无网络" imageName:@"no_networking" inView:self.tableView];
+        }
+        [self.dataArray removeAllObjects];
+        [self.tableView reloadData];
+        [self changePromptLabelStateWithArray:self.dataArray];
+    }];
+}
+
+- (void)beginRefreshImmediately {
+    [self.tableView.mj_header beginRefreshing];
+}
+
+- (void)beginFirstRefresh {
+    if (!self.isHeaderRefreshed) {
+        [self beginRefreshImmediately];
+    }
+}
+- (void)selectCellAtIndexPath:(NSIndexPath *)indexPath {
+    
+    if (self.lastSelectedIndexPath == indexPath) {
+        return;
+    }
+    if (self.lastSelectedIndexPath != nil) {
+        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.lastSelectedIndexPath];
+        [cell setSelected:NO animated:NO];
+    }
+    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+    [cell setSelected:YES animated:NO];
+    self.lastSelectedIndexPath = indexPath;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    [self.tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.top.mas_equalTo(self.mas_top).offset(12);
+        make.left.right.bottom.mas_equalTo(self);
+    }];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 64.0f;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    GroupCourseStudentModel *model = self.dataArray[indexPath.row];
+    
+    MusicGroupStudenListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MusicGroupStudenListCell"];
+    STUDENTCELL_ROW_INDEX cellIndex = STUDENTCELL_ROW_INDEX_MIDDLE;
+    if (self.dataArray.count == 1) {
+        cellIndex = STUDENTCELL_ROW_INDEX_SINGLE;
+    }
+    else {
+        if (indexPath.row == 0) {
+            cellIndex = STUDENTCELL_ROW_INDEX_TOP;
+        }
+        else if (indexPath.row == self.dataArray.count - 1) {
+            cellIndex = STUDENTCELL_ROW_INDEX_BOTTOM;
+        }
+    }
+    MJWeakSelf;
+    [cell configWithRowIndex:cellIndex source:model callback:^(NSString * _Nonnull imUserId) {
+        [weakSelf chatStudent:imUserId];
+    }];
+    
+    return cell;
+}
+
+- (void)chatStudent:(NSString *)imUserId {
+    TUIChatConversationModel *model = [[TUIChatConversationModel alloc] init];
+    model.userID = imUserId;
+    KSChatConversationViewController *ctrl = [[KSChatConversationViewController alloc] init];
+    ctrl.conversation = model;
+    [self.naviController pushViewController:ctrl animated:YES];
+}
+
+/**
+ 设置没有数据时的显示
+ 
+ @param promptString 提示语
+ @param imgName 图片名称
+ @param view 显示在什么地方
+ */
+- (void)setPromptString:(NSString *)promptString imageName:(NSString *)imgName inView:(UIView *)view {
+    if (self.promptView != nil) {
+        [self.promptView removeFromSuperview];
+    }
+    else {
+        self.promptView = [[StateView alloc]init];
+        self.promptView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight - 300);
+    }
+    _promptPlaceView = view;
+    //当请求不到数据时 ,自定义提示view 将会出现;
+    self.promptView.imageName = imgName;
+    self.promptView.alpha = 0.0f;
+    [self.promptView setText:promptString];
+    [view addSubview:self.promptView];
+}
+
+// 结束刷新后调用方法
+- (void)changePromptLabelStateWithArray:(NSMutableArray *)array {
+    NSInteger count;
+    if (array.count) {
+        count = array.count;
+    } else {
+        count = 0;
+    }
+    
+    [UIView animateWithDuration:0.1 animations:^{
+        [[self promptView] setAlpha:count ? 0.0f :1.0f];
+    }];
+}
+
+- (BOOL)networkAvaiable {
+    return [self checkNetworkAvaiable];
+}
+
+- (BOOL)checkNetworkAvaiable {
+    BOOL isExistenceNetwork = YES;
+    Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
+    switch ([reach currentReachabilityStatus]) {
+        case NotReachable:
+            isExistenceNetwork = NO;
+            //NSLog(@"notReachable");
+            break;
+        case ReachableViaWiFi:
+            isExistenceNetwork = YES;
+            //NSLog(@"WIFI");
+            break;
+        case ReachableViaWWAN:
+            isExistenceNetwork = YES;
+            //NSLog(@"3G");
+            break;
+    }
+    return isExistenceNetwork;
+}
+
 /*
 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.

+ 1 - 1
KulexiuForTeacher/KulexiuForTeacher/Module/Course/VIPCourse/View/ProgramCourseGroupBodyView.m

@@ -266,7 +266,7 @@
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     // 课程详情
     GroupCourseListModel *courseModel = self.dataArray[indexPath.row];
-    CourseStudentVos *studentModel = [courseModel.courseStudentVos lastObject];
+    CourseStudentVos *studentModel = [courseModel.courseStudentVos firstObject];
     if (self.courseType == COURSE_GROUP_TYPE_VIP) {
         VipCouseDetailViewController *detailVC = [[VipCouseDetailViewController alloc] init];
         detailVC.courseId = courseModel.courseId;