فهرست منبع

1.聊天修改

Steven 2 سال پیش
والد
کامیت
e1024f6bd1
84فایلهای تغییر یافته به همراه2685 افزوده شده و 261 حذف شده
  1. 80 0
      KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj
  2. BIN
      KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate
  3. 59 75
      KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  4. 1 1
      KulexiuForStudent/KulexiuForStudent/AppDelegate.m
  5. 6 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/Contents.json
  6. 2 2
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentList.imageset/Contents.json
  7. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentList.imageset/chat_talentList@2x.png
  8. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentList.imageset/chat_talentList@3x.png
  9. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentTag.imageset/Contents.json
  10. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentTag.imageset/chat_talentTag@2x.png
  11. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentTag.imageset/chat_talentTag@3x.png
  12. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerList.imageset/Contents.json
  13. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerList.imageset/chat_ownerList@2x.png
  14. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerList.imageset/chat_ownerList@3x.png
  15. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerTag.imageset/Contents.json
  16. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerTag.imageset/group_ownerTag@2x.png
  17. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerTag.imageset/group_ownerTag@3x.png
  18. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_talentTag.imageset/Contents.json
  19. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_talentTag.imageset/chat_talentTag@2x.png
  20. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_talentTag.imageset/chat_talentTag@3x.png
  21. 2 2
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_use_sex.imageset/Contents.json
  22. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_use_sex.imageset/chat_use_sex@2x.png
  23. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_use_sex.imageset/chat_use_sex@3x.png
  24. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_user_subject.imageset/Contents.json
  25. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_user_subject.imageset/chat_user_subject@2x.png
  26. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_user_subject.imageset/chat_user_subject@3x.png
  27. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_owner.imageset/group_owner@2x.png
  28. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_owner.imageset/group_owner@3x.png
  29. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_ownerList.imageset/group_ownerList@2x.png
  30. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_ownerList.imageset/group_ownerList@3x.png
  31. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/user_detailBg.imageset/Contents.json
  32. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/user_detailBg.imageset/user_detailBg@2x.png
  33. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/user_detailBg.imageset/user_detailBg@3x.png
  34. 27 0
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.h
  35. 48 2
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.m
  36. 10 2
      KulexiuForStudent/KulexiuForStudent/Common/Base/KSRCIMDataSource.m
  37. 14 14
      KulexiuForStudent/KulexiuForStudent/Common/Define/PrefixHeader.pch
  38. 5 1
      KulexiuForStudent/KulexiuForStudent/Common/Define/UserKeyHeader.h
  39. 1 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/ChatAddressViewController.m
  40. 104 12
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.m
  41. 22 2
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatListViewController.m
  42. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatUserDetailViewController.h
  43. 175 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatUserDetailViewController.m
  44. 7 3
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupMemberViewController.m
  45. 8 3
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupSettingViewController.m
  46. 8 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupMemberListCell.m
  47. 14 3
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupMemberListCell.xib
  48. 22 4
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupSettingBodyView.m
  49. 44 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/ChatUserInfo.h
  50. 263 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/ChatUserInfo.m
  51. 70 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/RecentPracticeModel.h
  52. 445 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/RecentPracticeModel.m
  53. 2 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/FriendListModel.h
  54. 15 5
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/FriendListModel.m
  55. 1 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/GroupMemberModel.h
  56. 7 3
      KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/GroupMemberModel.m
  57. 2 2
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m
  58. 24 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/RecentMusicView.h
  59. 185 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/RecentMusicView.m
  60. 132 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/RecentMusicView.xib
  61. 26 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBodyView.h
  62. 100 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBodyView.m
  63. 262 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBodyView.xib
  64. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBottomView.h
  65. 25 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBottomView.m
  66. 37 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBottomView.xib
  67. 22 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailNavView.h
  68. 44 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailNavView.m
  69. 69 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailNavView.xib
  70. 8 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ContractListCell.m
  71. 14 3
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ContractListCell.xib
  72. 16 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatTagView.h
  73. 20 0
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatTagView.m
  74. 14 7
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ShareLiveCellContentView.xib
  75. 13 7
      KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ShareMusicCellContentView.xib
  76. 3 23
      KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m
  77. 5 2
      KulexiuForStudent/KulexiuForStudent/Module/Home/View/HotAlbum/HomeHotAlbumCell.xib
  78. 0 40
      KulexiuForStudent/KulexiuForStudent/Module/Home/View/HotMusic/HomeHotMusicCellView.m
  79. 13 28
      KulexiuForStudent/KulexiuForStudent/Module/Home/View/HotMusic/HomeHotMusicCellView.xib
  80. 0 2
      KulexiuForStudent/KulexiuForStudent/Module/Live/View/SeatContentView.m
  81. 1 0
      KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfo.h
  82. 7 0
      KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfo.m
  83. 8 1
      KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfoManager.m
  84. 5 12
      KulexiuForStudent/KulexiuForStudent/Module/SealClass/Sections/Classroom/View/Chat/MessageManager/MessageHelper.m

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

@@ -421,6 +421,10 @@
 		BC119298280FBCB400A716F7 /* UIView+ExtensionForDotLine.m in Sources */ = {isa = PBXBuildFile; fileRef = BC119297280FBCB400A716F7 /* UIView+ExtensionForDotLine.m */; };
 		BC11929B280FD2E800A716F7 /* HomeworkBottomView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC11929A280FD2E800A716F7 /* HomeworkBottomView.m */; };
 		BC11929D280FD2EF00A716F7 /* HomeworkBottomView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC11929C280FD2EF00A716F7 /* HomeworkBottomView.xib */; };
+		BC12636428FE930C00509E90 /* ChatUserInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = BC12636228FE930C00509E90 /* ChatUserInfo.m */; };
+		BC12636728FEA01F00509E90 /* RecentPracticeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC12636628FEA01F00509E90 /* RecentPracticeModel.m */; };
+		BC12636D28FEA20100509E90 /* RecentMusicView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC12636C28FEA20100509E90 /* RecentMusicView.m */; };
+		BC12636F28FEA20800509E90 /* RecentMusicView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC12636E28FEA20800509E90 /* RecentMusicView.xib */; };
 		BC27A06E280FF56C00F91E27 /* AccompanyEvaluateCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC27A06A280FF56B00F91E27 /* AccompanyEvaluateCell.xib */; };
 		BC27A06F280FF56C00F91E27 /* AccompanyStudentEvaCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BC27A06B280FF56C00F91E27 /* AccompanyStudentEvaCell.m */; };
 		BC27A070280FF56C00F91E27 /* AccompanyStudentEvaCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC27A06C280FF56C00F91E27 /* AccompanyStudentEvaCell.xib */; };
@@ -587,6 +591,14 @@
 		BC71D2892888083B0010F14B /* tabbar5.json in Resources */ = {isa = PBXBuildFile; fileRef = BC71D2842888083B0010F14B /* tabbar5.json */; };
 		BC736A92288036E8004A9B0A /* MyVideoSearchView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC736A90288036E8004A9B0A /* MyVideoSearchView.m */; };
 		BC736A93288036E8004A9B0A /* MyVideoSearchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC736A91288036E8004A9B0A /* MyVideoSearchView.xib */; };
+		BC756CB628FE4E5D00AA9ECB /* KSChatTagView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC756CB528FE4E5D00AA9ECB /* KSChatTagView.m */; };
+		BC756CB928FE7D1D00AA9ECB /* KSChatUserDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC756CB828FE7D1D00AA9ECB /* KSChatUserDetailViewController.m */; };
+		BC756CBC28FE7D5600AA9ECB /* UserDetailBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC756CBB28FE7D5600AA9ECB /* UserDetailBodyView.m */; };
+		BC756CBE28FE7D6000AA9ECB /* UserDetailBodyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC756CBD28FE7D6000AA9ECB /* UserDetailBodyView.xib */; };
+		BC756CC128FE7D9500AA9ECB /* UserDetailNavView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC756CC028FE7D9500AA9ECB /* UserDetailNavView.m */; };
+		BC756CC328FE7DA900AA9ECB /* UserDetailNavView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC756CC228FE7DA900AA9ECB /* UserDetailNavView.xib */; };
+		BC756CC628FE866100AA9ECB /* UserDetailBottomView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC756CC528FE866100AA9ECB /* UserDetailBottomView.m */; };
+		BC756CC828FE867000AA9ECB /* UserDetailBottomView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC756CC728FE867000AA9ECB /* UserDetailBottomView.xib */; };
 		BC76630E2827E48800C91A1D /* NotiferMessageModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC76630C2827E48800C91A1D /* NotiferMessageModel.m */; };
 		BC7663152827E49900C91A1D /* NotiferHeadView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC76630F2827E49800C91A1D /* NotiferHeadView.m */; };
 		BC7663162827E49900C91A1D /* NotiferHeadView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC7663102827E49800C91A1D /* NotiferHeadView.xib */; };
@@ -1730,6 +1742,13 @@
 		BC119299280FD2E800A716F7 /* HomeworkBottomView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeworkBottomView.h; sourceTree = "<group>"; };
 		BC11929A280FD2E800A716F7 /* HomeworkBottomView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeworkBottomView.m; sourceTree = "<group>"; };
 		BC11929C280FD2EF00A716F7 /* HomeworkBottomView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeworkBottomView.xib; sourceTree = "<group>"; };
+		BC12636228FE930C00509E90 /* ChatUserInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatUserInfo.m; sourceTree = "<group>"; };
+		BC12636328FE930C00509E90 /* ChatUserInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatUserInfo.h; sourceTree = "<group>"; };
+		BC12636528FEA01F00509E90 /* RecentPracticeModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentPracticeModel.h; sourceTree = "<group>"; };
+		BC12636628FEA01F00509E90 /* RecentPracticeModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentPracticeModel.m; sourceTree = "<group>"; };
+		BC12636B28FEA20100509E90 /* RecentMusicView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RecentMusicView.h; sourceTree = "<group>"; };
+		BC12636C28FEA20100509E90 /* RecentMusicView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RecentMusicView.m; sourceTree = "<group>"; };
+		BC12636E28FEA20800509E90 /* RecentMusicView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RecentMusicView.xib; sourceTree = "<group>"; };
 		BC27A068280FF56B00F91E27 /* AccompanyEvaluateCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccompanyEvaluateCell.h; sourceTree = "<group>"; };
 		BC27A069280FF56B00F91E27 /* AccompanyStudentEvaCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccompanyStudentEvaCell.h; sourceTree = "<group>"; };
 		BC27A06A280FF56B00F91E27 /* AccompanyEvaluateCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccompanyEvaluateCell.xib; sourceTree = "<group>"; };
@@ -1956,6 +1975,19 @@
 		BC736A8F288036E8004A9B0A /* MyVideoSearchView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyVideoSearchView.h; sourceTree = "<group>"; };
 		BC736A90288036E8004A9B0A /* MyVideoSearchView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyVideoSearchView.m; sourceTree = "<group>"; };
 		BC736A91288036E8004A9B0A /* MyVideoSearchView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyVideoSearchView.xib; sourceTree = "<group>"; };
+		BC756CB428FE4E5D00AA9ECB /* KSChatTagView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KSChatTagView.h; sourceTree = "<group>"; };
+		BC756CB528FE4E5D00AA9ECB /* KSChatTagView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSChatTagView.m; sourceTree = "<group>"; };
+		BC756CB728FE7D1D00AA9ECB /* KSChatUserDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KSChatUserDetailViewController.h; sourceTree = "<group>"; };
+		BC756CB828FE7D1D00AA9ECB /* KSChatUserDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSChatUserDetailViewController.m; sourceTree = "<group>"; };
+		BC756CBA28FE7D5600AA9ECB /* UserDetailBodyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserDetailBodyView.h; sourceTree = "<group>"; };
+		BC756CBB28FE7D5600AA9ECB /* UserDetailBodyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UserDetailBodyView.m; sourceTree = "<group>"; };
+		BC756CBD28FE7D6000AA9ECB /* UserDetailBodyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UserDetailBodyView.xib; sourceTree = "<group>"; };
+		BC756CBF28FE7D9500AA9ECB /* UserDetailNavView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserDetailNavView.h; sourceTree = "<group>"; };
+		BC756CC028FE7D9500AA9ECB /* UserDetailNavView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UserDetailNavView.m; sourceTree = "<group>"; };
+		BC756CC228FE7DA900AA9ECB /* UserDetailNavView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UserDetailNavView.xib; sourceTree = "<group>"; };
+		BC756CC428FE866000AA9ECB /* UserDetailBottomView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserDetailBottomView.h; sourceTree = "<group>"; };
+		BC756CC528FE866100AA9ECB /* UserDetailBottomView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UserDetailBottomView.m; sourceTree = "<group>"; };
+		BC756CC728FE867000AA9ECB /* UserDetailBottomView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UserDetailBottomView.xib; sourceTree = "<group>"; };
 		BC76630C2827E48800C91A1D /* NotiferMessageModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotiferMessageModel.m; sourceTree = "<group>"; };
 		BC76630D2827E48800C91A1D /* NotiferMessageModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotiferMessageModel.h; sourceTree = "<group>"; };
 		BC76630F2827E49800C91A1D /* NotiferHeadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotiferHeadView.m; sourceTree = "<group>"; };
@@ -3039,6 +3071,8 @@
 				2723B59E27F1578000E0B90B /* KSChatConversationViewController.m */,
 				2723B59F27F1578100E0B90B /* KSChatListViewController.h */,
 				2723B59C27F1577F00E0B90B /* KSChatListViewController.m */,
+				BC756CB728FE7D1D00AA9ECB /* KSChatUserDetailViewController.h */,
+				BC756CB828FE7D1D00AA9ECB /* KSChatUserDetailViewController.m */,
 			);
 			path = Controller;
 			sourceTree = "<group>";
@@ -3046,6 +3080,7 @@
 		275FA20127E7356B00CFEA2E /* Model */ = {
 			isa = PBXGroup;
 			children = (
+				BC12638628FEB5D700509E90 /* ChatUserInfo */,
 				BCED5CA5284F55A0009A42DE /* FriendListModel.h */,
 				BCED5CA6284F55A0009A42DE /* FriendListModel.m */,
 				2723B5C927F157BA00E0B90B /* GroupListModel.h */,
@@ -3065,6 +3100,7 @@
 		275FA20227E7356B00CFEA2E /* View */ = {
 			isa = PBXGroup;
 			children = (
+				BC12637028FEB59B00509E90 /* ChatUserInfo */,
 				2723B5B027F157AB00E0B90B /* ChatAddressBodyView.h */,
 				2723B5A727F157A300E0B90B /* ChatAddressBodyView.m */,
 				2723B5B627F157AF00E0B90B /* ChatAddressHeaderView.h */,
@@ -3099,6 +3135,8 @@
 				BCB908EC2850B08D00F5FF69 /* ShareMusicCellContentView.xib */,
 				BCDE358C289A7D8700A9A560 /* KSGroupTagImageView.h */,
 				BCDE358D289A7D8700A9A560 /* KSGroupTagImageView.m */,
+				BC756CB428FE4E5D00AA9ECB /* KSChatTagView.h */,
+				BC756CB528FE4E5D00AA9ECB /* KSChatTagView.m */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -4370,6 +4408,36 @@
 			path = View;
 			sourceTree = "<group>";
 		};
+		BC12637028FEB59B00509E90 /* ChatUserInfo */ = {
+			isa = PBXGroup;
+			children = (
+				BC756CBF28FE7D9500AA9ECB /* UserDetailNavView.h */,
+				BC756CC028FE7D9500AA9ECB /* UserDetailNavView.m */,
+				BC756CC228FE7DA900AA9ECB /* UserDetailNavView.xib */,
+				BC756CBA28FE7D5600AA9ECB /* UserDetailBodyView.h */,
+				BC756CBB28FE7D5600AA9ECB /* UserDetailBodyView.m */,
+				BC756CBD28FE7D6000AA9ECB /* UserDetailBodyView.xib */,
+				BC756CC428FE866000AA9ECB /* UserDetailBottomView.h */,
+				BC756CC528FE866100AA9ECB /* UserDetailBottomView.m */,
+				BC756CC728FE867000AA9ECB /* UserDetailBottomView.xib */,
+				BC12636B28FEA20100509E90 /* RecentMusicView.h */,
+				BC12636C28FEA20100509E90 /* RecentMusicView.m */,
+				BC12636E28FEA20800509E90 /* RecentMusicView.xib */,
+			);
+			path = ChatUserInfo;
+			sourceTree = "<group>";
+		};
+		BC12638628FEB5D700509E90 /* ChatUserInfo */ = {
+			isa = PBXGroup;
+			children = (
+				BC12636328FE930C00509E90 /* ChatUserInfo.h */,
+				BC12636228FE930C00509E90 /* ChatUserInfo.m */,
+				BC12636528FEA01F00509E90 /* RecentPracticeModel.h */,
+				BC12636628FEA01F00509E90 /* RecentPracticeModel.m */,
+			);
+			path = ChatUserInfo;
+			sourceTree = "<group>";
+		};
 		BC25C18D28F50C46009E31BD /* RecordManager */ = {
 			isa = PBXGroup;
 			children = (
@@ -6188,6 +6256,7 @@
 				275FA1EF27E7351900CFEA2E /* KSUpdateAlert.xib in Resources */,
 				BC802DBA28BC8C810079E350 /* HomeHotVideoCourseView.xib in Resources */,
 				277935AF27E324A90010E277 /* mss_browseLoading@3x.png in Resources */,
+				BC756CBE28FE7D6000AA9ECB /* UserDetailBodyView.xib in Resources */,
 				BC60E3CE287D552800B05441 /* DeleteAccountBodyView.xib in Resources */,
 				BCFDA61328BC8FCE0022B497 /* HomeHotVideoCell.xib in Resources */,
 				BCC583BE28A9EC6400BAB4CF /* cloud_animation_24.png in Resources */,
@@ -6285,6 +6354,7 @@
 				BC71D267288804CD0010F14B /* img_42.png in Resources */,
 				BC71D27A288804CD0010F14B /* img_35.png in Resources */,
 				BC71D25A288804CD0010F14B /* img_46.png in Resources */,
+				BC12636F28FEA20800509E90 /* RecentMusicView.xib in Resources */,
 				BCC5841E28AA545B00BAB4CF /* cloud_animation_29.png in Resources */,
 				BCBFDF5228115DA40052AFE5 /* HomeIntroduceView.xib in Resources */,
 				BC71D277288804CD0010F14B /* img_36.png in Resources */,
@@ -6405,6 +6475,7 @@
 				BC71D25D288804CD0010F14B /* img_47.png in Resources */,
 				BCA353F12859BB2900377661 /* MusicRoomCourseCell.xib in Resources */,
 				BCC583B828A9EC6400BAB4CF /* cloud_animation_23.png in Resources */,
+				BC756CC328FE7DA900AA9ECB /* UserDetailNavView.xib in Resources */,
 				2723B66E27F15CFC00E0B90B /* PhoneCheckBodyView.xib in Resources */,
 				BCFDA65128BCA2000022B497 /* live_animation_2.png in Resources */,
 				BC119217280ED6A900A716F7 /* MyLessonSearchView.xib in Resources */,
@@ -6435,6 +6506,7 @@
 				BC50171727FC0D8E00F8BCBC /* SubjectChooseBodyView.xib in Resources */,
 				BC71D26F288804CD0010F14B /* img_24.png in Resources */,
 				BC71D26B288804CD0010F14B /* img_8.png in Resources */,
+				BC756CC828FE867000AA9ECB /* UserDetailBottomView.xib in Resources */,
 				BCFDA62628BC94480022B497 /* HomeNavSearchView.xib in Resources */,
 				BC71D0F42881A2420010F14B /* UMCommonLog.bundle in Resources */,
 				BCB6359D27F6D2AB00ACFDCF /* tock.wav in Resources */,
@@ -6628,6 +6700,7 @@
 				BCFDA66228BDC3640022B497 /* TalentTeacherModel.m in Sources */,
 				BC8B6DC92856CFB800866917 /* KSDocument.m in Sources */,
 				275FA1E927E7351900CFEA2E /* KSNetTypeManager.m in Sources */,
+				BC756CC128FE7D9500AA9ECB /* UserDetailNavView.m in Sources */,
 				2723B66B27F15CFC00E0B90B /* PhoneCheckBodyView.m in Sources */,
 				27F9033027E87C2E00C08A19 /* AudioRecordManager.m in Sources */,
 				BCB6355227F6D2A300ACFDCF /* SelectionButton.m in Sources */,
@@ -6724,6 +6797,7 @@
 				BCB6356727F6D2A300ACFDCF /* MemberChangeMessage.m in Sources */,
 				2779353B27E324A60010E277 /* UrlDecode.m in Sources */,
 				BC40BA23281255F700DEC0D1 /* HomeCourseTipsView.m in Sources */,
+				BC12636D28FEA20100509E90 /* RecentMusicView.m in Sources */,
 				BC8C2C5F2823F57100FBA5D5 /* MyAddressListCell.m in Sources */,
 				275FA22C27E7356B00CFEA2E /* CourseViewController.m in Sources */,
 				2779358D27E324A80010E277 /* DZNSegmentedControl.m in Sources */,
@@ -6880,6 +6954,7 @@
 				BCFE540328152A8500AD6786 /* KSOrderManager.m in Sources */,
 				2723B64427F15B5900E0B90B /* SCIndexViewConfiguration.m in Sources */,
 				2779358527E324A80010E277 /* LLFileManager.m in Sources */,
+				BC756CBC28FE7D5600AA9ECB /* UserDetailBodyView.m in Sources */,
 				BCB6346D27F6D29600ACFDCF /* KSEnterLiveroomManager.m in Sources */,
 				2779357327E324A70010E277 /* prodectButton.m in Sources */,
 				2723B5BD27F157B100E0B90B /* KSChatListSearchView.m in Sources */,
@@ -6976,6 +7051,7 @@
 				277935B227E324A90010E277 /* UIView+MSSLayout.m in Sources */,
 				BCFDA61228BC8FCE0022B497 /* HomeHotVideoCell.m in Sources */,
 				275FA1E427E7351900CFEA2E /* KSWebNavView.m in Sources */,
+				BC756CB928FE7D1D00AA9ECB /* KSChatUserDetailViewController.m in Sources */,
 				2779356D27E324A70010E277 /* StoreShopCaterview.m in Sources */,
 				BC119267280FA92700A716F7 /* HomeworkDetailViewController.m in Sources */,
 				BCB6346127F6D29600ACFDCF /* KSChatroomMessageCenter.m in Sources */,
@@ -7039,6 +7115,7 @@
 				275FA1E127E7351900CFEA2E /* KSTabBarViewController.m in Sources */,
 				BC11926B280FAF5900A716F7 /* AccompanyAlertView.m in Sources */,
 				277935BB27E324A90010E277 /* FSCalendarSeparatorDecorationView.m in Sources */,
+				BC756CC628FE866100AA9ECB /* UserDetailBottomView.m in Sources */,
 				BC8A45A9283DC33400094BBB /* KSCloudBeatView.m in Sources */,
 				275FA1DF27E7351900CFEA2E /* RCConnectionManager.m in Sources */,
 				275FA22B27E7356B00CFEA2E /* HomeViewController.m in Sources */,
@@ -7148,6 +7225,7 @@
 				BC5082B4283345A10031DD0A /* KSChatListCell.m in Sources */,
 				BCB6345D27F6D29600ACFDCF /* KSLiveChatroomWelcome.m in Sources */,
 				2779352927E324A60010E277 /* zhPopupController.m in Sources */,
+				BC12636728FEA01F00509E90 /* RecentPracticeModel.m in Sources */,
 				2779359527E324A80010E277 /* TZVideoEditedPreviewController.m in Sources */,
 				2723B63127F157D500E0B90B /* GroupSettingBodyView.m in Sources */,
 				BC119290280FB46100A716F7 /* KSVideoHelper.m in Sources */,
@@ -7165,6 +7243,7 @@
 				2723B5C127F157B100E0B90B /* ContractListCell.m in Sources */,
 				BC802D9728BC4FC40079E350 /* HomeHotMusicView.m in Sources */,
 				275FA1E527E7351900CFEA2E /* KSAccompanyWebViewController.m in Sources */,
+				BC756CB628FE4E5D00AA9ECB /* KSChatTagView.m in Sources */,
 				BC8A45A5283DC33400094BBB /* StaffImageDisplayView.m in Sources */,
 				BC11923A280ED98E00A716F7 /* AccompanyCourseCell.m in Sources */,
 				BCFDA62F28BC99410022B497 /* HomeBannerView.m in Sources */,
@@ -7235,6 +7314,7 @@
 				BC8C2C572823F57100FBA5D5 /* AddressDetailViewController.m in Sources */,
 				BCB6359627F6D2AB00ACFDCF /* LocalRenderManager.m in Sources */,
 				2723B66927F15CFC00E0B90B /* PhoneChangeBodyView.m in Sources */,
+				BC12636428FE930C00509E90 /* ChatUserInfo.m in Sources */,
 				27F9033227E87C2E00C08A19 /* SettingViewController.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

BIN
KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate


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

@@ -55,156 +55,140 @@
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "D2276D3F-954F-4D89-B78F-7FF698AA732A"
-            shouldBeEnabled = "Yes"
+            uuid = "48D19C1D-7CA8-41F5-B6D2-62482808D92F"
+            shouldBeEnabled = "No"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/AppDelegate.m"
+            filePath = "KulexiuForStudent/Module/Home/Controller/HomeViewController.m"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "577"
-            endingLineNumber = "577"
-            landmarkName = "-jpushNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:"
+            startingLineNumber = "551"
+            endingLineNumber = "551"
+            landmarkName = "-requestHotAlbum"
             landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
          <BreakpointContent
-            uuid = "821B291D-6858-47E2-8EC5-833A950C4F38"
+            uuid = "B53C8936-0246-4C10-A4ED-11D513BBA445"
             shouldBeEnabled = "Yes"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.m"
+            breakpointStackSelectionBehavior = "1"
+            scope = "1"
+            stopOnStyle = "1">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "1111ED18-417D-42C2-AF8C-16DA1DDDACC4"
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "KulexiuForStudent/Module/Login/Model/UserInfoManager.m"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "325"
-            endingLineNumber = "325"
-            landmarkName = "-refreshUserInfoOrGroupInfo"
+            startingLineNumber = "385"
+            endingLineNumber = "385"
+            landmarkName = "-startUMCountAndLoginCount"
             landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "A4FEF7A2-024A-4B17-BEED-02383B7F4FF8"
+            uuid = "3BD18AAA-986A-4C4B-AC76-97F242E45E7F"
             shouldBeEnabled = "Yes"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Common/Base/KSRCIMDataSource.m"
+            filePath = "KulexiuForStudent/Module/SealClass/Services/Classroom/ClassroomService.m"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "71"
-            endingLineNumber = "71"
-            landmarkName = "-getUserInfoWithUserId:completion:"
+            startingLineNumber = "411"
+            endingLineNumber = "411"
+            landmarkName = "-onReceiveDeviceMessage:withSenderId:"
             landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "48D19C1D-7CA8-41F5-B6D2-62482808D92F"
+            uuid = "96F5853A-BD70-4A02-9086-16255829C27B"
             shouldBeEnabled = "No"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Module/Home/Controller/HomeViewController.m"
+            filePath = "KulexiuForStudent/Common/Base/KSNetworkingManager.m"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "552"
-            endingLineNumber = "552"
-            landmarkName = "-requestHotAlbum"
+            startingLineNumber = "799"
+            endingLineNumber = "799"
+            landmarkName = "+imUserFriendRequest:search:success:faliure:"
             landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "7DBFF699-6450-4D38-A4A5-C6E7115FD5F8"
+            uuid = "C0FA1F71-1707-4AF4-9FFF-9C6B57E831F2"
             shouldBeEnabled = "Yes"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m"
+            filePath = "KulexiuForStudent/Common/Base/KSBaseWKWebViewController.m"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "129"
-            endingLineNumber = "129"
-            landmarkName = "-requestData"
+            startingLineNumber = "536"
+            endingLineNumber = "536"
+            landmarkName = "-handleScriptMessageSource:"
             landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "36EDB858-B943-472A-B904-A4C60B222D3D"
-            shouldBeEnabled = "Yes"
+            uuid = "18AD76CB-BAF9-457C-AF3F-6ACC381E87D6"
+            shouldBeEnabled = "No"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m"
+            filePath = "KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.m"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "127"
-            endingLineNumber = "127"
-            landmarkName = "-requestData"
+            startingLineNumber = "449"
+            endingLineNumber = "449"
+            landmarkName = "-willDisplayMessageCell:atIndexPath:"
             landmarkType = "7">
-            <Locations>
-               <Location
-                  uuid = "36EDB858-B943-472A-B904-A4C60B222D3D - 8cbd1df76a1d5c0e"
-                  shouldBeEnabled = "Yes"
-                  ignoreCount = "0"
-                  continueAfterRunningActions = "No"
-                  symbolName = "-[ChatAddressBodyView requestData]"
-                  moduleName = "KulexiuForStudent"
-                  usesParentBreakpointCondition = "Yes"
-                  urlString = "file:///Users/wangzhi/DayaWorkspace/Klx_student/KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m"
-                  startingColumnNumber = "9223372036854775807"
-                  endingColumnNumber = "9223372036854775807"
-                  startingLineNumber = "127"
-                  endingLineNumber = "127"
-                  offsetFromSymbolStart = "348">
-               </Location>
-               <Location
-                  uuid = "36EDB858-B943-472A-B904-A4C60B222D3D - 1410eff7d7e023ab"
-                  shouldBeEnabled = "Yes"
-                  ignoreCount = "0"
-                  continueAfterRunningActions = "No"
-                  symbolName = "__34-[ChatAddressBodyView requestData]_block_invoke.33"
-                  moduleName = "KulexiuForStudent"
-                  usesParentBreakpointCondition = "Yes"
-                  urlString = "file:///Users/wangzhi/DayaWorkspace/Klx_student/KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m"
-                  startingColumnNumber = "9223372036854775807"
-                  endingColumnNumber = "9223372036854775807"
-                  startingLineNumber = "128"
-                  endingLineNumber = "128"
-                  offsetFromSymbolStart = "76">
-               </Location>
-            </Locations>
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "B53C8936-0246-4C10-A4ED-11D513BBA445"
+            uuid = "AA6465A8-5632-47BC-B900-486CE81013FB"
             shouldBeEnabled = "Yes"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            breakpointStackSelectionBehavior = "1"
-            scope = "1"
-            stopOnStyle = "1">
+            filePath = "KulexiuForStudent/Module/Chat/View/ShareMusicCellContentView.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "57"
+            endingLineNumber = "57"
+            landmarkName = "-configWithSongName:type:authName:sendAvatar:sendName:userId:tags:"
+            landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "09C10380-97EA-4BF2-9EA5-659F5FD75E81"
+            uuid = "3BA78656-E0B8-45EB-BDD5-8F4D055637B3"
             shouldBeEnabled = "Yes"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Module/Home/Controller/HomeViewController.m"
+            filePath = "KulexiuForStudent/Module/Chat/View/KSChatMusicShareCell.m"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "727"
-            endingLineNumber = "727"
-            landmarkName = "-requestInformationList"
+            startingLineNumber = "68"
+            endingLineNumber = "68"
+            landmarkName = "-setDataModel:"
             landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>

+ 1 - 1
KulexiuForStudent/KulexiuForStudent/AppDelegate.m

@@ -302,7 +302,7 @@
     RCKitConfigCenter.ui.globalMessagePortraitSize = CGSizeMake(40, 40);
     // 会话列表头像设置
     RCKitConfigCenter.ui.globalConversationAvatarStyle = RC_USER_AVATAR_RECTANGLE;
-    RCKitConfigCenter.ui.globalConversationPortraitSize = CGSizeMake(48, 48);
+    RCKitConfigCenter.ui.globalConversationPortraitSize = CGSizeMake(44, 44);
     
     //开启消息撤回功能
     RCKitConfigCenter.message.enableMessageRecall = YES;

+ 6 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/Contents.json

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

+ 2 - 2
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_ownerList.imageset/Contents.json → KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentList.imageset/Contents.json

@@ -5,12 +5,12 @@
       "scale" : "1x"
     },
     {
-      "filename" : "group_ownerList@2x.png",
+      "filename" : "chat_talentList@2x.png",
       "idiom" : "universal",
       "scale" : "2x"
     },
     {
-      "filename" : "group_ownerList@3x.png",
+      "filename" : "chat_talentList@3x.png",
       "idiom" : "universal",
       "scale" : "3x"
     }

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentList.imageset/chat_talentList@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentList.imageset/chat_talentList@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentTag.imageset/Contents.json

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

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentTag.imageset/chat_talentTag@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/chat_talentTag.imageset/chat_talentTag@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerList.imageset/Contents.json

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

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerList.imageset/chat_ownerList@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerList.imageset/chat_ownerList@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerTag.imageset/Contents.json

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

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerTag.imageset/group_ownerTag@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/ChatTag/group_ownerTag.imageset/group_ownerTag@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_talentTag.imageset/Contents.json

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

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_talentTag.imageset/chat_talentTag@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_talentTag.imageset/chat_talentTag@3x.png


+ 2 - 2
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_owner.imageset/Contents.json → KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_use_sex.imageset/Contents.json

@@ -5,12 +5,12 @@
       "scale" : "1x"
     },
     {
-      "filename" : "group_owner@2x.png",
+      "filename" : "chat_use_sex@2x.png",
       "idiom" : "universal",
       "scale" : "2x"
     },
     {
-      "filename" : "group_owner@3x.png",
+      "filename" : "chat_use_sex@3x.png",
       "idiom" : "universal",
       "scale" : "3x"
     }

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_use_sex.imageset/chat_use_sex@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_use_sex.imageset/chat_use_sex@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_user_subject.imageset/Contents.json

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

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_user_subject.imageset/chat_user_subject@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/chat_user_subject.imageset/chat_user_subject@3x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_owner.imageset/group_owner@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_owner.imageset/group_owner@3x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_ownerList.imageset/group_ownerList@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/group_ownerList.imageset/group_ownerList@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/user_detailBg.imageset/Contents.json

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

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/user_detailBg.imageset/user_detailBg@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Chat/user_detailBg.imageset/user_detailBg@3x.png


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

@@ -633,6 +633,14 @@ NS_ASSUME_NONNULL_BEGIN
 /// @param faliure 失败
 + (void)homeMusicListRequest:(NSString *)post version:(NSString *)version success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
 
+// /api-student/music/sheet/appMusicSheet
+/// 首页曲目数据
+/// @param post post
+/// @param version version
+/// @param success 成功
+/// @param faliure 失败
++ (void)homeAppMusicSheetRequest:(NSString *)post version:(NSString *)version success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
 // /api-student/teacher/queryHotTeacherList
 
 /// 推荐老师列表
@@ -869,6 +877,25 @@ NS_ASSUME_NONNULL_BEGIN
 /// @param success 成功
 /// @param faliure 失败
 + (void)checkReceiveRewardRequest:(NSString *)get success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
+
+// api-student/student/queryUserById 参数 rongCloudUserId
+
+/// 查询指定学员信息-融云token
+/// @param get get
+/// @param rongCloudUserId rongCloudUserId
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryUserById:(NSString *)get rongCloudUserId:(NSString *)rongCloudUserId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
+// /api-student/music/sheet/user/practice
+/// 查看指定最近练习记录
+/// @param get get
+/// @param userId 用户id
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryUserRecentRequest:(NSString *)get userId:(NSString *)userId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure;
+
 @end
 
 NS_ASSUME_NONNULL_END

+ 48 - 2
KulexiuForStudent/KulexiuForStudent/Common/Base/KSNetworkingManager.m

@@ -801,7 +801,7 @@
 
 // /api-student/imGroup/queryAll
 
-/// 查询老师群组列表
+/// 查询群组列表
 /// @param post post
 /// @param search 搜索
 /// @param success 成功
@@ -923,7 +923,6 @@
 + (void)sysImComplaintRequest:(NSString *)post type:(NSString *)type fileUrl:(NSString *)fileUrl memo:(NSString *)memo targetId:(NSString *)targetId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
     [self configRequestMethodJSON];
     NSString *url = [NSString stringWithFormat:@"%@%@", hostURL, @"/api-student/sysImComplaint/add"];
-//    targetId = [self returnNoContainGroupId:targetId];
     NSMutableDictionary *parm = [NSMutableDictionary dictionary];
     [parm setValue:type forKey:@"type"];
     [parm setValue:fileUrl forKey:@"url"];
@@ -1325,6 +1324,26 @@
 }
 
 
+// /api-student/music/sheet/appMusicSheet
+/// 首页曲目数据
+/// @param post post
+/// @param version version
+/// @param success 成功
+/// @param faliure 失败
++ (void)homeAppMusicSheetRequest:(NSString *)post version:(NSString *)version success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    [self configRequestMethodJSON];
+    NSString *url = [NSString stringWithFormat:@"%@%@", hostURL, @"/api-student/music/sheet/appMusicSheet"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:@(NO) forKey:@"myself"];
+    [parm setValue:@"PASS" forKey:@"auditStatus"];
+    [parm setValue:@(1) forKey:@"page"];
+    [parm setValue:@(21) forKey:@"rows"];
+    [parm setValue:version forKey:@"version"];
+    [parm setValue:@"ios-student" forKey:@"platform"];
+    [self request:post andWithUrl:url and:parm success:success faliure:faliure];
+}
+
+
 
 // /api-student/teacher/queryHotTeacherList
 
@@ -1695,4 +1714,31 @@
     [self request:get andWithUrl:url and:nil success:success faliure:faliure];
 }
 
+// api-student/student/queryUserById 参数 rongCloudUserId
+
+/// 查询指定学员信息-融云token
+/// @param get get
+/// @param rongCloudUserId rongCloudUserId
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryUserById:(NSString *)get rongCloudUserId:(NSString *)rongCloudUserId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    NSString *url = [NSString stringWithFormat:@"%@%@", hostURL, @"/api-student/student/queryUserById"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:rongCloudUserId forKey:@"rongCloudUserId"];
+    [self request:get andWithUrl:url and:parm success:success faliure:faliure];
+}
+
+// /api-student/music/sheet/user/practice
+/// 查看指定最近练习记录
+/// @param get get
+/// @param userId 用户id
+/// @param success 成功
+/// @param faliure 失败
++ (void)queryUserRecentRequest:(NSString *)get userId:(NSString *)userId success:(void(^)(NSDictionary *dic))success faliure:(void(^)(NSError *error))faliure {
+    NSString *url = [NSString stringWithFormat:@"%@%@", hostURL, @"/api-student/music/sheet/user/practice"];
+    NSMutableDictionary *parm = [NSMutableDictionary dictionary];
+    [parm setValue:userId forKey:@"userId"];
+    [self request:get andWithUrl:url and:parm success:success faliure:faliure];
+}
+
 @end

+ 10 - 2
KulexiuForStudent/KulexiuForStudent/Common/Base/KSRCIMDataSource.m

@@ -82,6 +82,10 @@
                 
                 NSDictionary *userDic = [dic dictionaryValueForKey:@"data"];
                 RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:userId name:[userDic stringValueForKey:@"friendNickname"] portrait:[userDic stringValueForKey:@"friendAvatar"]];
+                // 附加字段
+                NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
+                [extraDic setValue:[userDic stringValueForKey:@"roleType"] forKey:@"role"];
+                user.extra = [extraDic mj_JSONString];
                 completion(user);
             }
             else {
@@ -94,7 +98,7 @@
         }];
     }
     else {
-        RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:UserDefault(UIDKey) name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
+        RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:UserDefault(RongCloudID) name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
         return completion(user);
     }
 }
@@ -114,9 +118,13 @@
             NSDictionary *result = [dic dictionaryValueForKey:@"data"];
             NSString *name = [result stringValueForKey:@"nickname"];
             RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:userId name:name portrait:[result stringValueForKey:@"avatar"]];
+            // 附加字段
+            NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
             if ([result boolValueForKey:@"isAdmin"]) {
-                user.extra = @"owner";
+                [extraDic setValue:@"owner" forKey:@"groupOwner"];
             }
+            [extraDic setValue:[result stringValueForKey:@"roleType"] forKey:@"role"];
+            user.extra = [extraDic mj_JSONString];
             completion(user);
         }
         else {

+ 14 - 14
KulexiuForStudent/KulexiuForStudent/Common/Define/PrefixHeader.pch

@@ -139,13 +139,13 @@ shouldPrevent = NO; \
 
 //#ifdef DEBUG
 
-//#define hostURL (@"https://dev.colexiu.com")
-//#define SEALCLASSHOST (@"https://dev.colexiu.com/api-classroom")
-//#define WEBHOST (@"https://dev.colexiu.com/student")
-//#define SOCKET_URL (@"wss://dev.colexiu.com/audioAnalysis")
-//#define JSPUSH_ENVIRONMENT (NO)
-//#define RCIM_KEY (@"0vnjpoad0jbdz")
-//#define SUBMIT_UUID (YES)
+#define hostURL (@"https://dev.colexiu.com")
+#define SEALCLASSHOST (@"https://dev.colexiu.com/api-classroom")
+#define WEBHOST (@"https://dev.colexiu.com/student")
+#define SOCKET_URL (@"wss://dev.colexiu.com/audioAnalysis")
+#define JSPUSH_ENVIRONMENT (NO)
+#define RCIM_KEY (@"0vnjpoad0jbdz")
+#define SUBMIT_UUID (YES)
 
 // 预生产环境
 //#define hostURL (@"https://ponline.colexiu.com")
@@ -158,13 +158,13 @@ shouldPrevent = NO; \
 
 //#else
 
-#define hostURL (@"https://online.colexiu.com")
-#define SEALCLASSHOST (@"https://online.colexiu.com/api-classroom")
-#define WEBHOST (@"https://online.colexiu.com/student")
-#define SOCKET_URL (@"wss://online.colexiu.com/audioAnalysis")
-#define JSPUSH_ENVIRONMENT (YES)
-#define RCIM_KEY (@"e5t4ouvpe42pa")
-#define SUBMIT_UUID (YES)
+//#define hostURL (@"https://online.colexiu.com")
+//#define SEALCLASSHOST (@"https://online.colexiu.com/api-classroom")
+//#define WEBHOST (@"https://online.colexiu.com/student")
+//#define SOCKET_URL (@"wss://online.colexiu.com/audioAnalysis")
+//#define JSPUSH_ENVIRONMENT (YES)
+//#define RCIM_KEY (@"e5t4ouvpe42pa")
+//#define SUBMIT_UUID (YES)
 
 //#endif
 

+ 5 - 1
KulexiuForStudent/KulexiuForStudent/Common/Define/UserKeyHeader.h

@@ -68,8 +68,12 @@
 // 老师类型
 #define TeacherTypeKey (@"teacher_type")
 
-// UID (融云使用)
+// userId 用户id
 #define UIDKey (@"UID")
+
+// 融云ID
+#define RongCloudID (@"RongCloudID")
+
 //用户token
 #define TokenKey  (@"access_token")
 

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/ChatAddressViewController.m

@@ -191,6 +191,7 @@
     ChatAddressBodyView *listView = self.listViewArray[selectedIndex];
     NSString *searchKey = listView.searchKey;
     self.headView.searchField.text = searchKey;
+    [self.view endEditing:YES];
 }
 
 

+ 104 - 12
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatConversationViewController.m

@@ -27,6 +27,7 @@
 
 #import "KSPublicAlertView.h"
 #import "KSGroupTagImageView.h"
+#import "KSChatUserDetailViewController.h"
 
 #define SHARE_MUSIC_TAG (2001)
 
@@ -327,6 +328,11 @@
                 if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
                     NSDictionary *userDic = [dic dictionaryValueForKey:@"data"];
                     RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:self.targetId name:[userDic stringValueForKey:@"friendNickname"] portrait:[userDic stringValueForKey:@"friendAvatar"]];
+                    // 附加字段
+                    NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
+                    [extraDic setValue:[userDic stringValueForKey:@"roleType"] forKey:@"role"];
+                    user.extra = [extraDic mj_JSONString];
+                    
                     [[RCIM sharedRCIM] refreshUserInfoCache:user withUserId:self.targetId];
                     [self refreshTitle];
                 }
@@ -350,11 +356,16 @@
                     }
                     GroupMemberModel *model = [[GroupMemberModel alloc] initWithDictionary:parm];
                     // 刷新缓存
-                    RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.userId name:model.nickname portrait:model.avatar];
+                    RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.imUserId name:model.nickname portrait:model.avatar];
+                    // 附加字段
+                    NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
                     if (model.isAdmin) {
-                        user.extra = @"owner";
+                        [extraDic setValue:@"owner" forKey:@"groupOwner"];
                     }
-                    [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.userId withGroupId:self.targetId];
+                    [extraDic setValue:model.roleType forKey:@"role"];
+                    user.extra = [extraDic mj_JSONString];
+                    
+                    [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.imUserId withGroupId:self.targetId];
                 }
             }
             else {
@@ -398,14 +409,12 @@
     if (self.conversationType == ConversationType_GROUP) {
         RCGroup *group = [[RCIM sharedRCIM] getGroupInfoCache:self.targetId];
         if (![NSString isEmptyString:group.groupName]) {
-//            self.title = group.groupName;
             [self allocTitle:group.groupName withColor:[UIColor blackColor]];
         }
     }
     else {
         RCUserInfo *userInfo = [[RCIM sharedRCIM] getUserInfoCache:self.targetId];
         if (![NSString isEmptyString:userInfo.name]) {
-//            self.title = userInfo.name;
             [self allocTitle:userInfo.name withColor:[UIColor blackColor]];
         }
     }
@@ -443,22 +452,62 @@
             for (UIView *subView in contentView.subviews) {
                 if ([subView isKindOfClass:[KSGroupTagImageView class]]) {
                     [subView removeFromSuperview];
-                    break;
                 }
             }
             RCUserInfo *user = [[RCIM sharedRCIM] getGroupUserInfoCache:model.senderUserId withGroupId:self.targetId];
-            if ([user.extra isEqualToString:@"owner"]) {
-                KSGroupTagImageView *avatarImage = [[KSGroupTagImageView alloc] initWithImage:[UIImage imageNamed:@"group_owner"]];
+            NSDictionary *extraDic = [user.extra mj_JSONObject];
+            
+            if ([[extraDic stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
+                KSGroupTagImageView *avatarImage = [[KSGroupTagImageView alloc] initWithImage:[UIImage imageNamed:@"chat_talentTag"]];
                 [contentView addSubview:avatarImage];
                 [avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
-                    make.width.mas_equalTo(36);
-                    make.height.mas_equalTo(16);
+                    make.width.mas_equalTo(40);
+                    make.height.mas_equalTo(13);
                     make.centerX.mas_equalTo(imageView.mas_centerX);
-                    make.centerY.mas_equalTo(imageView.mas_bottom);
+                    make.bottom.mas_equalTo(imageView.mas_bottom);
+                }];
+            }
+            // owner
+            if ([[extraDic stringValueForKey:@"groupOwner"] isEqualToString:@"owner"]) {
+                
+                RCMessageCell *baseCell = (RCMessageCell *)cell;
+                
+                KSGroupTagImageView *ownerTagView = [[KSGroupTagImageView alloc] initWithImage:[UIImage imageNamed:@"group_ownerTag"]];
+                [contentView addSubview:ownerTagView];
+                [ownerTagView mas_makeConstraints:^(MASConstraintMaker *make) {
+                    make.width.mas_equalTo(24);
+                    make.height.mas_equalTo(14);
+                    make.centerY.mas_equalTo(baseCell.nicknameLabel.mas_centerY);
+                    make.left.mas_equalTo(baseCell.bubbleBackgroundView.mas_left);
+                }];
+                [baseCell.nicknameLabel mas_updateConstraints:^(MASConstraintMaker *make) {
+                    make.left.mas_equalTo(ownerTagView.mas_right).offset(4);
+                }];
+            }
+            
+        }
+        else if (self.conversationType == ConversationType_PRIVATE) {
+            UIView *contentView = (UIView *)((RCMessageCell *)cell).messageContentView;
+            for (UIView *subView in contentView.subviews) {
+                if ([subView isKindOfClass:[KSGroupTagImageView class]]) {
+                    [subView removeFromSuperview];
+                    break;
+                }
+            }
+            RCMessageModel *model = self.conversationDataRepository[indexPath.row];
+            RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:model.senderUserId];
+            NSDictionary *extraDic = [user.extra mj_JSONObject];
+            if ([[extraDic stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
+                KSGroupTagImageView *avatarImage = [[KSGroupTagImageView alloc] initWithImage:[UIImage imageNamed:@"chat_talentTag"]];
+                [contentView addSubview:avatarImage];
+                [avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
+                    make.width.mas_equalTo(40);
+                    make.height.mas_equalTo(13);
+                    make.centerX.mas_equalTo(imageView.mas_centerX);
+                    make.bottom.mas_equalTo(imageView.mas_bottom);
                 }];
             }
         }
-        
     }
 }
 
@@ -738,6 +787,49 @@
     return path;
 }
 
+- (void)didTapCellPortrait:(NSString *)userId {
+    if ([userId isEqualToString:UserDefault(RongCloudID)]) {
+        [self displayStudent:userId];
+    }
+    else {
+        RCUserInfo *user = nil;
+        if (self.conversationType == ConversationType_PRIVATE) {
+            RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:userId];
+            
+            NSDictionary *extraDic = [user.extra mj_JSONObject];
+            if ([[extraDic stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
+                [self displayTeacher:userId];
+            }
+            else {
+                [self displayStudent:userId];
+            }
+        }
+        else {
+            RCUserInfo *user = [[RCIM sharedRCIM] getGroupUserInfoCache:userId withGroupId:self.targetId];
+            NSDictionary *extraDic = [user.extra mj_JSONObject];
+            if ([[extraDic stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
+                [self displayTeacher:userId];
+            }
+            else {
+                [self displayStudent:userId];
+            }
+        }
+        
+    }
+}
+
+- (void)displayStudent:(NSString *)stuentId {
+    KSChatUserDetailViewController *ctrl = [[KSChatUserDetailViewController alloc] init];
+    ctrl.rongCloudId = stuentId;
+    [self.navigationController pushViewController:ctrl animated:YES];
+}
+
+- (void)displayTeacher:(NSString *)teacherId {
+    KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
+    ctrl.url = [NSString stringWithFormat:@"%@%@%@", WEBHOST, @"/#/teacherHome?teacherId=",teacherId];
+    [self.navigationController pushViewController:ctrl animated:YES];
+}
+
 /*
 #pragma mark - Navigation
 

+ 22 - 2
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatListViewController.m

@@ -11,7 +11,7 @@
 #import "KSSearchHistoryMessageController.h"
 #import "KSChatConversationViewController.h"
 #import "KSTabBarViewController.h"
-#import "KSChatListCell.h"
+#import "KSChatTagView.h"
 
 @interface KSChatListViewController ()
 
@@ -180,7 +180,11 @@
     UIView *tagView = (UIView *)((RCConversationCell *)cell).conversationTagView;
     imageView.contentMode = UIViewContentModeScaleAspectFill;
     imageView.layer.masksToBounds = YES;
-    
+    for (UIView *view in cell.contentView.subviews) {
+        if ([view isKindOfClass:[KSChatTagView class]]) {
+            [view removeFromSuperview];
+        }
+    }
     RCConversationModel *model = self.conversationListDataSource[indexPath.row];
     if (model.conversationType == ConversationType_GROUP) {
         if ([model.targetId containsString:@"FAN"]) { // 粉丝群
@@ -198,6 +202,22 @@
             tagImage.frame = CGRectMake(0, 2, 45, 17);
         }
     }
+    else if (model.conversationType == ConversationType_PRIVATE) {
+        UIView *contentView = (UIView *)((RCConversationCell *)cell).contentView;
+        RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:model.targetId];
+        NSDictionary *extraDic = [user.extra mj_JSONObject];
+        if ([[extraDic stringValueForKey:@"role"] isEqualToString:@"TEACHER"]) {
+            KSChatTagView *avatarImage = [[KSChatTagView alloc] initWithImage:[UIImage imageNamed:@"chat_talentList"]];
+            [contentView addSubview:avatarImage];
+            [avatarImage mas_makeConstraints:^(MASConstraintMaker *make) {
+                make.width.mas_equalTo(44);
+                make.height.mas_equalTo(13);
+                make.centerX.mas_equalTo(imageView.mas_centerX);
+                make.bottom.mas_equalTo(imageView.mas_bottom);
+            }];
+        }
+        
+    }
 }
 
 - (UIView *)stateView {

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatUserDetailViewController.h

@@ -0,0 +1,18 @@
+//
+//  KSChatUserDetailViewController.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import "KSBaseViewController.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSChatUserDetailViewController : KSBaseViewController
+
+@property (nonatomic, strong) NSString *rongCloudId;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 175 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Controller/KSChatUserDetailViewController.m

@@ -0,0 +1,175 @@
+//
+//  KSChatUserDetailViewController.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import "KSChatUserDetailViewController.h"
+#import "UserDetailNavView.h"
+#import "ChatUserInfo.h"
+#import "UserDetailBodyView.h"
+#import "UserDetailBottomView.h"
+#import "RecentPracticeModel.h"
+#import "KSBaseWKWebViewController.h"
+
+@interface KSChatUserDetailViewController ()<UIScrollViewDelegate>
+
+@property (nonatomic, strong) UserDetailNavView *navView;
+
+@property (nonatomic, strong) ChatUserInfo *userInfo;
+
+@property (nonatomic, strong) UserDetailBodyView *bodyView;
+
+@property (nonatomic, strong) UserDetailBottomView *bottomView;
+@end
+
+@implementation KSChatUserDetailViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.ks_prefersNavigationBarHidden = YES;
+    [self configUI];
+    
+}
+
+- (void)configUI {
+    
+    UIImage *bgImage = [UIImage imageNamed:@"user_detailBg"];
+    CGFloat height = bgImage.size.height / bgImage.size.width * kScreenWidth;
+    UIImageView *imageView = [[UIImageView alloc] initWithImage:bgImage];
+    imageView.frame = CGRectMake(0, 0, kScreenWidth, height);
+    [self.view addSubview:imageView];
+    
+    [self.view addSubview:self.navView];
+    
+    self.scrollView.backgroundColor = [UIColor clearColor];
+    self.scrollView.delegate = self;
+    
+    [self.view bringSubviewToFront:self.scrollView];
+    [self.view bringSubviewToFront:self.navView];
+    [self.scrollView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.top.mas_equalTo(self.view.mas_top);
+        make.left.right.mas_equalTo(self.view);
+        make.bottom.mas_equalTo(self.view.mas_bottom);
+    }];
+    
+    UIView *headView = [[UIView alloc] init];
+    headView.backgroundColor = [UIColor clearColor];
+    [self.scrollView addSubview:headView];
+    [headView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.mas_equalTo(self.scrollView.mas_top);
+        make.left.right.mas_equalTo(self.view);
+        make.height.mas_equalTo(kNaviBarHeight);
+    }];
+    
+    [self.view addSubview:self.bodyView];
+    CGFloat bodyViewHeight = [UserDetailBodyView getViewHeight];
+    if (bodyViewHeight < KPortraitHeight - kNaviBarHeight - 70) {
+        bodyViewHeight = KPortraitHeight - kNaviBarHeight - 70;
+    }
+    [self.bodyView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.mas_equalTo(headView.mas_bottom);
+        make.left.right.mas_equalTo(self.view);
+        make.height.mas_equalTo(bodyViewHeight);
+    }];
+    [self.view addSubview:self.bottomView];
+    [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.mas_equalTo(self.view);
+        make.top.mas_equalTo(self.bodyView.mas_bottom);
+        make.bottom.mas_equalTo(self.scrollView.mas_bottom);
+        make.height.mas_equalTo(70);
+    }];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    [self requestUserMessage];
+}
+
+- (void)requestUserMessage {
+    [self showhud];
+    [KSNetworkingManager queryUserById:KS_GET rongCloudUserId:self.rongCloudId success:^(NSDictionary * _Nonnull dic) {
+        if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
+            self.userInfo = [[ChatUserInfo alloc] initWithDictionary:[dic dictionaryValueForKey:@"data"]];
+            [self requestRecentPractice];
+        }
+        else {
+            
+        }
+        
+    } faliure:^(NSError * _Nonnull error) {
+        [self removehub];
+    }];
+}
+
+- (void)requestRecentPractice {
+    
+    [KSNetworkingManager queryUserRecentRequest:KS_GET userId:[NSString stringWithFormat:@"%.0f",self.userInfo.userId] success:^(NSDictionary * _Nonnull dic) {
+        [self removehub];
+        NSLog(@"%@", [dic mj_JSONString]);
+        if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
+            NSArray *sourceArray = [[dic dictionaryValueForKey:@"data"] arrayValueForKey:@"rows"];
+            [self evaluateSource:sourceArray];
+        }
+        else {
+            
+        }
+    } faliure:^(NSError * _Nonnull error) {
+        [self removehub];
+    }];
+}
+
+- (void)evaluateSource:(NSArray *)musicArray {
+    NSMutableArray *source = [NSMutableArray array];
+    for (NSDictionary *dic in musicArray) {
+        RecentPracticeModel *model = [[RecentPracticeModel alloc] initWithDictionary:dic];
+        [source addObject:model];
+    }
+    MJWeakSelf;
+    [self.bodyView configUserMessage:self.userInfo musicArray:source callback:^(NSString *songId) {
+        KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
+        ctrl.url = [NSString stringWithFormat:@"%@%@%@", WEBHOST, @"/#/music-detail?id=",songId];
+        [weakSelf.navigationController pushViewController:ctrl animated:YES];
+    }];
+}
+
+#pragma mark ----- lazying
+
+- (UserDetailNavView *)navView {
+    if (!_navView) {
+        _navView = [UserDetailNavView shareInstance];
+        MJWeakSelf;
+        [_navView navAction:^{
+            [weakSelf backAction];
+        }];
+    }
+    return _navView;
+}
+
+- (UserDetailBodyView *)bodyView {
+    if (!_bodyView) {
+        _bodyView = [UserDetailBodyView shareInstance];
+        
+    }
+    return _bodyView;
+}
+
+- (UserDetailBottomView *)bottomView {
+    if (!_bottomView) {
+        _bottomView = [UserDetailBottomView shareInstance];
+    }
+    return _bottomView;
+}
+/*
+#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

+ 7 - 3
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupMemberViewController.m

@@ -55,11 +55,15 @@
                 [self.sourceArray addObject:model];
                 
                 // 刷新缓存
-                RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.userId name:model.nickname portrait:model.avatar];
+                RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.imUserId name:model.nickname portrait:model.avatar];
+                // 附加字段
+                NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
                 if (model.isAdmin) {
-                    user.extra = @"owner";
+                    [extraDic setValue:@"owner" forKey:@"groupOwner"];
                 }
-                [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.userId withGroupId:self.groupId];
+                [extraDic setValue:model.roleType forKey:@"role"];
+                user.extra = [extraDic mj_JSONString];
+                [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.imUserId withGroupId:self.groupId];
             }
             [self evaluateMessge];
         }

+ 8 - 3
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/Controller/GroupSettingViewController.m

@@ -98,11 +98,16 @@
                 [self.sourceArray addObject:model];
                 
                 // 刷新缓存
-                RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.userId name:model.nickname portrait:model.avatar];
+                RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:model.imUserId name:model.nickname portrait:model.avatar];
+                // 附加字段
+                NSMutableDictionary *extraDic = [NSMutableDictionary dictionary];
                 if (model.isAdmin) {
-                    user.extra = @"owner";
+                    [extraDic setValue:@"owner" forKey:@"groupOwner"];
                 }
-                [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.userId withGroupId:self.groupId];
+                [extraDic setValue:model.roleType forKey:@"role"];
+                user.extra = [extraDic mj_JSONString];
+                
+                [[RCIM sharedRCIM] refreshGroupUserInfoCache:user withUserId:model.imUserId withGroupId:self.groupId];
             }
             [self evaluateMessge];
         }

+ 8 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupMemberListCell.m

@@ -18,6 +18,8 @@
 
 @property (weak, nonatomic) IBOutlet UILabel *memberName;
 
+@property (weak, nonatomic) IBOutlet UIImageView *typeView;
+
 @property (nonatomic, copy) ChatCallback callback;
 
 @property (nonatomic, strong) GroupMemberModel *sourceModel;
@@ -65,6 +67,12 @@
             self.ownerWidth.constant = 0.0f;
             self.ownerImage.hidden = YES;
         }
+        if ([model.roleType isEqualToString:@"TEACHER"]) {
+            self.typeView.hidden = NO;
+        }
+        else {
+            self.typeView.hidden = YES;
+        }
     }
 }
 - (IBAction)chatAction:(id)sender {

+ 14 - 3
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupMemberListCell.xib

@@ -1,9 +1,9 @@
 <?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">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" 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"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
         <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"/>
@@ -29,7 +29,7 @@
                                 </constraints>
                                 <userDefinedRuntimeAttributes>
                                     <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                        <real key="value" value="6"/>
+                                        <real key="value" value="4"/>
                                     </userDefinedRuntimeAttribute>
                                 </userDefinedRuntimeAttributes>
                             </imageView>
@@ -61,13 +61,22 @@
                                     <constraint firstAttribute="height" constant="18" id="yGQ-mL-173"/>
                                 </constraints>
                             </imageView>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_talentList" translatesAutoresizingMaskIntoConstraints="NO" id="V3Z-gz-k2w">
+                                <rect key="frame" x="14" y="40" width="44" height="14"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="44" id="1WR-Pc-gtP"/>
+                                    <constraint firstAttribute="height" constant="14" id="S1M-3m-wGg"/>
+                                </constraints>
+                            </imageView>
                         </subviews>
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <constraints>
                             <constraint firstItem="Vhp-Wi-YsA" firstAttribute="centerY" secondItem="GW3-Oz-aPr" secondAttribute="centerY" id="4jm-Nc-ex4"/>
                             <constraint firstItem="C2d-wO-ajH" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Vhp-Wi-YsA" secondAttribute="trailing" constant="12" id="Aoh-be-l3n"/>
                             <constraint firstItem="GW3-Oz-aPr" firstAttribute="centerY" secondItem="3bd-Vo-rTM" secondAttribute="centerY" id="Mw8-KH-Nlc"/>
+                            <constraint firstItem="V3Z-gz-k2w" firstAttribute="bottom" secondItem="GW3-Oz-aPr" secondAttribute="bottom" id="XDN-3Q-VsG"/>
                             <constraint firstAttribute="trailing" secondItem="C2d-wO-ajH" secondAttribute="trailing" constant="14" id="a77-uB-Due"/>
+                            <constraint firstItem="V3Z-gz-k2w" firstAttribute="centerX" secondItem="GW3-Oz-aPr" secondAttribute="centerX" id="cQw-k2-Hvh"/>
                             <constraint firstItem="C2d-wO-ajH" firstAttribute="centerY" secondItem="Vhp-Wi-YsA" secondAttribute="centerY" id="cZb-Vp-Luy"/>
                             <constraint firstItem="GW3-Oz-aPr" firstAttribute="leading" secondItem="3bd-Vo-rTM" secondAttribute="leading" constant="14" id="g2u-Nh-Bgq"/>
                             <constraint firstItem="Vhp-Wi-YsA" firstAttribute="leading" secondItem="qqr-xe-xWm" secondAttribute="trailing" constant="4" id="qXP-PU-oDm"/>
@@ -97,12 +106,14 @@
                 <outlet property="nameLeft" destination="qXP-PU-oDm" id="xZu-cz-adF"/>
                 <outlet property="ownerImage" destination="qqr-xe-xWm" id="1qi-YL-kwV"/>
                 <outlet property="ownerWidth" destination="d6B-m0-bcK" id="Yus-cM-ofV"/>
+                <outlet property="typeView" destination="V3Z-gz-k2w" id="OnM-Id-B8X"/>
             </connections>
             <point key="canvasLocation" x="131.8840579710145" y="63.616071428571423"/>
         </tableViewCell>
     </objects>
     <resources>
         <image name="chat_chat" width="19" height="18"/>
+        <image name="chat_talentList" width="44" height="14"/>
         <image name="group_ownerList" width="34" height="18"/>
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>

+ 22 - 4
KulexiuForStudent/KulexiuForStudent/Module/Chat/Group/View/GroupSettingBodyView.m

@@ -19,9 +19,11 @@ typedef void(^ChooseMemberCallback)(NSString *targetId);
 
 @property (nonatomic, strong) NSString *targetId;
 
+@property (nonatomic, strong) UIImageView *roleTypeView;
+
 @property (nonatomic, copy) ChooseMemberCallback callback;
 
-- (void)configMemberWithUrl:(NSString *)url name:(NSString *)name targetId:(NSString *)targetId callback:(ChooseMemberCallback)callback;
+- (void)configMemberWithUrl:(NSString *)url name:(NSString *)name targetId:(NSString *)targetId roleType:(NSString *)roleType callback:(ChooseMemberCallback)callback;
 
 @end
 
@@ -52,7 +54,7 @@ typedef void(^ChooseMemberCallback)(NSString *targetId);
     
     
     self.memberLogo = [[UIImageView alloc] init];
-    self.memberLogo.layer.cornerRadius = 6;
+    self.memberLogo.layer.cornerRadius = 4;
     self.memberLogo.layer.masksToBounds = YES;
     self.memberLogo.contentMode = UIViewContentModeScaleAspectFill;
     
@@ -65,6 +67,16 @@ typedef void(^ChooseMemberCallback)(NSString *targetId);
     UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
     [self addGestureRecognizer:tapGesture];
     
+    self.roleTypeView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"chat_talentTag"]];
+    [self addSubview:self.roleTypeView];
+    [self.roleTypeView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.width.mas_equalTo(40);
+        make.centerX.mas_equalTo(self.memberLogo.mas_centerX);
+        make.height.mas_equalTo(13);
+        make.bottom.mas_equalTo(self.memberLogo.mas_bottom);
+    }];
+    self.roleTypeView.hidden = YES;
+    
 }
 
 - (void)tapAction:(UITapGestureRecognizer *)gesture {
@@ -73,13 +85,19 @@ typedef void(^ChooseMemberCallback)(NSString *targetId);
     }
 }
 
-- (void)configMemberWithUrl:(NSString *)url name:(NSString *)name targetId:(NSString *)targetId  callback:(ChooseMemberCallback)callback {
+- (void)configMemberWithUrl:(NSString *)url name:(NSString *)name targetId:(NSString *)targetId roleType:(NSString *)roleType callback:(ChooseMemberCallback)callback {
     if (callback) {
         self.callback = callback;
     }
     [self.memberLogo sd_setImageWithURL:[NSURL URLWithString:[url getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:CHAT_USER_DEFAULT_LOGO]];
     self.memberLabel.text = [NSString returnNoNullStringWithString:name];
     self.targetId = targetId;
+    if ([roleType isEqualToString:@"TEACHER"]) {
+        self.roleTypeView.hidden = NO;
+    }
+    else {
+        self.roleTypeView.hidden = YES;
+    }
 }
 @end
 
@@ -158,7 +176,7 @@ typedef void(^ChooseMemberCallback)(NSString *targetId);
         GroupMemberModel *model = [studentArray objectAtIndex:i];
         MemberView *view = [[MemberView alloc] initWithFrame:frame];
 
-        [view configMemberWithUrl:model.avatar name:model.nickname targetId:model.userId callback:^(NSString *targetId) {
+        [view configMemberWithUrl:model.avatar name:model.nickname targetId:model.imUserId roleType:model.roleType callback:^(NSString *targetId) {
 
         }];
         [self.memberView addSubview:view];

+ 44 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/ChatUserInfo.h

@@ -0,0 +1,44 @@
+//
+//  ChatUserInfo.h
+//
+//  Created by Steven  on 2022/10/18
+//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+
+@interface ChatUserInfo : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, assign) double userId;
+@property (nonatomic, assign) double isReal;
+@property (nonatomic, assign) double cloudStudySequenceDays;
+@property (nonatomic, strong) NSString *membershipStartTime;
+@property (nonatomic, strong) NSString *userStatus;
+@property (nonatomic, strong) NSString *membershipEndTime;
+@property (nonatomic, assign) double isVip;
+@property (nonatomic, assign) double lockFlag;
+@property (nonatomic, strong) NSString *updateTime;
+@property (nonatomic, strong) NSString *realName;
+@property (nonatomic, strong) NSString *userType;
+@property (nonatomic, assign) id delFlag;
+@property (nonatomic, strong) NSString *subjectName;
+@property (nonatomic, strong) NSString *cloudStudyUseLastDay;
+@property (nonatomic, assign) double memberRankSettingId;
+@property (nonatomic, assign) double gender;
+@property (nonatomic, strong) NSString *subjectId;
+@property (nonatomic, strong) NSString *birthdate;
+@property (nonatomic, strong) NSString *phone;
+@property (nonatomic, strong) NSString *idCardNo;
+@property (nonatomic, strong) NSString *avatar;
+@property (nonatomic, assign) double age;
+@property (nonatomic, strong) NSString *createTime;
+@property (nonatomic, strong) NSString *isBank;
+@property (nonatomic, strong) NSString *username;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 263 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/ChatUserInfo.m

@@ -0,0 +1,263 @@
+//
+//  ChatUserInfo.m
+//
+//  Created by Steven  on 2022/10/18
+//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//
+
+#import "ChatUserInfo.h"
+
+
+NSString *const kChatUserInfoUserId = @"userId";
+NSString *const kChatUserInfoIsReal = @"isReal";
+NSString *const kChatUserInfoCloudStudySequenceDays = @"cloudStudySequenceDays";
+NSString *const kChatUserInfoMembershipStartTime = @"membershipStartTime";
+NSString *const kChatUserInfoUserStatus = @"userStatus";
+NSString *const kChatUserInfoMembershipEndTime = @"membershipEndTime";
+NSString *const kChatUserInfoIsVip = @"isVip";
+NSString *const kChatUserInfoLockFlag = @"lockFlag";
+NSString *const kChatUserInfoUpdateTime = @"updateTime";
+NSString *const kChatUserInfoRealName = @"realName";
+NSString *const kChatUserInfoUserType = @"userType";
+NSString *const kChatUserInfoDelFlag = @"delFlag";
+NSString *const kChatUserInfoSubjectName = @"subjectName";
+NSString *const kChatUserInfoCloudStudyUseLastDay = @"cloudStudyUseLastDay";
+NSString *const kChatUserInfoMemberRankSettingId = @"memberRankSettingId";
+NSString *const kChatUserInfoGender = @"gender";
+NSString *const kChatUserInfoSubjectId = @"subjectId";
+NSString *const kChatUserInfoBirthdate = @"birthdate";
+NSString *const kChatUserInfoPhone = @"phone";
+NSString *const kChatUserInfoIdCardNo = @"idCardNo";
+NSString *const kChatUserInfoAvatar = @"avatar";
+NSString *const kChatUserInfoAge = @"age";
+NSString *const kChatUserInfoCreateTime = @"createTime";
+NSString *const kChatUserInfoIsBank = @"isBank";
+NSString *const kChatUserInfoUsername = @"username";
+
+
+@interface ChatUserInfo ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation ChatUserInfo
+
+@synthesize userId = _userId;
+@synthesize isReal = _isReal;
+@synthesize cloudStudySequenceDays = _cloudStudySequenceDays;
+@synthesize membershipStartTime = _membershipStartTime;
+@synthesize userStatus = _userStatus;
+@synthesize membershipEndTime = _membershipEndTime;
+@synthesize isVip = _isVip;
+@synthesize lockFlag = _lockFlag;
+@synthesize updateTime = _updateTime;
+@synthesize realName = _realName;
+@synthesize userType = _userType;
+@synthesize delFlag = _delFlag;
+@synthesize subjectName = _subjectName;
+@synthesize cloudStudyUseLastDay = _cloudStudyUseLastDay;
+@synthesize memberRankSettingId = _memberRankSettingId;
+@synthesize gender = _gender;
+@synthesize subjectId = _subjectId;
+@synthesize birthdate = _birthdate;
+@synthesize phone = _phone;
+@synthesize idCardNo = _idCardNo;
+@synthesize avatar = _avatar;
+@synthesize age = _age;
+@synthesize createTime = _createTime;
+@synthesize isBank = _isBank;
+@synthesize username = _username;
+
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
+{
+    return [[self alloc] initWithDictionary:dict];
+}
+
+- (instancetype)initWithDictionary:(NSDictionary *)dict
+{
+    self = [super init];
+    
+    // This check serves to make sure that a non-NSDictionary object
+    // passed into the model class doesn't break the parsing.
+    if(self && [dict isKindOfClass:[NSDictionary class]]) {
+            self.userId = [[self objectOrNilForKey:kChatUserInfoUserId fromDictionary:dict] doubleValue];
+            self.isReal = [[self objectOrNilForKey:kChatUserInfoIsReal fromDictionary:dict] doubleValue];
+            self.cloudStudySequenceDays = [[self objectOrNilForKey:kChatUserInfoCloudStudySequenceDays fromDictionary:dict] doubleValue];
+            self.membershipStartTime = [self objectOrNilForKey:kChatUserInfoMembershipStartTime fromDictionary:dict];
+            self.userStatus = [self objectOrNilForKey:kChatUserInfoUserStatus fromDictionary:dict];
+            self.membershipEndTime = [self objectOrNilForKey:kChatUserInfoMembershipEndTime fromDictionary:dict];
+            self.isVip = [[self objectOrNilForKey:kChatUserInfoIsVip fromDictionary:dict] doubleValue];
+            self.lockFlag = [[self objectOrNilForKey:kChatUserInfoLockFlag fromDictionary:dict] doubleValue];
+            self.updateTime = [self objectOrNilForKey:kChatUserInfoUpdateTime fromDictionary:dict];
+            self.realName = [self objectOrNilForKey:kChatUserInfoRealName fromDictionary:dict];
+            self.userType = [self objectOrNilForKey:kChatUserInfoUserType fromDictionary:dict];
+            self.delFlag = [self objectOrNilForKey:kChatUserInfoDelFlag fromDictionary:dict];
+            self.subjectName = [self objectOrNilForKey:kChatUserInfoSubjectName fromDictionary:dict];
+            self.cloudStudyUseLastDay = [self objectOrNilForKey:kChatUserInfoCloudStudyUseLastDay fromDictionary:dict];
+            self.memberRankSettingId = [[self objectOrNilForKey:kChatUserInfoMemberRankSettingId fromDictionary:dict] doubleValue];
+            self.gender = [[self objectOrNilForKey:kChatUserInfoGender fromDictionary:dict] doubleValue];
+            self.subjectId = [self objectOrNilForKey:kChatUserInfoSubjectId fromDictionary:dict];
+            self.birthdate = [self objectOrNilForKey:kChatUserInfoBirthdate fromDictionary:dict];
+            self.phone = [self objectOrNilForKey:kChatUserInfoPhone fromDictionary:dict];
+            self.idCardNo = [self objectOrNilForKey:kChatUserInfoIdCardNo fromDictionary:dict];
+            self.avatar = [self objectOrNilForKey:kChatUserInfoAvatar fromDictionary:dict];
+            self.age = [[self objectOrNilForKey:kChatUserInfoAge fromDictionary:dict] doubleValue];
+            self.createTime = [self objectOrNilForKey:kChatUserInfoCreateTime fromDictionary:dict];
+            self.isBank = [self objectOrNilForKey:kChatUserInfoIsBank fromDictionary:dict];
+            self.username = [self objectOrNilForKey:kChatUserInfoUsername fromDictionary:dict];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.userId] forKey:kChatUserInfoUserId];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.isReal] forKey:kChatUserInfoIsReal];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.cloudStudySequenceDays] forKey:kChatUserInfoCloudStudySequenceDays];
+    [mutableDict setValue:self.membershipStartTime forKey:kChatUserInfoMembershipStartTime];
+    [mutableDict setValue:self.userStatus forKey:kChatUserInfoUserStatus];
+    [mutableDict setValue:self.membershipEndTime forKey:kChatUserInfoMembershipEndTime];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.isVip] forKey:kChatUserInfoIsVip];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.lockFlag] forKey:kChatUserInfoLockFlag];
+    [mutableDict setValue:self.updateTime forKey:kChatUserInfoUpdateTime];
+    [mutableDict setValue:self.realName forKey:kChatUserInfoRealName];
+    [mutableDict setValue:self.userType forKey:kChatUserInfoUserType];
+    [mutableDict setValue:self.delFlag forKey:kChatUserInfoDelFlag];
+    [mutableDict setValue:self.subjectName forKey:kChatUserInfoSubjectName];
+    [mutableDict setValue:self.cloudStudyUseLastDay forKey:kChatUserInfoCloudStudyUseLastDay];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.memberRankSettingId] forKey:kChatUserInfoMemberRankSettingId];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.gender] forKey:kChatUserInfoGender];
+    [mutableDict setValue:self.subjectId forKey:kChatUserInfoSubjectId];
+    [mutableDict setValue:self.birthdate forKey:kChatUserInfoBirthdate];
+    [mutableDict setValue:self.phone forKey:kChatUserInfoPhone];
+    [mutableDict setValue:self.idCardNo forKey:kChatUserInfoIdCardNo];
+    [mutableDict setValue:self.avatar forKey:kChatUserInfoAvatar];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.age] forKey:kChatUserInfoAge];
+    [mutableDict setValue:self.createTime forKey:kChatUserInfoCreateTime];
+    [mutableDict setValue:self.isBank forKey:kChatUserInfoIsBank];
+    [mutableDict setValue:self.username forKey:kChatUserInfoUsername];
+
+    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];
+    return [object isEqual:[NSNull null]] ? nil : object;
+}
+
+
+#pragma mark - NSCoding Methods
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super init];
+
+    self.userId = [aDecoder decodeDoubleForKey:kChatUserInfoUserId];
+    self.isReal = [aDecoder decodeDoubleForKey:kChatUserInfoIsReal];
+    self.cloudStudySequenceDays = [aDecoder decodeDoubleForKey:kChatUserInfoCloudStudySequenceDays];
+    self.membershipStartTime = [aDecoder decodeObjectForKey:kChatUserInfoMembershipStartTime];
+    self.userStatus = [aDecoder decodeObjectForKey:kChatUserInfoUserStatus];
+    self.membershipEndTime = [aDecoder decodeObjectForKey:kChatUserInfoMembershipEndTime];
+    self.isVip = [aDecoder decodeDoubleForKey:kChatUserInfoIsVip];
+    self.lockFlag = [aDecoder decodeDoubleForKey:kChatUserInfoLockFlag];
+    self.updateTime = [aDecoder decodeObjectForKey:kChatUserInfoUpdateTime];
+    self.realName = [aDecoder decodeObjectForKey:kChatUserInfoRealName];
+    self.userType = [aDecoder decodeObjectForKey:kChatUserInfoUserType];
+    self.delFlag = [aDecoder decodeObjectForKey:kChatUserInfoDelFlag];
+    self.subjectName = [aDecoder decodeObjectForKey:kChatUserInfoSubjectName];
+    self.cloudStudyUseLastDay = [aDecoder decodeObjectForKey:kChatUserInfoCloudStudyUseLastDay];
+    self.memberRankSettingId = [aDecoder decodeDoubleForKey:kChatUserInfoMemberRankSettingId];
+    self.gender = [aDecoder decodeDoubleForKey:kChatUserInfoGender];
+    self.subjectId = [aDecoder decodeObjectForKey:kChatUserInfoSubjectId];
+    self.birthdate = [aDecoder decodeObjectForKey:kChatUserInfoBirthdate];
+    self.phone = [aDecoder decodeObjectForKey:kChatUserInfoPhone];
+    self.idCardNo = [aDecoder decodeObjectForKey:kChatUserInfoIdCardNo];
+    self.avatar = [aDecoder decodeObjectForKey:kChatUserInfoAvatar];
+    self.age = [aDecoder decodeDoubleForKey:kChatUserInfoAge];
+    self.createTime = [aDecoder decodeObjectForKey:kChatUserInfoCreateTime];
+    self.isBank = [aDecoder decodeObjectForKey:kChatUserInfoIsBank];
+    self.username = [aDecoder decodeObjectForKey:kChatUserInfoUsername];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeDouble:_userId forKey:kChatUserInfoUserId];
+    [aCoder encodeDouble:_isReal forKey:kChatUserInfoIsReal];
+    [aCoder encodeDouble:_cloudStudySequenceDays forKey:kChatUserInfoCloudStudySequenceDays];
+    [aCoder encodeObject:_membershipStartTime forKey:kChatUserInfoMembershipStartTime];
+    [aCoder encodeObject:_userStatus forKey:kChatUserInfoUserStatus];
+    [aCoder encodeObject:_membershipEndTime forKey:kChatUserInfoMembershipEndTime];
+    [aCoder encodeDouble:_isVip forKey:kChatUserInfoIsVip];
+    [aCoder encodeDouble:_lockFlag forKey:kChatUserInfoLockFlag];
+    [aCoder encodeObject:_updateTime forKey:kChatUserInfoUpdateTime];
+    [aCoder encodeObject:_realName forKey:kChatUserInfoRealName];
+    [aCoder encodeObject:_userType forKey:kChatUserInfoUserType];
+    [aCoder encodeObject:_delFlag forKey:kChatUserInfoDelFlag];
+    [aCoder encodeObject:_subjectName forKey:kChatUserInfoSubjectName];
+    [aCoder encodeObject:_cloudStudyUseLastDay forKey:kChatUserInfoCloudStudyUseLastDay];
+    [aCoder encodeDouble:_memberRankSettingId forKey:kChatUserInfoMemberRankSettingId];
+    [aCoder encodeDouble:_gender forKey:kChatUserInfoGender];
+    [aCoder encodeObject:_subjectId forKey:kChatUserInfoSubjectId];
+    [aCoder encodeObject:_birthdate forKey:kChatUserInfoBirthdate];
+    [aCoder encodeObject:_phone forKey:kChatUserInfoPhone];
+    [aCoder encodeObject:_idCardNo forKey:kChatUserInfoIdCardNo];
+    [aCoder encodeObject:_avatar forKey:kChatUserInfoAvatar];
+    [aCoder encodeDouble:_age forKey:kChatUserInfoAge];
+    [aCoder encodeObject:_createTime forKey:kChatUserInfoCreateTime];
+    [aCoder encodeObject:_isBank forKey:kChatUserInfoIsBank];
+    [aCoder encodeObject:_username forKey:kChatUserInfoUsername];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    ChatUserInfo *copy = [[ChatUserInfo alloc] init];
+    
+    if (copy) {
+
+        copy.userId = self.userId;
+        copy.isReal = self.isReal;
+        copy.cloudStudySequenceDays = self.cloudStudySequenceDays;
+        copy.membershipStartTime = [self.membershipStartTime copyWithZone:zone];
+        copy.userStatus = [self.userStatus copyWithZone:zone];
+        copy.membershipEndTime = [self.membershipEndTime copyWithZone:zone];
+        copy.isVip = self.isVip;
+        copy.lockFlag = self.lockFlag;
+        copy.updateTime = [self.updateTime copyWithZone:zone];
+        copy.realName = [self.realName copyWithZone:zone];
+        copy.userType = [self.userType copyWithZone:zone];
+        copy.delFlag = [self.delFlag copyWithZone:zone];
+        copy.subjectName = [self.subjectName copyWithZone:zone];
+        copy.cloudStudyUseLastDay = [self.cloudStudyUseLastDay copyWithZone:zone];
+        copy.memberRankSettingId = self.memberRankSettingId;
+        copy.gender = self.gender;
+        copy.subjectId = [self.subjectId copyWithZone:zone];
+        copy.birthdate = [self.birthdate copyWithZone:zone];
+        copy.phone = [self.phone copyWithZone:zone];
+        copy.idCardNo = [self.idCardNo copyWithZone:zone];
+        copy.avatar = [self.avatar copyWithZone:zone];
+        copy.age = self.age;
+        copy.createTime = [self.createTime copyWithZone:zone];
+        copy.isBank = [self.isBank copyWithZone:zone];
+        copy.username = [self.username copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 70 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/RecentPracticeModel.h

@@ -0,0 +1,70 @@
+//
+//  RecentPracticeModel.h
+//
+//  Created by Steven  on 2022/10/18
+//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+
+@interface RecentPracticeModel : NSObject <NSCoding, NSCopying>
+
+@property (nonatomic, strong) NSString *metronomeUrl;
+@property (nonatomic, strong) NSString *musicSheetName;
+@property (nonatomic, assign) double albumNums;
+@property (nonatomic, assign) double internalBaseClassIdentifier;
+@property (nonatomic, strong) NSString *xmlFileUrl;
+@property (nonatomic, assign) double showFingering;
+@property (nonatomic, assign) double albumSortNumber;
+@property (nonatomic, assign) double state;
+@property (nonatomic, strong) NSString *remark;
+@property (nonatomic, strong) NSString *titleImg;
+@property (nonatomic, assign) double notation;
+@property (nonatomic, strong) NSString *musicImg;
+@property (nonatomic, assign) double favoriteCount;
+@property (nonatomic, strong) NSString *url;
+@property (nonatomic, assign) double musicPrice;
+@property (nonatomic, assign) double sortNumber;
+@property (nonatomic, assign) double exquisiteFlag;
+@property (nonatomic, assign) id play;
+@property (nonatomic, strong) NSString *addUserAvatar;
+@property (nonatomic, strong) NSString *audioType;
+@property (nonatomic, assign) double canEvaluate;
+@property (nonatomic, assign) BOOL delFlag;
+@property (nonatomic, strong) NSString *musicTagNames;
+@property (nonatomic, strong) NSString *subjectNames;
+@property (nonatomic, strong) NSString *chargeType;
+@property (nonatomic, strong) NSString *updateTime;
+@property (nonatomic, assign) double updateBy;
+@property (nonatomic, strong) NSString *musicTag;
+@property (nonatomic, strong) NSString *extConfigJson;
+@property (nonatomic, strong) NSString *addName;
+@property (nonatomic, strong) NSString *paymentType;
+@property (nonatomic, strong) NSString *accompanimentType;
+@property (nonatomic, assign) double favorite;
+@property (nonatomic, strong) NSString *auditStatus;
+@property (nonatomic, assign) double createBy;
+@property (nonatomic, assign) double topFlag;
+@property (nonatomic, strong) NSString *midiUrl;
+@property (nonatomic, strong) NSString *composer;
+@property (nonatomic, strong) NSString *sourceType;
+@property (nonatomic, strong) NSString *firstPassAuditTime;
+@property (nonatomic, strong) NSString *mp3Type;
+@property (nonatomic, assign) id hotFlag;
+@property (nonatomic, strong) NSString *createTime;
+@property (nonatomic, assign) double playSpeed;
+@property (nonatomic, strong) NSString *audioFileUrl;
+@property (nonatomic, assign) double hasBeat;
+@property (nonatomic, strong) NSString *reason;
+@property (nonatomic, assign) double auditVersion;
+@property (nonatomic, strong) NSString *musicSubject;
+@property (nonatomic, assign) double userId;
+@property (nonatomic, strong) NSString *submitAuditTime;
+
++ (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+- (NSDictionary *)dictionaryRepresentation;
+
+@end

+ 445 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/ChatUserInfo/RecentPracticeModel.m

@@ -0,0 +1,445 @@
+//
+//  RecentPracticeModel.m
+//
+//  Created by Steven  on 2022/10/18
+//  Copyright (c) 2022 __MyCompanyName__. All rights reserved.
+//
+
+#import "RecentPracticeModel.h"
+
+
+NSString *const kRecentPracticeModelMetronomeUrl = @"metronomeUrl";
+NSString *const kRecentPracticeModelMusicSheetName = @"musicSheetName";
+NSString *const kRecentPracticeModelAlbumNums = @"albumNums";
+NSString *const kRecentPracticeModelId = @"id";
+NSString *const kRecentPracticeModelXmlFileUrl = @"xmlFileUrl";
+NSString *const kRecentPracticeModelShowFingering = @"showFingering";
+NSString *const kRecentPracticeModelAlbumSortNumber = @"albumSortNumber";
+NSString *const kRecentPracticeModelState = @"state";
+NSString *const kRecentPracticeModelRemark = @"remark";
+NSString *const kRecentPracticeModelTitleImg = @"titleImg";
+NSString *const kRecentPracticeModelNotation = @"notation";
+NSString *const kRecentPracticeModelMusicImg = @"musicImg";
+NSString *const kRecentPracticeModelFavoriteCount = @"favoriteCount";
+NSString *const kRecentPracticeModelUrl = @"url";
+NSString *const kRecentPracticeModelMusicPrice = @"musicPrice";
+NSString *const kRecentPracticeModelSortNumber = @"sortNumber";
+NSString *const kRecentPracticeModelExquisiteFlag = @"exquisiteFlag";
+NSString *const kRecentPracticeModelPlay = @"play";
+NSString *const kRecentPracticeModelAddUserAvatar = @"addUserAvatar";
+NSString *const kRecentPracticeModelAudioType = @"audioType";
+NSString *const kRecentPracticeModelCanEvaluate = @"canEvaluate";
+NSString *const kRecentPracticeModelDelFlag = @"delFlag";
+NSString *const kRecentPracticeModelMusicTagNames = @"musicTagNames";
+NSString *const kRecentPracticeModelSubjectNames = @"subjectNames";
+NSString *const kRecentPracticeModelChargeType = @"chargeType";
+NSString *const kRecentPracticeModelUpdateTime = @"updateTime";
+NSString *const kRecentPracticeModelUpdateBy = @"updateBy";
+NSString *const kRecentPracticeModelMusicTag = @"musicTag";
+NSString *const kRecentPracticeModelExtConfigJson = @"extConfigJson";
+NSString *const kRecentPracticeModelAddName = @"addName";
+NSString *const kRecentPracticeModelPaymentType = @"paymentType";
+NSString *const kRecentPracticeModelAccompanimentType = @"accompanimentType";
+NSString *const kRecentPracticeModelFavorite = @"favorite";
+NSString *const kRecentPracticeModelAuditStatus = @"auditStatus";
+NSString *const kRecentPracticeModelCreateBy = @"createBy";
+NSString *const kRecentPracticeModelTopFlag = @"topFlag";
+NSString *const kRecentPracticeModelMidiUrl = @"midiUrl";
+NSString *const kRecentPracticeModelComposer = @"composer";
+NSString *const kRecentPracticeModelSourceType = @"sourceType";
+NSString *const kRecentPracticeModelFirstPassAuditTime = @"firstPassAuditTime";
+NSString *const kRecentPracticeModelMp3Type = @"mp3Type";
+NSString *const kRecentPracticeModelHotFlag = @"hotFlag";
+NSString *const kRecentPracticeModelCreateTime = @"createTime";
+NSString *const kRecentPracticeModelPlaySpeed = @"playSpeed";
+NSString *const kRecentPracticeModelAudioFileUrl = @"audioFileUrl";
+NSString *const kRecentPracticeModelHasBeat = @"hasBeat";
+NSString *const kRecentPracticeModelReason = @"reason";
+NSString *const kRecentPracticeModelAuditVersion = @"auditVersion";
+NSString *const kRecentPracticeModelMusicSubject = @"musicSubject";
+NSString *const kRecentPracticeModelUserId = @"userId";
+NSString *const kRecentPracticeModelSubmitAuditTime = @"submitAuditTime";
+
+
+@interface RecentPracticeModel ()
+
+- (id)objectOrNilForKey:(id)aKey fromDictionary:(NSDictionary *)dict;
+
+@end
+
+@implementation RecentPracticeModel
+
+@synthesize metronomeUrl = _metronomeUrl;
+@synthesize musicSheetName = _musicSheetName;
+@synthesize albumNums = _albumNums;
+@synthesize internalBaseClassIdentifier = _internalBaseClassIdentifier;
+@synthesize xmlFileUrl = _xmlFileUrl;
+@synthesize showFingering = _showFingering;
+@synthesize albumSortNumber = _albumSortNumber;
+@synthesize state = _state;
+@synthesize remark = _remark;
+@synthesize titleImg = _titleImg;
+@synthesize notation = _notation;
+@synthesize musicImg = _musicImg;
+@synthesize favoriteCount = _favoriteCount;
+@synthesize url = _url;
+@synthesize musicPrice = _musicPrice;
+@synthesize sortNumber = _sortNumber;
+@synthesize exquisiteFlag = _exquisiteFlag;
+@synthesize play = _play;
+@synthesize addUserAvatar = _addUserAvatar;
+@synthesize audioType = _audioType;
+@synthesize canEvaluate = _canEvaluate;
+@synthesize delFlag = _delFlag;
+@synthesize musicTagNames = _musicTagNames;
+@synthesize subjectNames = _subjectNames;
+@synthesize chargeType = _chargeType;
+@synthesize updateTime = _updateTime;
+@synthesize updateBy = _updateBy;
+@synthesize musicTag = _musicTag;
+@synthesize extConfigJson = _extConfigJson;
+@synthesize addName = _addName;
+@synthesize paymentType = _paymentType;
+@synthesize accompanimentType = _accompanimentType;
+@synthesize favorite = _favorite;
+@synthesize auditStatus = _auditStatus;
+@synthesize createBy = _createBy;
+@synthesize topFlag = _topFlag;
+@synthesize midiUrl = _midiUrl;
+@synthesize composer = _composer;
+@synthesize sourceType = _sourceType;
+@synthesize firstPassAuditTime = _firstPassAuditTime;
+@synthesize mp3Type = _mp3Type;
+@synthesize hotFlag = _hotFlag;
+@synthesize createTime = _createTime;
+@synthesize playSpeed = _playSpeed;
+@synthesize audioFileUrl = _audioFileUrl;
+@synthesize hasBeat = _hasBeat;
+@synthesize reason = _reason;
+@synthesize auditVersion = _auditVersion;
+@synthesize musicSubject = _musicSubject;
+@synthesize userId = _userId;
+@synthesize submitAuditTime = _submitAuditTime;
+
+
++ (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.metronomeUrl = [self objectOrNilForKey:kRecentPracticeModelMetronomeUrl fromDictionary:dict];
+            self.musicSheetName = [self objectOrNilForKey:kRecentPracticeModelMusicSheetName fromDictionary:dict];
+            self.albumNums = [[self objectOrNilForKey:kRecentPracticeModelAlbumNums fromDictionary:dict] doubleValue];
+            self.internalBaseClassIdentifier = [[self objectOrNilForKey:kRecentPracticeModelId fromDictionary:dict] doubleValue];
+            self.xmlFileUrl = [self objectOrNilForKey:kRecentPracticeModelXmlFileUrl fromDictionary:dict];
+            self.showFingering = [[self objectOrNilForKey:kRecentPracticeModelShowFingering fromDictionary:dict] doubleValue];
+            self.albumSortNumber = [[self objectOrNilForKey:kRecentPracticeModelAlbumSortNumber fromDictionary:dict] doubleValue];
+            self.state = [[self objectOrNilForKey:kRecentPracticeModelState fromDictionary:dict] doubleValue];
+            self.remark = [self objectOrNilForKey:kRecentPracticeModelRemark fromDictionary:dict];
+            self.titleImg = [self objectOrNilForKey:kRecentPracticeModelTitleImg fromDictionary:dict];
+            self.notation = [[self objectOrNilForKey:kRecentPracticeModelNotation fromDictionary:dict] doubleValue];
+            self.musicImg = [self objectOrNilForKey:kRecentPracticeModelMusicImg fromDictionary:dict];
+            self.favoriteCount = [[self objectOrNilForKey:kRecentPracticeModelFavoriteCount fromDictionary:dict] doubleValue];
+            self.url = [self objectOrNilForKey:kRecentPracticeModelUrl fromDictionary:dict];
+            self.musicPrice = [[self objectOrNilForKey:kRecentPracticeModelMusicPrice fromDictionary:dict] doubleValue];
+            self.sortNumber = [[self objectOrNilForKey:kRecentPracticeModelSortNumber fromDictionary:dict] doubleValue];
+            self.exquisiteFlag = [[self objectOrNilForKey:kRecentPracticeModelExquisiteFlag fromDictionary:dict] doubleValue];
+            self.play = [self objectOrNilForKey:kRecentPracticeModelPlay fromDictionary:dict];
+            self.addUserAvatar = [self objectOrNilForKey:kRecentPracticeModelAddUserAvatar fromDictionary:dict];
+            self.audioType = [self objectOrNilForKey:kRecentPracticeModelAudioType fromDictionary:dict];
+            self.canEvaluate = [[self objectOrNilForKey:kRecentPracticeModelCanEvaluate fromDictionary:dict] doubleValue];
+            self.delFlag = [[self objectOrNilForKey:kRecentPracticeModelDelFlag fromDictionary:dict] boolValue];
+            self.musicTagNames = [self objectOrNilForKey:kRecentPracticeModelMusicTagNames fromDictionary:dict];
+            self.subjectNames = [self objectOrNilForKey:kRecentPracticeModelSubjectNames fromDictionary:dict];
+            self.chargeType = [self objectOrNilForKey:kRecentPracticeModelChargeType fromDictionary:dict];
+            self.updateTime = [self objectOrNilForKey:kRecentPracticeModelUpdateTime fromDictionary:dict];
+            self.updateBy = [[self objectOrNilForKey:kRecentPracticeModelUpdateBy fromDictionary:dict] doubleValue];
+            self.musicTag = [self objectOrNilForKey:kRecentPracticeModelMusicTag fromDictionary:dict];
+            self.extConfigJson = [self objectOrNilForKey:kRecentPracticeModelExtConfigJson fromDictionary:dict];
+            self.addName = [self objectOrNilForKey:kRecentPracticeModelAddName fromDictionary:dict];
+            self.paymentType = [self objectOrNilForKey:kRecentPracticeModelPaymentType fromDictionary:dict];
+            self.accompanimentType = [self objectOrNilForKey:kRecentPracticeModelAccompanimentType fromDictionary:dict];
+            self.favorite = [[self objectOrNilForKey:kRecentPracticeModelFavorite fromDictionary:dict] doubleValue];
+            self.auditStatus = [self objectOrNilForKey:kRecentPracticeModelAuditStatus fromDictionary:dict];
+            self.createBy = [[self objectOrNilForKey:kRecentPracticeModelCreateBy fromDictionary:dict] doubleValue];
+            self.topFlag = [[self objectOrNilForKey:kRecentPracticeModelTopFlag fromDictionary:dict] doubleValue];
+            self.midiUrl = [self objectOrNilForKey:kRecentPracticeModelMidiUrl fromDictionary:dict];
+            self.composer = [self objectOrNilForKey:kRecentPracticeModelComposer fromDictionary:dict];
+            self.sourceType = [self objectOrNilForKey:kRecentPracticeModelSourceType fromDictionary:dict];
+            self.firstPassAuditTime = [self objectOrNilForKey:kRecentPracticeModelFirstPassAuditTime fromDictionary:dict];
+            self.mp3Type = [self objectOrNilForKey:kRecentPracticeModelMp3Type fromDictionary:dict];
+            self.hotFlag = [self objectOrNilForKey:kRecentPracticeModelHotFlag fromDictionary:dict];
+            self.createTime = [self objectOrNilForKey:kRecentPracticeModelCreateTime fromDictionary:dict];
+            self.playSpeed = [[self objectOrNilForKey:kRecentPracticeModelPlaySpeed fromDictionary:dict] doubleValue];
+            self.audioFileUrl = [self objectOrNilForKey:kRecentPracticeModelAudioFileUrl fromDictionary:dict];
+            self.hasBeat = [[self objectOrNilForKey:kRecentPracticeModelHasBeat fromDictionary:dict] doubleValue];
+            self.reason = [self objectOrNilForKey:kRecentPracticeModelReason fromDictionary:dict];
+            self.auditVersion = [[self objectOrNilForKey:kRecentPracticeModelAuditVersion fromDictionary:dict] doubleValue];
+            self.musicSubject = [self objectOrNilForKey:kRecentPracticeModelMusicSubject fromDictionary:dict];
+            self.userId = [[self objectOrNilForKey:kRecentPracticeModelUserId fromDictionary:dict] doubleValue];
+            self.submitAuditTime = [self objectOrNilForKey:kRecentPracticeModelSubmitAuditTime fromDictionary:dict];
+
+    }
+    
+    return self;
+    
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
+    [mutableDict setValue:self.metronomeUrl forKey:kRecentPracticeModelMetronomeUrl];
+    [mutableDict setValue:self.musicSheetName forKey:kRecentPracticeModelMusicSheetName];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.albumNums] forKey:kRecentPracticeModelAlbumNums];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.internalBaseClassIdentifier] forKey:kRecentPracticeModelId];
+    [mutableDict setValue:self.xmlFileUrl forKey:kRecentPracticeModelXmlFileUrl];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.showFingering] forKey:kRecentPracticeModelShowFingering];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.albumSortNumber] forKey:kRecentPracticeModelAlbumSortNumber];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.state] forKey:kRecentPracticeModelState];
+    [mutableDict setValue:self.remark forKey:kRecentPracticeModelRemark];
+    [mutableDict setValue:self.titleImg forKey:kRecentPracticeModelTitleImg];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.notation] forKey:kRecentPracticeModelNotation];
+    [mutableDict setValue:self.musicImg forKey:kRecentPracticeModelMusicImg];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.favoriteCount] forKey:kRecentPracticeModelFavoriteCount];
+    [mutableDict setValue:self.url forKey:kRecentPracticeModelUrl];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.musicPrice] forKey:kRecentPracticeModelMusicPrice];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.sortNumber] forKey:kRecentPracticeModelSortNumber];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.exquisiteFlag] forKey:kRecentPracticeModelExquisiteFlag];
+    [mutableDict setValue:self.play forKey:kRecentPracticeModelPlay];
+    [mutableDict setValue:self.addUserAvatar forKey:kRecentPracticeModelAddUserAvatar];
+    [mutableDict setValue:self.audioType forKey:kRecentPracticeModelAudioType];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.canEvaluate] forKey:kRecentPracticeModelCanEvaluate];
+    [mutableDict setValue:[NSNumber numberWithBool:self.delFlag] forKey:kRecentPracticeModelDelFlag];
+    [mutableDict setValue:self.musicTagNames forKey:kRecentPracticeModelMusicTagNames];
+    [mutableDict setValue:self.subjectNames forKey:kRecentPracticeModelSubjectNames];
+    [mutableDict setValue:self.chargeType forKey:kRecentPracticeModelChargeType];
+    [mutableDict setValue:self.updateTime forKey:kRecentPracticeModelUpdateTime];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.updateBy] forKey:kRecentPracticeModelUpdateBy];
+    [mutableDict setValue:self.musicTag forKey:kRecentPracticeModelMusicTag];
+    [mutableDict setValue:self.extConfigJson forKey:kRecentPracticeModelExtConfigJson];
+    [mutableDict setValue:self.addName forKey:kRecentPracticeModelAddName];
+    [mutableDict setValue:self.paymentType forKey:kRecentPracticeModelPaymentType];
+    [mutableDict setValue:self.accompanimentType forKey:kRecentPracticeModelAccompanimentType];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.favorite] forKey:kRecentPracticeModelFavorite];
+    [mutableDict setValue:self.auditStatus forKey:kRecentPracticeModelAuditStatus];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.createBy] forKey:kRecentPracticeModelCreateBy];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.topFlag] forKey:kRecentPracticeModelTopFlag];
+    [mutableDict setValue:self.midiUrl forKey:kRecentPracticeModelMidiUrl];
+    [mutableDict setValue:self.composer forKey:kRecentPracticeModelComposer];
+    [mutableDict setValue:self.sourceType forKey:kRecentPracticeModelSourceType];
+    [mutableDict setValue:self.firstPassAuditTime forKey:kRecentPracticeModelFirstPassAuditTime];
+    [mutableDict setValue:self.mp3Type forKey:kRecentPracticeModelMp3Type];
+    [mutableDict setValue:self.hotFlag forKey:kRecentPracticeModelHotFlag];
+    [mutableDict setValue:self.createTime forKey:kRecentPracticeModelCreateTime];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.playSpeed] forKey:kRecentPracticeModelPlaySpeed];
+    [mutableDict setValue:self.audioFileUrl forKey:kRecentPracticeModelAudioFileUrl];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.hasBeat] forKey:kRecentPracticeModelHasBeat];
+    [mutableDict setValue:self.reason forKey:kRecentPracticeModelReason];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.auditVersion] forKey:kRecentPracticeModelAuditVersion];
+    [mutableDict setValue:self.musicSubject forKey:kRecentPracticeModelMusicSubject];
+    [mutableDict setValue:[NSNumber numberWithDouble:self.userId] forKey:kRecentPracticeModelUserId];
+    [mutableDict setValue:self.submitAuditTime forKey:kRecentPracticeModelSubmitAuditTime];
+
+    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];
+    return [object isEqual:[NSNull null]] ? nil : object;
+}
+
+
+#pragma mark - NSCoding Methods
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super init];
+
+    self.metronomeUrl = [aDecoder decodeObjectForKey:kRecentPracticeModelMetronomeUrl];
+    self.musicSheetName = [aDecoder decodeObjectForKey:kRecentPracticeModelMusicSheetName];
+    self.albumNums = [aDecoder decodeDoubleForKey:kRecentPracticeModelAlbumNums];
+    self.internalBaseClassIdentifier = [aDecoder decodeDoubleForKey:kRecentPracticeModelId];
+    self.xmlFileUrl = [aDecoder decodeObjectForKey:kRecentPracticeModelXmlFileUrl];
+    self.showFingering = [aDecoder decodeDoubleForKey:kRecentPracticeModelShowFingering];
+    self.albumSortNumber = [aDecoder decodeDoubleForKey:kRecentPracticeModelAlbumSortNumber];
+    self.state = [aDecoder decodeDoubleForKey:kRecentPracticeModelState];
+    self.remark = [aDecoder decodeObjectForKey:kRecentPracticeModelRemark];
+    self.titleImg = [aDecoder decodeObjectForKey:kRecentPracticeModelTitleImg];
+    self.notation = [aDecoder decodeDoubleForKey:kRecentPracticeModelNotation];
+    self.musicImg = [aDecoder decodeObjectForKey:kRecentPracticeModelMusicImg];
+    self.favoriteCount = [aDecoder decodeDoubleForKey:kRecentPracticeModelFavoriteCount];
+    self.url = [aDecoder decodeObjectForKey:kRecentPracticeModelUrl];
+    self.musicPrice = [aDecoder decodeDoubleForKey:kRecentPracticeModelMusicPrice];
+    self.sortNumber = [aDecoder decodeDoubleForKey:kRecentPracticeModelSortNumber];
+    self.exquisiteFlag = [aDecoder decodeDoubleForKey:kRecentPracticeModelExquisiteFlag];
+    self.play = [aDecoder decodeObjectForKey:kRecentPracticeModelPlay];
+    self.addUserAvatar = [aDecoder decodeObjectForKey:kRecentPracticeModelAddUserAvatar];
+    self.audioType = [aDecoder decodeObjectForKey:kRecentPracticeModelAudioType];
+    self.canEvaluate = [aDecoder decodeDoubleForKey:kRecentPracticeModelCanEvaluate];
+    self.delFlag = [aDecoder decodeBoolForKey:kRecentPracticeModelDelFlag];
+    self.musicTagNames = [aDecoder decodeObjectForKey:kRecentPracticeModelMusicTagNames];
+    self.subjectNames = [aDecoder decodeObjectForKey:kRecentPracticeModelSubjectNames];
+    self.chargeType = [aDecoder decodeObjectForKey:kRecentPracticeModelChargeType];
+    self.updateTime = [aDecoder decodeObjectForKey:kRecentPracticeModelUpdateTime];
+    self.updateBy = [aDecoder decodeDoubleForKey:kRecentPracticeModelUpdateBy];
+    self.musicTag = [aDecoder decodeObjectForKey:kRecentPracticeModelMusicTag];
+    self.extConfigJson = [aDecoder decodeObjectForKey:kRecentPracticeModelExtConfigJson];
+    self.addName = [aDecoder decodeObjectForKey:kRecentPracticeModelAddName];
+    self.paymentType = [aDecoder decodeObjectForKey:kRecentPracticeModelPaymentType];
+    self.accompanimentType = [aDecoder decodeObjectForKey:kRecentPracticeModelAccompanimentType];
+    self.favorite = [aDecoder decodeDoubleForKey:kRecentPracticeModelFavorite];
+    self.auditStatus = [aDecoder decodeObjectForKey:kRecentPracticeModelAuditStatus];
+    self.createBy = [aDecoder decodeDoubleForKey:kRecentPracticeModelCreateBy];
+    self.topFlag = [aDecoder decodeDoubleForKey:kRecentPracticeModelTopFlag];
+    self.midiUrl = [aDecoder decodeObjectForKey:kRecentPracticeModelMidiUrl];
+    self.composer = [aDecoder decodeObjectForKey:kRecentPracticeModelComposer];
+    self.sourceType = [aDecoder decodeObjectForKey:kRecentPracticeModelSourceType];
+    self.firstPassAuditTime = [aDecoder decodeObjectForKey:kRecentPracticeModelFirstPassAuditTime];
+    self.mp3Type = [aDecoder decodeObjectForKey:kRecentPracticeModelMp3Type];
+    self.hotFlag = [aDecoder decodeObjectForKey:kRecentPracticeModelHotFlag];
+    self.createTime = [aDecoder decodeObjectForKey:kRecentPracticeModelCreateTime];
+    self.playSpeed = [aDecoder decodeDoubleForKey:kRecentPracticeModelPlaySpeed];
+    self.audioFileUrl = [aDecoder decodeObjectForKey:kRecentPracticeModelAudioFileUrl];
+    self.hasBeat = [aDecoder decodeDoubleForKey:kRecentPracticeModelHasBeat];
+    self.reason = [aDecoder decodeObjectForKey:kRecentPracticeModelReason];
+    self.auditVersion = [aDecoder decodeDoubleForKey:kRecentPracticeModelAuditVersion];
+    self.musicSubject = [aDecoder decodeObjectForKey:kRecentPracticeModelMusicSubject];
+    self.userId = [aDecoder decodeDoubleForKey:kRecentPracticeModelUserId];
+    self.submitAuditTime = [aDecoder decodeObjectForKey:kRecentPracticeModelSubmitAuditTime];
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)aCoder
+{
+
+    [aCoder encodeObject:_metronomeUrl forKey:kRecentPracticeModelMetronomeUrl];
+    [aCoder encodeObject:_musicSheetName forKey:kRecentPracticeModelMusicSheetName];
+    [aCoder encodeDouble:_albumNums forKey:kRecentPracticeModelAlbumNums];
+    [aCoder encodeDouble:_internalBaseClassIdentifier forKey:kRecentPracticeModelId];
+    [aCoder encodeObject:_xmlFileUrl forKey:kRecentPracticeModelXmlFileUrl];
+    [aCoder encodeDouble:_showFingering forKey:kRecentPracticeModelShowFingering];
+    [aCoder encodeDouble:_albumSortNumber forKey:kRecentPracticeModelAlbumSortNumber];
+    [aCoder encodeDouble:_state forKey:kRecentPracticeModelState];
+    [aCoder encodeObject:_remark forKey:kRecentPracticeModelRemark];
+    [aCoder encodeObject:_titleImg forKey:kRecentPracticeModelTitleImg];
+    [aCoder encodeDouble:_notation forKey:kRecentPracticeModelNotation];
+    [aCoder encodeObject:_musicImg forKey:kRecentPracticeModelMusicImg];
+    [aCoder encodeDouble:_favoriteCount forKey:kRecentPracticeModelFavoriteCount];
+    [aCoder encodeObject:_url forKey:kRecentPracticeModelUrl];
+    [aCoder encodeDouble:_musicPrice forKey:kRecentPracticeModelMusicPrice];
+    [aCoder encodeDouble:_sortNumber forKey:kRecentPracticeModelSortNumber];
+    [aCoder encodeDouble:_exquisiteFlag forKey:kRecentPracticeModelExquisiteFlag];
+    [aCoder encodeObject:_play forKey:kRecentPracticeModelPlay];
+    [aCoder encodeObject:_addUserAvatar forKey:kRecentPracticeModelAddUserAvatar];
+    [aCoder encodeObject:_audioType forKey:kRecentPracticeModelAudioType];
+    [aCoder encodeDouble:_canEvaluate forKey:kRecentPracticeModelCanEvaluate];
+    [aCoder encodeBool:_delFlag forKey:kRecentPracticeModelDelFlag];
+    [aCoder encodeObject:_musicTagNames forKey:kRecentPracticeModelMusicTagNames];
+    [aCoder encodeObject:_subjectNames forKey:kRecentPracticeModelSubjectNames];
+    [aCoder encodeObject:_chargeType forKey:kRecentPracticeModelChargeType];
+    [aCoder encodeObject:_updateTime forKey:kRecentPracticeModelUpdateTime];
+    [aCoder encodeDouble:_updateBy forKey:kRecentPracticeModelUpdateBy];
+    [aCoder encodeObject:_musicTag forKey:kRecentPracticeModelMusicTag];
+    [aCoder encodeObject:_extConfigJson forKey:kRecentPracticeModelExtConfigJson];
+    [aCoder encodeObject:_addName forKey:kRecentPracticeModelAddName];
+    [aCoder encodeObject:_paymentType forKey:kRecentPracticeModelPaymentType];
+    [aCoder encodeObject:_accompanimentType forKey:kRecentPracticeModelAccompanimentType];
+    [aCoder encodeDouble:_favorite forKey:kRecentPracticeModelFavorite];
+    [aCoder encodeObject:_auditStatus forKey:kRecentPracticeModelAuditStatus];
+    [aCoder encodeDouble:_createBy forKey:kRecentPracticeModelCreateBy];
+    [aCoder encodeDouble:_topFlag forKey:kRecentPracticeModelTopFlag];
+    [aCoder encodeObject:_midiUrl forKey:kRecentPracticeModelMidiUrl];
+    [aCoder encodeObject:_composer forKey:kRecentPracticeModelComposer];
+    [aCoder encodeObject:_sourceType forKey:kRecentPracticeModelSourceType];
+    [aCoder encodeObject:_firstPassAuditTime forKey:kRecentPracticeModelFirstPassAuditTime];
+    [aCoder encodeObject:_mp3Type forKey:kRecentPracticeModelMp3Type];
+    [aCoder encodeObject:_hotFlag forKey:kRecentPracticeModelHotFlag];
+    [aCoder encodeObject:_createTime forKey:kRecentPracticeModelCreateTime];
+    [aCoder encodeDouble:_playSpeed forKey:kRecentPracticeModelPlaySpeed];
+    [aCoder encodeObject:_audioFileUrl forKey:kRecentPracticeModelAudioFileUrl];
+    [aCoder encodeDouble:_hasBeat forKey:kRecentPracticeModelHasBeat];
+    [aCoder encodeObject:_reason forKey:kRecentPracticeModelReason];
+    [aCoder encodeDouble:_auditVersion forKey:kRecentPracticeModelAuditVersion];
+    [aCoder encodeObject:_musicSubject forKey:kRecentPracticeModelMusicSubject];
+    [aCoder encodeDouble:_userId forKey:kRecentPracticeModelUserId];
+    [aCoder encodeObject:_submitAuditTime forKey:kRecentPracticeModelSubmitAuditTime];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    RecentPracticeModel *copy = [[RecentPracticeModel alloc] init];
+    
+    if (copy) {
+
+        copy.metronomeUrl = [self.metronomeUrl copyWithZone:zone];
+        copy.musicSheetName = [self.musicSheetName copyWithZone:zone];
+        copy.albumNums = self.albumNums;
+        copy.internalBaseClassIdentifier = self.internalBaseClassIdentifier;
+        copy.xmlFileUrl = [self.xmlFileUrl copyWithZone:zone];
+        copy.showFingering = self.showFingering;
+        copy.albumSortNumber = self.albumSortNumber;
+        copy.state = self.state;
+        copy.remark = [self.remark copyWithZone:zone];
+        copy.titleImg = [self.titleImg copyWithZone:zone];
+        copy.notation = self.notation;
+        copy.musicImg = [self.musicImg copyWithZone:zone];
+        copy.favoriteCount = self.favoriteCount;
+        copy.url = [self.url copyWithZone:zone];
+        copy.musicPrice = self.musicPrice;
+        copy.sortNumber = self.sortNumber;
+        copy.exquisiteFlag = self.exquisiteFlag;
+        copy.play = [self.play copyWithZone:zone];
+        copy.addUserAvatar = [self.addUserAvatar copyWithZone:zone];
+        copy.audioType = [self.audioType copyWithZone:zone];
+        copy.canEvaluate = self.canEvaluate;
+        copy.delFlag = self.delFlag;
+        copy.musicTagNames = [self.musicTagNames copyWithZone:zone];
+        copy.subjectNames = [self.subjectNames copyWithZone:zone];
+        copy.chargeType = [self.chargeType copyWithZone:zone];
+        copy.updateTime = [self.updateTime copyWithZone:zone];
+        copy.updateBy = self.updateBy;
+        copy.musicTag = [self.musicTag copyWithZone:zone];
+        copy.extConfigJson = [self.extConfigJson copyWithZone:zone];
+        copy.addName = [self.addName copyWithZone:zone];
+        copy.paymentType = [self.paymentType copyWithZone:zone];
+        copy.accompanimentType = [self.accompanimentType copyWithZone:zone];
+        copy.favorite = self.favorite;
+        copy.auditStatus = [self.auditStatus copyWithZone:zone];
+        copy.createBy = self.createBy;
+        copy.topFlag = self.topFlag;
+        copy.midiUrl = [self.midiUrl copyWithZone:zone];
+        copy.composer = [self.composer copyWithZone:zone];
+        copy.sourceType = [self.sourceType copyWithZone:zone];
+        copy.firstPassAuditTime = [self.firstPassAuditTime copyWithZone:zone];
+        copy.mp3Type = [self.mp3Type copyWithZone:zone];
+        copy.hotFlag = [self.hotFlag copyWithZone:zone];
+        copy.createTime = [self.createTime copyWithZone:zone];
+        copy.playSpeed = self.playSpeed;
+        copy.audioFileUrl = [self.audioFileUrl copyWithZone:zone];
+        copy.hasBeat = self.hasBeat;
+        copy.reason = [self.reason copyWithZone:zone];
+        copy.auditVersion = self.auditVersion;
+        copy.musicSubject = [self.musicSubject copyWithZone:zone];
+        copy.userId = self.userId;
+        copy.submitAuditTime = [self.submitAuditTime copyWithZone:zone];
+    }
+    
+    return copy;
+}
+
+
+@end

+ 2 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/FriendListModel.h

@@ -20,6 +20,8 @@
 @property (nonatomic, strong) NSString *updateTime;
 @property (nonatomic, strong) NSString *createTime;
 @property (nonatomic, strong) NSString *firstLetter;
+@property (nonatomic, strong) NSString *imFriendId;
+@property (nonatomic, strong) NSString *roleType;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
 - (instancetype)initWithDictionary:(NSDictionary *)dict;

+ 15 - 5
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/FriendListModel.m

@@ -16,7 +16,8 @@ NSString *const kFriendListModelMemo = @"memo";
 NSString *const kFriendListModelFriendAvatar = @"friendAvatar";
 NSString *const kFriendListModelUpdateTime = @"updateTime";
 NSString *const kFriendListModelCreateTime = @"createTime";
-
+NSString *const kFriendListModelImFriendId = @"imFriendId";
+NSString *const kFriendListModelRoleType = @"roleType";
 
 @interface FriendListModel ()
 
@@ -34,7 +35,8 @@ NSString *const kFriendListModelCreateTime = @"createTime";
 @synthesize friendAvatar = _friendAvatar;
 @synthesize updateTime = _updateTime;
 @synthesize createTime = _createTime;
-
+@synthesize imFriendId = _imFriendId;
+@synthesize roleType = _roleType;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
 {
@@ -56,7 +58,8 @@ NSString *const kFriendListModelCreateTime = @"createTime";
             self.friendAvatar = [self objectOrNilForKey:kFriendListModelFriendAvatar fromDictionary:dict];
             self.updateTime = [self objectOrNilForKey:kFriendListModelUpdateTime fromDictionary:dict];
             self.createTime = [self objectOrNilForKey:kFriendListModelCreateTime fromDictionary:dict];
-
+            self.imFriendId = [self objectOrNilForKey:kFriendListModelImFriendId fromDictionary:dict];
+        self.roleType = [self objectOrNilForKey:kFriendListModelRoleType fromDictionary:dict];
     }
     
     return self;
@@ -74,7 +77,8 @@ NSString *const kFriendListModelCreateTime = @"createTime";
     [mutableDict setValue:self.friendAvatar forKey:kFriendListModelFriendAvatar];
     [mutableDict setValue:self.updateTime forKey:kFriendListModelUpdateTime];
     [mutableDict setValue:self.createTime forKey:kFriendListModelCreateTime];
-
+    [mutableDict setValue:self.imFriendId forKey:kFriendListModelImFriendId];
+    [mutableDict setValue:self.roleType forKey:kFriendListModelRoleType];
     return [NSDictionary dictionaryWithDictionary:mutableDict];
 }
 
@@ -109,6 +113,8 @@ NSString *const kFriendListModelCreateTime = @"createTime";
     self.friendAvatar = [aDecoder decodeObjectForKey:kFriendListModelFriendAvatar];
     self.updateTime = [aDecoder decodeObjectForKey:kFriendListModelUpdateTime];
     self.createTime = [aDecoder decodeObjectForKey:kFriendListModelCreateTime];
+    self.imFriendId = [aDecoder decodeObjectForKey:kFriendListModelImFriendId];
+    self.roleType = [aDecoder decodeObjectForKey:kFriendListModelRoleType];
     return self;
 }
 
@@ -123,6 +129,8 @@ NSString *const kFriendListModelCreateTime = @"createTime";
     [aCoder encodeObject:_friendAvatar forKey:kFriendListModelFriendAvatar];
     [aCoder encodeObject:_updateTime forKey:kFriendListModelUpdateTime];
     [aCoder encodeObject:_createTime forKey:kFriendListModelCreateTime];
+    [aCoder encodeObject:_imFriendId forKey:kFriendListModelImFriendId];
+    [aCoder encodeObject:_roleType forKey:kFriendListModelRoleType];
 }
 
 - (id)copyWithZone:(NSZone *)zone
@@ -130,7 +138,7 @@ NSString *const kFriendListModelCreateTime = @"createTime";
     FriendListModel *copy = [[FriendListModel alloc] init];
     
     if (copy) {
-
+        
         copy.userId = [self.userId copyWithZone:zone];
         copy.friendNickname = [self.friendNickname copyWithZone:zone];
         copy.internalBaseClassIdentifier = [self.internalBaseClassIdentifier copyWithZone:zone];
@@ -139,6 +147,8 @@ NSString *const kFriendListModelCreateTime = @"createTime";
         copy.friendAvatar = [self.friendAvatar copyWithZone:zone];
         copy.updateTime = [self.updateTime copyWithZone:zone];
         copy.createTime = [self.createTime copyWithZone:zone];
+        copy.imFriendId = [self.createTime copyWithZone:zone];
+        copy.roleType = [self.roleType copyWithZone:zone];
     }
     
     return copy;

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/GroupMemberModel.h

@@ -22,6 +22,7 @@
 @property (nonatomic, strong) NSString *createTime;
 
 @property (nonatomic, strong) NSString *firstLetter;
+@property (nonatomic, strong) NSString *imUserId;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
 - (instancetype)initWithDictionary:(NSDictionary *)dict;

+ 7 - 3
KulexiuForStudent/KulexiuForStudent/Module/Chat/Model/GroupMemberModel.m

@@ -17,6 +17,7 @@ NSString *const kGroupMemberModelNickname = @"nickname";
 NSString *const kGroupMemberModelIsAdmin = @"isAdmin";
 NSString *const kGroupMemberModelGroupId = @"groupId";
 NSString *const kGroupMemberModelCreateTime = @"createTime";
+NSString *const kGroupMemberModelImUserId = @"imUserId";
 
 
 @interface GroupMemberModel ()
@@ -36,7 +37,7 @@ NSString *const kGroupMemberModelCreateTime = @"createTime";
 @synthesize isAdmin = _isAdmin;
 @synthesize groupId = _groupId;
 @synthesize createTime = _createTime;
-
+@synthesize imUserId = _imUserId;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
 {
@@ -59,7 +60,7 @@ NSString *const kGroupMemberModelCreateTime = @"createTime";
             self.isAdmin = [[self objectOrNilForKey:kGroupMemberModelIsAdmin fromDictionary:dict] boolValue];
             self.groupId = [self objectOrNilForKey:kGroupMemberModelGroupId fromDictionary:dict];
             self.createTime = [self objectOrNilForKey:kGroupMemberModelCreateTime fromDictionary:dict];
-
+        self.imUserId = [self objectOrNilForKey:kGroupMemberModelImUserId fromDictionary:dict];
     }
     
     return self;
@@ -78,7 +79,7 @@ NSString *const kGroupMemberModelCreateTime = @"createTime";
     [mutableDict setValue:[NSNumber numberWithBool:self.isAdmin] forKey:kGroupMemberModelIsAdmin];
     [mutableDict setValue:self.groupId forKey:kGroupMemberModelGroupId];
     [mutableDict setValue:self.createTime forKey:kGroupMemberModelCreateTime];
-
+    [mutableDict setValue:self.imUserId forKey:kGroupMemberModelImUserId];
     return [NSDictionary dictionaryWithDictionary:mutableDict];
 }
 
@@ -114,6 +115,7 @@ NSString *const kGroupMemberModelCreateTime = @"createTime";
     self.isAdmin = [aDecoder decodeBoolForKey:kGroupMemberModelIsAdmin];
     self.groupId = [aDecoder decodeObjectForKey:kGroupMemberModelGroupId];
     self.createTime = [aDecoder decodeObjectForKey:kGroupMemberModelCreateTime];
+    self.imUserId = [aDecoder decodeObjectForKey:kGroupMemberModelImUserId];
     return self;
 }
 
@@ -129,6 +131,7 @@ NSString *const kGroupMemberModelCreateTime = @"createTime";
     [aCoder encodeBool:_isAdmin forKey:kGroupMemberModelIsAdmin];
     [aCoder encodeObject:_groupId forKey:kGroupMemberModelGroupId];
     [aCoder encodeObject:_createTime forKey:kGroupMemberModelCreateTime];
+    [aCoder encodeObject:_imUserId forKey:kGroupMemberModelImUserId];
 }
 
 - (id)copyWithZone:(NSZone *)zone
@@ -146,6 +149,7 @@ NSString *const kGroupMemberModelCreateTime = @"createTime";
         copy.isAdmin = self.isAdmin;
         copy.groupId = [self.groupId copyWithZone:zone];
         copy.createTime = [self.createTime copyWithZone:zone];
+        copy.imUserId = [self.imUserId copyWithZone:zone];
     }
     
     return copy;

+ 2 - 2
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatAddressBodyView.m

@@ -287,10 +287,10 @@
         NSArray *filterArray = self.studentArray[indexPath.section];
         FriendListModel *model = filterArray[indexPath.row];
         if (_isShareImage) { // 分享
-            [self sendMessageWithTargetId:model.friendId isGroup:NO];
+            [self sendMessageWithTargetId:model.imFriendId isGroup:NO];
         }
         else { // 聊天
-            [self chatConversationWithTargetId:model.friendId targetName:model.friendNickname isGroup:NO];
+            [self chatConversationWithTargetId:model.imFriendId targetName:model.friendNickname isGroup:NO];
         }
     }
     else { // 群聊

+ 24 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/RecentMusicView.h

@@ -0,0 +1,24 @@
+//
+//  RecentMusicView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import <UIKit/UIKit.h>
+#import "RecentPracticeModel.h"
+
+typedef void(^RecentMusicDetailBlock)(NSString * _Nonnull songId);
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RecentMusicView : UIView
+
++ (instancetype)shareInstance;
+
+- (void)configWithMusicModel:(RecentPracticeModel *)sourceModel hiddenLineView:(BOOL)hideLineView callback:(RecentMusicDetailBlock)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 185 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/RecentMusicView.m

@@ -0,0 +1,185 @@
+//
+//  RecentMusicView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import "RecentMusicView.h"
+#import "MusicTagView.h"
+
+@interface RecentMusicView ()
+
+@property (weak, nonatomic) IBOutlet UILabel *songNameLabel;
+@property (weak, nonatomic) IBOutlet UILabel *songAuth;
+@property (weak, nonatomic) IBOutlet UILabel *uploadName;
+
+@property (weak, nonatomic) IBOutlet UIView *tagView;
+@property (weak, nonatomic) IBOutlet UIView *lineView;
+
+@property (nonatomic, copy) RecentMusicDetailBlock callback;
+
+@property (nonatomic, strong) RecentPracticeModel *model;
+
+@property (weak, nonatomic) IBOutlet UIImageView *qualityMusicTag;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *qualityTagWidth;
+
+@property (weak, nonatomic) IBOutlet UIImageView *albumTag;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *albumTagWidth;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *albumTagLeft;
+
+@end
+
+@implementation RecentMusicView
+
++ (instancetype)shareInstance {
+    RecentMusicView *view = [[[NSBundle mainBundle] loadNibNamed:@"RecentMusicView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configWithMusicModel:(RecentPracticeModel *)sourceModel hiddenLineView:(BOOL)hideLineView callback:(RecentMusicDetailBlock)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    self.model = sourceModel;
+    if (sourceModel.exquisiteFlag) {
+        self.qualityMusicTag.hidden = NO;
+        self.qualityTagWidth.constant = 14.0f;
+    }
+    else {
+        self.qualityMusicTag.hidden = NO;
+        self.qualityTagWidth.constant = 0.0f;
+    }
+    
+    if (sourceModel.albumNums > 0) {
+        self.albumTag.hidden = NO;
+        self.albumTagWidth.constant = 15.0f;
+        self.albumTagLeft.constant = 5.0f;
+    }
+    else {
+        self.albumTag.hidden = YES;
+        self.albumTagWidth.constant = 0.0f;
+        self.albumTagLeft.constant = 0.0f;
+    }
+    
+    if ([NSString isEmptyString:sourceModel.musicSheetName]) {
+        self.songNameLabel.text = @"";
+    }
+    else {
+        NSString *musicName = @"";
+        if (sourceModel.musicSheetName.length > 10) {
+            musicName = [NSString stringWithFormat:@"%@...",[sourceModel.musicSheetName substringToIndex:9]];
+        }
+        else {
+            musicName = sourceModel.musicSheetName;
+        }
+        self.songNameLabel.text = musicName;
+    }
+    if ([NSString isEmptyString:sourceModel.composer]) {
+        self.songAuth.text = @"";
+    }
+    else {
+        NSString *songAuth = @"";
+        if (sourceModel.composer.length > 4) {
+            songAuth = [NSString stringWithFormat:@"-%@...",[sourceModel.composer substringToIndex:4]];
+        }
+        else {
+            songAuth = [NSString stringWithFormat:@"-%@",sourceModel.composer];
+        }
+        self.songAuth.text = songAuth;
+    }
+    NSArray *tagArray = nil;
+    if (![NSString isEmptyString:sourceModel.subjectNames]) {
+        tagArray = [sourceModel.subjectNames componentsSeparatedByString:@","];
+    }
+    
+    NSString *owner = @"";
+    if ([NSString isEmptyString:sourceModel.addName]) {
+        owner = [NSString stringWithFormat:@"上传者:游客%.0f",sourceModel.userId];
+    }
+    else {
+        owner = sourceModel.addName;
+        if (sourceModel.addName.length > 4) {
+            owner = [NSString stringWithFormat:@"上传者:%@...",[sourceModel.addName substringToIndex:4]];
+        }
+        else {
+            owner = [NSString stringWithFormat:@"上传者:%@",sourceModel.addName];
+        }
+    }
+    self.uploadName.text = owner;
+
+    CGFloat maxWidth = [self getTagViewMaxWidth:owner];
+    [self configTagViewWithTagArray:tagArray maxWidth:maxWidth];
+    self.lineView.hidden = hideLineView;
+}
+
+- (CGFloat)getWidthWithTypeCount:(NSInteger)count singleWidth:(CGFloat)singleWidth space:(CGFloat)space {
+    if (count == 1) {
+        return singleWidth;
+    }
+    else {
+        return singleWidth + (singleWidth + space) * (count - 1);
+    }
+}
+
+- (CGFloat)getTagViewMaxWidth:(NSString *)teacherName {
+    CGFloat width = [self getStringWidthInLabel:teacherName font:[UIFont systemFontOfSize:12.0f]];
+    return KPortraitWidth - 48 - width - 12;
+}
+
+- (void)configTagViewWithTagArray:(NSArray *)tagArray maxWidth:(CGFloat)maxWidth {
+    [self.tagView removeAllSubViews];
+    CGFloat width = maxWidth;
+    CGFloat xSpace = 0.0f;
+    for (NSInteger i = 0; i < tagArray.count; i++) {
+        NSString *tagString = tagArray[i];
+        CGFloat labelWidth = [self getStringWidthInLabel:tagString font:[UIFont systemFontOfSize:10.0f]];
+        CGFloat viewWidth = labelWidth + 10;
+        if (xSpace + viewWidth > width) {
+            return;
+        }
+        CGRect frame = CGRectMake(xSpace, 0, viewWidth, 16.0f);
+        [self createTagLabelViewWithName:tagString frame:frame];
+        xSpace += (viewWidth + 5);
+    }
+}
+
+- (CGFloat)getStringWidthInLabel:(NSString *)tagString font:(UIFont *)font {
+    CGFloat width = [tagString boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 16.0f) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil].size.width+1;
+    return width;
+}
+
+- (void)createTagLabelViewWithName:(NSString *)name frame:(CGRect)frame {
+    UIView *bgView = [[UIView alloc] initWithFrame:frame];
+    bgView.backgroundColor = HexRGB(0xEFFBF9);
+    bgView.layer.cornerRadius = 8.0f;
+    [self.tagView addSubview:bgView];
+    
+    UILabel *tagLabel = [[UILabel alloc] init];
+    tagLabel.text = name;
+    tagLabel.textColor = THEMECOLOR;
+    tagLabel.font = [UIFont systemFontOfSize:10.0f];
+    tagLabel.textAlignment = NSTextAlignmentCenter;
+    [bgView addSubview:tagLabel];
+    [tagLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.mas_equalTo(bgView.mas_left).offset(5);
+        make.right.mas_equalTo(bgView.mas_right).offset(-5);
+        make.top.bottom.mas_equalTo(bgView);
+    }];
+}
+
+- (IBAction)buttonAction:(id)sender {
+    if (self.callback) {
+        NSString *songId = [NSString stringWithFormat:@"%.0f",self.model.internalBaseClassIdentifier];
+        self.callback(songId);
+    }
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 132 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/RecentMusicView.xib

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_0" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RecentMusicView">
+            <rect key="frame" x="0.0" y="0.0" width="390" height="84"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="最伟大的作品" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Shl-oF-wvN">
+                    <rect key="frame" x="57" y="21.666666666666671" width="98" height="22"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="22" id="yEu-dU-wB3"/>
+                    </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>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-周杰伦" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="43W-cg-jr5">
+                    <rect key="frame" x="160" y="25" width="43" height="15"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                    <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="hvc-Gg-1Zz">
+                    <rect key="frame" x="18" y="53.666666666666664" width="123" height="16.999999999999993"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="17" id="rS3-rz-IW0"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="home_music_play" translatesAutoresizingMaskIntoConstraints="NO" id="4gu-v4-wJm">
+                    <rect key="frame" x="342" y="30" width="24" height="24"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="24" id="aJX-AJ-O25"/>
+                        <constraint firstAttribute="height" constant="24" id="gcw-w5-2ob"/>
+                    </constraints>
+                </imageView>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8Xo-oO-3x3">
+                    <rect key="frame" x="153" y="54" width="184" height="16"/>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="16" id="3RW-fM-J0s"/>
+                    </constraints>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="R2e-lE-ZM6">
+                    <rect key="frame" x="18" y="83.666666666666671" width="354" height="0.3333333333333286"/>
+                    <color key="backgroundColor" red="0.90980392160000001" green="0.90980392160000001" blue="0.90980392160000001" alpha="1" colorSpace="calibratedRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="0.5" id="Ifk-5G-zlF"/>
+                    </constraints>
+                </view>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="quality_tag" translatesAutoresizingMaskIntoConstraints="NO" id="8fL-Jy-bgr">
+                    <rect key="frame" x="18" y="24" width="14" height="17"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="14" id="BIZ-8m-Xog"/>
+                        <constraint firstAttribute="height" constant="17" id="Vyh-lk-Y2u"/>
+                    </constraints>
+                </imageView>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="music_albumTag" translatesAutoresizingMaskIntoConstraints="NO" id="Uca-W8-cUY">
+                    <rect key="frame" x="37" y="25" width="15" height="15"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="15" id="nIS-wf-l8i"/>
+                        <constraint firstAttribute="width" constant="15" id="rso-cD-zs9"/>
+                    </constraints>
+                </imageView>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UvT-Ln-7qo">
+                    <rect key="frame" x="0.0" y="0.0" width="390" height="84"/>
+                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                    <connections>
+                        <action selector="buttonAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="Xiw-64-8rM"/>
+                    </connections>
+                </button>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="UvT-Ln-7qo" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="0z4-iF-ucd"/>
+                <constraint firstItem="4gu-v4-wJm" firstAttribute="leading" secondItem="8Xo-oO-3x3" secondAttribute="trailing" constant="5" id="2bH-bi-rsd"/>
+                <constraint firstItem="4gu-v4-wJm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="43W-cg-jr5" secondAttribute="trailing" constant="5" id="6dq-x6-1RP"/>
+                <constraint firstItem="43W-cg-jr5" firstAttribute="centerY" secondItem="8fL-Jy-bgr" secondAttribute="centerY" id="8kf-kw-cS9"/>
+                <constraint firstItem="hvc-Gg-1Zz" firstAttribute="leading" secondItem="8fL-Jy-bgr" secondAttribute="leading" id="9nd-TU-kyn"/>
+                <constraint firstItem="UvT-Ln-7qo" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Fh8-eQ-jxk"/>
+                <constraint firstItem="8fL-Jy-bgr" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="24" id="Kpm-kV-SRi"/>
+                <constraint firstItem="43W-cg-jr5" firstAttribute="leading" secondItem="Shl-oF-wvN" secondAttribute="trailing" constant="5" id="MuV-qV-dVg"/>
+                <constraint firstAttribute="trailing" secondItem="4gu-v4-wJm" secondAttribute="trailing" constant="24" id="N6e-ub-5Cc"/>
+                <constraint firstAttribute="trailing" secondItem="UvT-Ln-7qo" secondAttribute="trailing" id="Syk-cV-CFd"/>
+                <constraint firstItem="Uca-W8-cUY" firstAttribute="leading" secondItem="8fL-Jy-bgr" secondAttribute="trailing" constant="5" id="TSx-tA-rAn"/>
+                <constraint firstItem="Uca-W8-cUY" firstAttribute="centerY" secondItem="8fL-Jy-bgr" secondAttribute="centerY" id="TmH-4n-nH4"/>
+                <constraint firstItem="hvc-Gg-1Zz" firstAttribute="top" secondItem="Shl-oF-wvN" secondAttribute="bottom" constant="10" id="VkD-Y3-BSf"/>
+                <constraint firstItem="8Xo-oO-3x3" firstAttribute="leading" secondItem="hvc-Gg-1Zz" secondAttribute="trailing" constant="12" id="WYh-zk-vte"/>
+                <constraint firstItem="R2e-lE-ZM6" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="18" id="XZj-xi-1FR"/>
+                <constraint firstItem="8Xo-oO-3x3" firstAttribute="centerY" secondItem="hvc-Gg-1Zz" secondAttribute="centerY" id="cPs-M6-keN"/>
+                <constraint firstAttribute="trailing" secondItem="R2e-lE-ZM6" secondAttribute="trailing" constant="18" id="fx0-GH-hQe"/>
+                <constraint firstItem="8fL-Jy-bgr" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="18" id="kt6-OU-oYn"/>
+                <constraint firstAttribute="bottom" secondItem="R2e-lE-ZM6" secondAttribute="bottom" id="pMe-In-6YX"/>
+                <constraint firstItem="Shl-oF-wvN" firstAttribute="leading" secondItem="Uca-W8-cUY" secondAttribute="trailing" constant="5" id="pmf-Eg-NCR"/>
+                <constraint firstItem="Shl-oF-wvN" firstAttribute="centerY" secondItem="8fL-Jy-bgr" secondAttribute="centerY" id="sZG-qc-hWe"/>
+                <constraint firstAttribute="bottom" secondItem="UvT-Ln-7qo" secondAttribute="bottom" id="t3d-MK-BUM"/>
+                <constraint firstItem="4gu-v4-wJm" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="zPb-kf-uh1"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="albumTag" destination="Uca-W8-cUY" id="eGx-WB-SJc"/>
+                <outlet property="albumTagLeft" destination="TSx-tA-rAn" id="8JH-hI-qO6"/>
+                <outlet property="albumTagWidth" destination="rso-cD-zs9" id="YMh-Cx-I5Q"/>
+                <outlet property="lineView" destination="R2e-lE-ZM6" id="qmg-Ew-0Ut"/>
+                <outlet property="qualityMusicTag" destination="8fL-Jy-bgr" id="XUR-m4-TKf"/>
+                <outlet property="qualityTagWidth" destination="BIZ-8m-Xog" id="fBy-eq-HMV"/>
+                <outlet property="songAuth" destination="43W-cg-jr5" id="LK6-4t-gGK"/>
+                <outlet property="songNameLabel" destination="Shl-oF-wvN" id="Fi7-Gb-vEF"/>
+                <outlet property="tagView" destination="8Xo-oO-3x3" id="WHd-26-x2X"/>
+                <outlet property="uploadName" destination="hvc-Gg-1Zz" id="TyX-af-akM"/>
+            </connections>
+            <point key="canvasLocation" x="101.53846153846153" y="-60.426540284360186"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="home_music_play" width="24" height="24"/>
+        <image name="music_albumTag" width="15" height="15"/>
+        <image name="quality_tag" width="14" height="17"/>
+    </resources>
+</document>

+ 26 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBodyView.h

@@ -0,0 +1,26 @@
+//
+//  UserDetailBodyView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import <UIKit/UIKit.h>
+#import "ChatUserInfo.h"
+
+typedef void(^RecentMusicCallback)(NSString *songId);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface UserDetailBodyView : UIView
+
++ (instancetype)shareInstance;
+
+- (void)configUserMessage:(ChatUserInfo *)userInfo musicArray:(NSMutableArray *)musicArray callback:(RecentMusicCallback)callback;
+
+
++ (CGFloat)getViewHeight;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 100 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBodyView.m

@@ -0,0 +1,100 @@
+//
+//  UserDetailBodyView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import "UserDetailBodyView.h"
+#import "RecentMusicView.h"
+
+@interface UserDetailBodyView ()
+
+@property (weak, nonatomic) IBOutlet UIImageView *userAvatar;
+
+@property (weak, nonatomic) IBOutlet UILabel *userName;
+
+@property (weak, nonatomic) IBOutlet UIImageView *memberImage;
+
+@property (weak, nonatomic) IBOutlet UILabel *userSex;
+
+@property (weak, nonatomic) IBOutlet UILabel *userSubject;
+
+@property (weak, nonatomic) IBOutlet UIView *subjectView;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *subjectViewHeight;
+
+@property (weak, nonatomic) IBOutlet UILabel *userIdLabel;
+
+@property (nonatomic, copy) RecentMusicCallback callback;
+
+@end
+
+@implementation UserDetailBodyView
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+}
+
++ (instancetype)shareInstance {
+    UserDetailBodyView *view = [[[NSBundle mainBundle] loadNibNamed:@"UserDetailBodyView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)configUserMessage:(ChatUserInfo *)userInfo musicArray:(NSMutableArray *)musicArray callback:(RecentMusicCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+    NSString *viperImage = @"";
+    if (userInfo.isVip == 1) {
+        self.userAvatar.layer.borderColor = HexRGB(0xFFE0B9).CGColor;
+        viperImage = @"mine_vip";
+    }
+    else {
+        self.userAvatar.layer.borderColor = HexRGB(0xffffff).CGColor;
+        viperImage = @"mine_nomal";
+    }
+    
+    [self.memberImage setImage:[UIImage imageNamed:viperImage]];
+    
+    [self.userAvatar sd_setImageWithURL:[NSURL URLWithString:[userInfo.avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:USERDEFAULT_LOGO]];
+    self.userName.text = [NSString returnNoNullStringWithString:userInfo.username];
+    self.userIdLabel.text = [NSString stringWithFormat:@"学号:%.0f",userInfo.userId];
+    self.userSubject.text = [NSString returnNoNullStringWithString:userInfo.subjectName];
+    NSString *sexString = userInfo.gender == 1 ? @"男生" : @"女生";
+    self.userSex.text = sexString;
+    
+    [self evaluateSource:musicArray];
+}
+
+- (void)evaluateSource:(NSArray *)musicArray {
+    [self.subjectView removeAllSubViews];
+    NSInteger count = musicArray.count > 3 ? 3 : musicArray.count;
+    for (NSInteger i = 0; i < count; i++) {
+        // 添加按钮
+        RecentMusicView *musicView = [RecentMusicView shareInstance];
+        musicView.frame = CGRectMake(0, 84 * i, KPortraitWidth - 28, 84);
+        BOOL hideLineView = i == count - 1 ? YES : NO;
+        MJWeakSelf;
+        [musicView configWithMusicModel:musicArray[i] hiddenLineView:hideLineView callback:^(NSString * _Nonnull songId) {
+            if (weakSelf.callback) {
+                weakSelf.callback(songId);
+            }
+        }];
+        [self.subjectView addSubview:musicView];
+    }
+}
+
+
++ (CGFloat)getViewHeight {
+    return 590.0f;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 262 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBodyView.xib

@@ -0,0 +1,262 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_0" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="UserDetailBodyView">
+            <rect key="frame" x="0.0" y="0.0" width="390" height="590"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PZG-4f-DTT">
+                    <rect key="frame" x="14" y="14" width="362" height="260"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="user_default_avatal" translatesAutoresizingMaskIntoConstraints="NO" id="GcD-Ic-cNt">
+                            <rect key="frame" x="20" y="18" width="60" height="60"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="60" id="JVv-tN-XaL"/>
+                                <constraint firstAttribute="height" constant="60" id="Wba-Pj-zV9"/>
+                            </constraints>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="30"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                        </imageView>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="mine_nomal" translatesAutoresizingMaskIntoConstraints="NO" id="jg5-7G-Opf">
+                            <rect key="frame" x="33" y="70.666666666666671" width="34" height="15"/>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="小学生" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uqG-dv-SFP">
+                            <rect key="frame" x="102" y="28" width="250" height="28"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="28" id="gND-vy-QU4"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
+                            <nil key="textColor"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="mine_uid" translatesAutoresizingMaskIntoConstraints="NO" id="lQk-hY-YEs">
+                            <rect key="frame" x="102" y="58" width="11" height="11"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="11" id="1C1-5S-Xgd"/>
+                                <constraint firstAttribute="width" constant="11" id="oAT-cl-3w2"/>
+                            </constraints>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="学号:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DqI-wn-gqn">
+                            <rect key="frame" x="119" y="56.666666666666671" width="26" height="14"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="11"/>
+                            <color key="textColor" red="0.41568627450980389" green="0.41568627450980389" blue="0.41568627450980389" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="12B-UP-hU5">
+                            <rect key="frame" x="14" y="104" width="334" height="140"/>
+                            <subviews>
+                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hj1-nm-c6u">
+                                    <rect key="frame" x="0.0" y="0.0" width="334" height="70"/>
+                                    <subviews>
+                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qQE-Ie-jl3">
+                                            <rect key="frame" x="32" y="69" width="270" height="1"/>
+                                            <color key="backgroundColor" red="0.92156862745098034" green="0.92156862745098034" blue="0.92156862745098034" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="1" id="oX0-Vo-8dT"/>
+                                            </constraints>
+                                        </view>
+                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_use_sex" translatesAutoresizingMaskIntoConstraints="NO" id="0IW-8X-S9p">
+                                            <rect key="frame" x="16" y="25" width="20" height="20"/>
+                                            <constraints>
+                                                <constraint firstAttribute="width" constant="20" id="1Hn-XA-lU9"/>
+                                                <constraint firstAttribute="height" constant="20" id="rsl-FF-840"/>
+                                            </constraints>
+                                        </imageView>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="性别:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ix6-yj-abW">
+                                            <rect key="frame" x="48" y="24.666666666666657" width="46" height="21"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="21" id="iYb-XU-9n5"/>
+                                            </constraints>
+                                            <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                            <color key="textColor" red="0.41568627450980389" green="0.41568627450980389" blue="0.41568627450980389" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yzA-J6-60W">
+                                            <rect key="frame" x="96" y="24.666666666666657" width="0.0" height="21"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="21" id="ex4-d4-aaT"/>
+                                            </constraints>
+                                            <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstItem="ix6-yj-abW" firstAttribute="leading" secondItem="0IW-8X-S9p" secondAttribute="trailing" constant="12" id="Apc-un-raT"/>
+                                        <constraint firstItem="0IW-8X-S9p" firstAttribute="leading" secondItem="hj1-nm-c6u" secondAttribute="leading" constant="16" id="B1I-A3-C5j"/>
+                                        <constraint firstAttribute="bottom" secondItem="qQE-Ie-jl3" secondAttribute="bottom" id="C07-uC-YMx"/>
+                                        <constraint firstItem="yzA-J6-60W" firstAttribute="leading" secondItem="ix6-yj-abW" secondAttribute="trailing" constant="2" id="Fh2-3H-lq5"/>
+                                        <constraint firstItem="ix6-yj-abW" firstAttribute="centerY" secondItem="0IW-8X-S9p" secondAttribute="centerY" id="QaC-OO-Q9I"/>
+                                        <constraint firstAttribute="trailing" secondItem="qQE-Ie-jl3" secondAttribute="trailing" constant="32" id="ZYu-6L-IMQ"/>
+                                        <constraint firstAttribute="height" constant="70" id="b9w-WV-Lu1"/>
+                                        <constraint firstItem="qQE-Ie-jl3" firstAttribute="leading" secondItem="hj1-nm-c6u" secondAttribute="leading" constant="32" id="jgA-eJ-D08"/>
+                                        <constraint firstItem="yzA-J6-60W" firstAttribute="centerY" secondItem="ix6-yj-abW" secondAttribute="centerY" id="lXh-bB-Kzd"/>
+                                        <constraint firstItem="0IW-8X-S9p" firstAttribute="top" secondItem="hj1-nm-c6u" secondAttribute="top" constant="25" id="xGr-WD-exr"/>
+                                    </constraints>
+                                </view>
+                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9Tm-F6-cRH">
+                                    <rect key="frame" x="0.0" y="70" width="334" height="70"/>
+                                    <subviews>
+                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_user_subject" translatesAutoresizingMaskIntoConstraints="NO" id="UAH-63-z5x">
+                                            <rect key="frame" x="16" y="26" width="20" height="20"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="20" id="mcV-aA-1d5"/>
+                                                <constraint firstAttribute="width" constant="20" id="wXX-gX-zou"/>
+                                            </constraints>
+                                        </imageView>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="声部:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m0W-G0-lyK">
+                                            <rect key="frame" x="48" y="25.666666666666657" width="46" height="21"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="21" id="ZpX-6w-BFn"/>
+                                            </constraints>
+                                            <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                            <color key="textColor" red="0.41568627450980389" green="0.41568627450980389" blue="0.41568627450980389" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ab0-kc-WGQ">
+                                            <rect key="frame" x="96" y="25.666666666666657" width="0.0" height="21"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="21" id="UID-JK-AxO"/>
+                                            </constraints>
+                                            <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstItem="m0W-G0-lyK" firstAttribute="centerY" secondItem="UAH-63-z5x" secondAttribute="centerY" id="5pP-U1-Bam"/>
+                                        <constraint firstAttribute="bottom" secondItem="UAH-63-z5x" secondAttribute="bottom" constant="24" id="DMw-no-t76"/>
+                                        <constraint firstAttribute="height" constant="70" id="VPx-An-l21"/>
+                                        <constraint firstItem="m0W-G0-lyK" firstAttribute="leading" secondItem="UAH-63-z5x" secondAttribute="trailing" constant="12" id="fVJ-PH-AuK"/>
+                                        <constraint firstItem="ab0-kc-WGQ" firstAttribute="leading" secondItem="m0W-G0-lyK" secondAttribute="trailing" constant="2" id="iPn-Dx-uIF"/>
+                                        <constraint firstItem="ab0-kc-WGQ" firstAttribute="centerY" secondItem="m0W-G0-lyK" secondAttribute="centerY" id="ttd-3q-Pnt"/>
+                                        <constraint firstItem="UAH-63-z5x" firstAttribute="leading" secondItem="9Tm-F6-cRH" secondAttribute="leading" constant="16" id="zoy-Jj-brJ"/>
+                                    </constraints>
+                                </view>
+                            </subviews>
+                            <color key="backgroundColor" red="0.98431372549019602" green="0.98431372549019602" blue="0.98431372549019602" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <constraints>
+                                <constraint firstItem="hj1-nm-c6u" firstAttribute="leading" secondItem="12B-UP-hU5" secondAttribute="leading" id="Dhd-cE-bQZ"/>
+                                <constraint firstAttribute="bottom" secondItem="9Tm-F6-cRH" secondAttribute="bottom" id="G5t-fa-o3t"/>
+                                <constraint firstItem="9Tm-F6-cRH" firstAttribute="leading" secondItem="12B-UP-hU5" secondAttribute="leading" id="GVz-DI-Unz"/>
+                                <constraint firstAttribute="height" constant="140" id="HrN-xc-PpS"/>
+                                <constraint firstAttribute="trailing" secondItem="9Tm-F6-cRH" secondAttribute="trailing" id="S31-dv-6T3"/>
+                                <constraint firstItem="hj1-nm-c6u" firstAttribute="top" secondItem="12B-UP-hU5" secondAttribute="top" id="T8N-N8-q7O"/>
+                                <constraint firstAttribute="trailing" secondItem="hj1-nm-c6u" secondAttribute="trailing" id="oxR-Wc-y9H"/>
+                            </constraints>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                        </view>
+                    </subviews>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <constraints>
+                        <constraint firstAttribute="trailing" secondItem="uqG-dv-SFP" secondAttribute="trailing" constant="10" id="5kI-Jt-1ZK"/>
+                        <constraint firstItem="GcD-Ic-cNt" firstAttribute="top" secondItem="PZG-4f-DTT" secondAttribute="top" constant="18" id="A7Y-Nv-r6T"/>
+                        <constraint firstAttribute="bottom" secondItem="12B-UP-hU5" secondAttribute="bottom" constant="16" id="Muy-ZG-G0i"/>
+                        <constraint firstItem="jg5-7G-Opf" firstAttribute="centerY" secondItem="GcD-Ic-cNt" secondAttribute="bottom" id="Nro-XE-qIB"/>
+                        <constraint firstItem="lQk-hY-YEs" firstAttribute="top" secondItem="uqG-dv-SFP" secondAttribute="bottom" constant="2" id="UoT-Yy-bZY"/>
+                        <constraint firstItem="jg5-7G-Opf" firstAttribute="centerX" secondItem="GcD-Ic-cNt" secondAttribute="centerX" id="WMk-9B-Rph"/>
+                        <constraint firstItem="jg5-7G-Opf" firstAttribute="centerX" secondItem="GcD-Ic-cNt" secondAttribute="centerX" id="XXW-0R-FeT"/>
+                        <constraint firstItem="DqI-wn-gqn" firstAttribute="centerY" secondItem="lQk-hY-YEs" secondAttribute="centerY" id="Zss-Ml-3Pg"/>
+                        <constraint firstItem="GcD-Ic-cNt" firstAttribute="leading" secondItem="PZG-4f-DTT" secondAttribute="leading" constant="20" id="Zxm-3W-KTH"/>
+                        <constraint firstItem="uqG-dv-SFP" firstAttribute="leading" secondItem="GcD-Ic-cNt" secondAttribute="trailing" constant="22" id="hed-Y5-7uo"/>
+                        <constraint firstItem="12B-UP-hU5" firstAttribute="leading" secondItem="PZG-4f-DTT" secondAttribute="leading" constant="14" id="lYx-aq-8hM"/>
+                        <constraint firstItem="lQk-hY-YEs" firstAttribute="leading" secondItem="uqG-dv-SFP" secondAttribute="leading" id="m4h-Dp-o7j"/>
+                        <constraint firstAttribute="height" constant="260" id="nNJ-Bm-ZKA"/>
+                        <constraint firstItem="DqI-wn-gqn" firstAttribute="leading" secondItem="lQk-hY-YEs" secondAttribute="trailing" constant="6" id="ncp-Rd-256"/>
+                        <constraint firstItem="uqG-dv-SFP" firstAttribute="top" secondItem="GcD-Ic-cNt" secondAttribute="top" constant="10" id="rmL-EW-AQF"/>
+                        <constraint firstAttribute="trailing" secondItem="12B-UP-hU5" secondAttribute="trailing" constant="14" id="wZj-Kh-Ydp"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="16"/>
+                        </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="bhE-25-YYz">
+                    <rect key="frame" x="40" y="290" width="66" height="22"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="22" id="F6D-gT-EVx"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
+                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="home_left" translatesAutoresizingMaskIntoConstraints="NO" id="Jaj-wc-QDp">
+                    <rect key="frame" x="28" y="294" width="4" height="14"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="4" id="aMk-us-iHn"/>
+                        <constraint firstAttribute="height" constant="14" id="ek9-ya-EuK"/>
+                    </constraints>
+                </imageView>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JQZ-qL-qfG">
+                    <rect key="frame" x="14" y="328" width="362" height="252"/>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="252" id="12e-F9-uGR"/>
+                    </constraints>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="16"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="Jaj-wc-QDp" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="28" id="57y-60-JMr"/>
+                <constraint firstAttribute="trailing" secondItem="JQZ-qL-qfG" secondAttribute="trailing" constant="14" id="6ra-2M-rfP"/>
+                <constraint firstAttribute="trailing" secondItem="PZG-4f-DTT" secondAttribute="trailing" constant="14" id="D1K-zh-6wT"/>
+                <constraint firstItem="JQZ-qL-qfG" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="EOI-s2-CoO"/>
+                <constraint firstItem="Jaj-wc-QDp" firstAttribute="top" secondItem="PZG-4f-DTT" secondAttribute="bottom" constant="20" id="Fe6-GE-aJU"/>
+                <constraint firstItem="PZG-4f-DTT" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="ITv-tX-SAD"/>
+                <constraint firstItem="bhE-25-YYz" firstAttribute="centerY" secondItem="Jaj-wc-QDp" secondAttribute="centerY" id="PQr-vE-aih"/>
+                <constraint firstItem="bhE-25-YYz" firstAttribute="leading" secondItem="Jaj-wc-QDp" secondAttribute="trailing" constant="8" id="Ppz-Sd-W4W"/>
+                <constraint firstItem="PZG-4f-DTT" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="14" id="W87-6D-MF1"/>
+                <constraint firstItem="JQZ-qL-qfG" firstAttribute="top" secondItem="bhE-25-YYz" secondAttribute="bottom" constant="16" id="YQ8-Bi-xhj"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="memberImage" destination="jg5-7G-Opf" id="KTP-VB-YuG"/>
+                <outlet property="subjectView" destination="JQZ-qL-qfG" id="53i-9H-Tem"/>
+                <outlet property="subjectViewHeight" destination="12e-F9-uGR" id="laI-yK-4Ze"/>
+                <outlet property="userAvatar" destination="GcD-Ic-cNt" id="Y4k-qy-4L4"/>
+                <outlet property="userIdLabel" destination="DqI-wn-gqn" id="UO0-J2-gy1"/>
+                <outlet property="userName" destination="uqG-dv-SFP" id="7BT-p0-2Ri"/>
+                <outlet property="userSex" destination="yzA-J6-60W" id="0Rv-2j-Tpc"/>
+                <outlet property="userSubject" destination="ab0-kc-WGQ" id="3aw-Ip-Xr2"/>
+            </connections>
+            <point key="canvasLocation" x="101.53846153846153" y="0.35545023696682465"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="chat_use_sex" width="20" height="20"/>
+        <image name="chat_user_subject" width="20" height="20"/>
+        <image name="home_left" width="4" height="12"/>
+        <image name="mine_nomal" width="34" height="15"/>
+        <image name="mine_uid" width="11" height="11"/>
+        <image name="user_default_avatal" width="52" height="52"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBottomView.h

@@ -0,0 +1,18 @@
+//
+//  UserDetailBottomView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface UserDetailBottomView : UIView
+
++ (instancetype)shareInstance;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 25 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBottomView.m

@@ -0,0 +1,25 @@
+//
+//  UserDetailBottomView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import "UserDetailBottomView.h"
+
+@implementation UserDetailBottomView
+
+
++ (instancetype)shareInstance {
+    UserDetailBottomView *view = [[[NSBundle mainBundle] loadNibNamed:@"UserDetailBottomView" owner:nil options:nil] firstObject];
+    return view;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 37 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailBottomView.xib

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_0" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="UserDetailBottomView">
+            <rect key="frame" x="0.0" y="0.0" width="390" height="50"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="——最多显示3首最近练习曲目——" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HjU-rU-MRE">
+                    <rect key="frame" x="102.66666666666669" y="10" width="185" height="17"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="17" id="hAN-8A-cAE"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                    <color key="textColor" red="0.84705882352941175" green="0.84705882352941175" blue="0.84705882352941175" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="HjU-rU-MRE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="10" id="e9c-yn-o5Y"/>
+                <constraint firstItem="HjU-rU-MRE" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="wBY-p3-nzh"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <point key="canvasLocation" x="101.53846153846153" y="-294.31279620853081"/>
+        </view>
+    </objects>
+</document>

+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailNavView.h

@@ -0,0 +1,22 @@
+//
+//  UserDetailNavView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef void(^UserDetailCallback)(void);
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface UserDetailNavView : UIView
+
++ (instancetype)shareInstance;
+
+- (void)navAction:(UserDetailCallback)callback;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 44 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailNavView.m

@@ -0,0 +1,44 @@
+//
+//  UserDetailNavView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import "UserDetailNavView.h"
+
+@interface UserDetailNavView ()
+
+@property (nonatomic, copy) UserDetailCallback callback;
+
+@end
+
+@implementation UserDetailNavView
+
+
++ (instancetype)shareInstance {
+    UserDetailNavView *view = [[[NSBundle mainBundle] loadNibNamed:@"UserDetailNavView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)navAction:(UserDetailCallback)callback {
+    if (callback) {
+        self.callback = callback;
+    }
+}
+
+- (IBAction)navBack:(id)sender {
+    if (self.callback) {
+        self.callback();
+    }
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 69 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ChatUserInfo/UserDetailNavView.xib

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_0" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="UserDetailNavView">
+            <rect key="frame" x="0.0" y="0.0" width="390" height="99"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cmT-0r-dtM">
+                    <rect key="frame" x="0.0" y="55" width="390" height="44"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="back_black" translatesAutoresizingMaskIntoConstraints="NO" id="oFb-jc-rdF">
+                            <rect key="frame" x="15" y="12" width="12" height="20"/>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zKt-ob-UOF">
+                            <rect key="frame" x="0.0" y="2" width="40" height="40"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="40" id="FY2-IW-0aw"/>
+                                <constraint firstAttribute="height" constant="40" id="qdY-9n-Jyq"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <connections>
+                                <action selector="navBack:" destination="iN0-l3-epB" eventType="touchUpInside" id="med-KT-Eh5"/>
+                            </connections>
+                        </button>
+                        <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="用户信息" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qeQ-Mp-wpl">
+                            <rect key="frame" x="158" y="11" width="74" height="22"/>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="qeQ-Mp-wpl" firstAttribute="centerX" secondItem="cmT-0r-dtM" secondAttribute="centerX" id="3og-nk-hMl"/>
+                        <constraint firstItem="zKt-ob-UOF" firstAttribute="leading" secondItem="cmT-0r-dtM" secondAttribute="leading" id="A3m-xm-Gie"/>
+                        <constraint firstAttribute="height" constant="44" id="CMG-cf-z7o"/>
+                        <constraint firstItem="oFb-jc-rdF" firstAttribute="leading" secondItem="cmT-0r-dtM" secondAttribute="leading" constant="15" id="QJG-dR-rbA"/>
+                        <constraint firstItem="zKt-ob-UOF" firstAttribute="centerY" secondItem="cmT-0r-dtM" secondAttribute="centerY" id="dh7-1N-2Ie"/>
+                        <constraint firstItem="qeQ-Mp-wpl" firstAttribute="centerY" secondItem="cmT-0r-dtM" secondAttribute="centerY" id="ruV-G5-w80"/>
+                        <constraint firstItem="zKt-ob-UOF" firstAttribute="centerY" secondItem="oFb-jc-rdF" secondAttribute="centerY" id="uDO-d6-JEH"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="cmT-0r-dtM" secondAttribute="trailing" id="Z0Y-10-LJj"/>
+                <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="cmT-0r-dtM" secondAttribute="bottom" id="elp-pb-Di9"/>
+                <constraint firstItem="cmT-0r-dtM" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="s4K-nc-Krq"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <point key="canvasLocation" x="101.53846153846153" y="13.151658767772512"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="back_black" width="12" height="20"/>
+    </resources>
+</document>

+ 8 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ContractListCell.m

@@ -14,6 +14,8 @@
 
 @property (weak, nonatomic) IBOutlet UILabel *friendName;
 
+@property (weak, nonatomic) IBOutlet UIImageView *roleType;
+
 @end
 
 @implementation ContractListCell
@@ -35,6 +37,12 @@
             self.friendName.text = model.friendNickname;
         }
         self.friendName.text = [NSString returnNoNullStringWithString:model.friendNickname];
+        if ([model.roleType isEqualToString:@"TEACHER"]) {
+            self.roleType.hidden = NO;
+        }
+        else {
+            self.roleType.hidden = YES;
+        }
     }
 }
 

+ 14 - 3
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ContractListCell.xib

@@ -1,9 +1,9 @@
 <?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">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" 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"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -25,7 +25,7 @@
                         </constraints>
                         <userDefinedRuntimeAttributes>
                             <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                <real key="value" value="6"/>
+                                <real key="value" value="4"/>
                             </userDefinedRuntimeAttribute>
                         </userDefinedRuntimeAttributes>
                     </imageView>
@@ -45,13 +45,22 @@
                             <constraint firstAttribute="height" constant="1" id="pLM-MY-tjk"/>
                         </constraints>
                     </view>
+                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_talentList" translatesAutoresizingMaskIntoConstraints="NO" id="wE9-mv-fQZ">
+                        <rect key="frame" x="14" y="50.5" width="44" height="14"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="14" id="31K-VC-pL8"/>
+                            <constraint firstAttribute="width" constant="44" id="hUJ-sa-RuA"/>
+                        </constraints>
+                    </imageView>
                 </subviews>
                 <constraints>
                     <constraint firstItem="8fl-pa-IHx" firstAttribute="centerY" secondItem="vI1-v5-uMm" secondAttribute="centerY" id="9PL-c3-9J3"/>
+                    <constraint firstItem="wE9-mv-fQZ" firstAttribute="centerX" secondItem="vI1-v5-uMm" secondAttribute="centerX" id="Bi2-yQ-N9p"/>
                     <constraint firstItem="ZD7-0R-OoK" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="72" id="DPF-fF-mtx"/>
                     <constraint firstAttribute="bottom" secondItem="ZD7-0R-OoK" secondAttribute="bottom" id="Qy0-N6-dQU"/>
                     <constraint firstItem="8fl-pa-IHx" firstAttribute="leading" secondItem="vI1-v5-uMm" secondAttribute="trailing" constant="11" id="fdz-o1-pUv"/>
                     <constraint firstAttribute="trailing" secondItem="ZD7-0R-OoK" secondAttribute="trailing" id="qkd-cr-TeW"/>
+                    <constraint firstItem="wE9-mv-fQZ" firstAttribute="bottom" secondItem="vI1-v5-uMm" secondAttribute="bottom" id="vb6-na-6sB"/>
                     <constraint firstItem="vI1-v5-uMm" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="vgm-ZS-Nds"/>
                     <constraint firstItem="vI1-v5-uMm" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="yHs-ea-3Xd"/>
                 </constraints>
@@ -61,11 +70,13 @@
             <connections>
                 <outlet property="friendAvatar" destination="vI1-v5-uMm" id="U0E-W5-93f"/>
                 <outlet property="friendName" destination="8fl-pa-IHx" id="ADl-id-NuZ"/>
+                <outlet property="roleType" destination="wE9-mv-fQZ" id="DhH-hR-dPW"/>
             </connections>
             <point key="canvasLocation" x="178.2608695652174" y="95.424107142857139"/>
         </tableViewCell>
     </objects>
     <resources>
         <image name="chat_personLogo" width="44" height="44"/>
+        <image name="chat_talentList" width="44" height="14"/>
     </resources>
 </document>

+ 16 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatTagView.h

@@ -0,0 +1,16 @@
+//
+//  KSChatTagView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSChatTagView : UIImageView
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 20 - 0
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/KSChatTagView.m

@@ -0,0 +1,20 @@
+//
+//  KSChatTagView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/10/18.
+//
+
+#import "KSChatTagView.h"
+
+@implementation KSChatTagView
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 14 - 7
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ShareLiveCellContentView.xib

@@ -1,9 +1,9 @@
 <?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" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -15,7 +15,7 @@
             <autoresizingMask key="autoresizingMask"/>
             <subviews>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yd2-ur-hRq">
-                    <rect key="frame" x="88" y="0.0" width="260" height="161"/>
+                    <rect key="frame" x="84" y="0.0" width="260" height="161"/>
                     <subviews>
                         <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i7L-q9-DkS">
                             <rect key="frame" x="14" y="11" width="44" height="44"/>
@@ -162,25 +162,30 @@
                     </userDefinedRuntimeAttributes>
                 </view>
                 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="user_avatarRectangle" translatesAutoresizingMaskIntoConstraints="NO" id="gSu-yX-K9X">
-                    <rect key="frame" x="14" y="0.0" width="44" height="44"/>
+                    <rect key="frame" x="14" y="0.0" width="40" height="40"/>
                     <constraints>
-                        <constraint firstAttribute="width" constant="44" id="0EV-n1-hvY"/>
-                        <constraint firstAttribute="height" constant="44" id="T7L-RF-8bB"/>
+                        <constraint firstAttribute="width" constant="40" id="0EV-n1-hvY"/>
+                        <constraint firstAttribute="height" constant="40" id="T7L-RF-8bB"/>
                     </constraints>
                     <userDefinedRuntimeAttributes>
                         <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                            <real key="value" value="6"/>
+                            <real key="value" value="4"/>
                         </userDefinedRuntimeAttribute>
                     </userDefinedRuntimeAttributes>
                 </imageView>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_talentTag" translatesAutoresizingMaskIntoConstraints="NO" id="VIe-sF-XAw">
+                    <rect key="frame" x="14" y="27" width="40" height="13"/>
+                </imageView>
             </subviews>
             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
             <constraints>
                 <constraint firstItem="gSu-yX-K9X" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="7t6-aT-d6Z"/>
                 <constraint firstItem="yd2-ur-hRq" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="K8Q-lg-bH5"/>
+                <constraint firstItem="VIe-sF-XAw" firstAttribute="bottom" secondItem="gSu-yX-K9X" secondAttribute="bottom" id="ZDk-tE-Bn1"/>
                 <constraint firstItem="yd2-ur-hRq" firstAttribute="leading" secondItem="gSu-yX-K9X" secondAttribute="trailing" constant="30" id="jfK-m2-EUj"/>
                 <constraint firstItem="gSu-yX-K9X" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="mo9-mn-GBo"/>
                 <constraint firstAttribute="bottom" secondItem="yd2-ur-hRq" secondAttribute="bottom" id="uhj-Y8-HNb"/>
+                <constraint firstItem="VIe-sF-XAw" firstAttribute="centerX" secondItem="gSu-yX-K9X" secondAttribute="centerX" id="xMw-6H-OQN"/>
             </constraints>
             <nil key="simulatedTopBarMetrics"/>
             <nil key="simulatedBottomBarMetrics"/>
@@ -188,12 +193,14 @@
             <connections>
                 <outlet property="descLabel" destination="mG8-MH-eZ7" id="wsa-O9-VBC"/>
                 <outlet property="teacherAvatar" destination="SJI-XW-kBi" id="KNc-50-GWC"/>
+                <outlet property="teacher_info" destination="gSu-yX-K9X" id="G0M-44-is1"/>
                 <outlet property="waitDesc" destination="q2Q-aP-HCM" id="VLq-wX-8Sa"/>
             </connections>
             <point key="canvasLocation" x="132.60869565217394" y="-180.46875"/>
         </view>
     </objects>
     <resources>
+        <image name="chat_talentTag" width="40" height="13"/>
         <image name="user_avatarRectangle" width="44" height="44"/>
         <image name="user_default_avatal" width="52" height="52"/>
         <systemColor name="systemBackgroundColor">

+ 13 - 7
KulexiuForStudent/KulexiuForStudent/Module/Chat/View/ShareMusicCellContentView.xib

@@ -1,9 +1,9 @@
 <?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" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -15,7 +15,7 @@
             <autoresizingMask key="autoresizingMask"/>
             <subviews>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UDH-9B-8f6">
-                    <rect key="frame" x="88" y="0.0" width="260" height="100"/>
+                    <rect key="frame" x="84" y="0.0" width="260" height="100"/>
                     <subviews>
                         <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="music_logo" translatesAutoresizingMaskIntoConstraints="NO" id="TNu-dS-bgv">
                             <rect key="frame" x="11" y="10" width="41" height="40"/>
@@ -113,24 +113,29 @@
                     </userDefinedRuntimeAttributes>
                 </view>
                 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="user_avatarRectangle" translatesAutoresizingMaskIntoConstraints="NO" id="P84-NW-Sav">
-                    <rect key="frame" x="14" y="0.0" width="44" height="44"/>
+                    <rect key="frame" x="14" y="0.0" width="40" height="40"/>
                     <constraints>
-                        <constraint firstAttribute="width" constant="44" id="XPk-Kv-NCK"/>
-                        <constraint firstAttribute="height" constant="44" id="vqV-sI-xZc"/>
+                        <constraint firstAttribute="width" constant="40" id="XPk-Kv-NCK"/>
+                        <constraint firstAttribute="height" constant="40" id="vqV-sI-xZc"/>
                     </constraints>
                     <userDefinedRuntimeAttributes>
                         <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                            <real key="value" value="6"/>
+                            <real key="value" value="4"/>
                         </userDefinedRuntimeAttribute>
                     </userDefinedRuntimeAttributes>
                 </imageView>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_talentTag" translatesAutoresizingMaskIntoConstraints="NO" id="X63-Z5-XIk">
+                    <rect key="frame" x="14" y="27" width="40" height="13"/>
+                </imageView>
             </subviews>
             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
             <constraints>
                 <constraint firstItem="UDH-9B-8f6" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="OJt-lz-uN2"/>
+                <constraint firstItem="X63-Z5-XIk" firstAttribute="centerX" secondItem="P84-NW-Sav" secondAttribute="centerX" id="Sf3-UM-fib"/>
                 <constraint firstItem="P84-NW-Sav" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="YBF-NS-EjE"/>
                 <constraint firstAttribute="bottom" secondItem="UDH-9B-8f6" secondAttribute="bottom" id="iQY-mQ-cgC"/>
                 <constraint firstItem="UDH-9B-8f6" firstAttribute="leading" secondItem="P84-NW-Sav" secondAttribute="trailing" constant="30" id="jlg-BL-151"/>
+                <constraint firstItem="X63-Z5-XIk" firstAttribute="bottom" secondItem="P84-NW-Sav" secondAttribute="bottom" id="k5a-5q-tQM"/>
                 <constraint firstItem="P84-NW-Sav" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="14" id="xEF-rR-LNy"/>
             </constraints>
             <nil key="simulatedTopBarMetrics"/>
@@ -148,6 +153,7 @@
         </view>
     </objects>
     <resources>
+        <image name="chat_talentTag" width="40" height="13"/>
         <image name="music_free" width="55" height="22"/>
         <image name="music_logo" width="41" height="40"/>
         <image name="user_avatarRectangle" width="44" height="44"/>

+ 3 - 23
KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m

@@ -43,7 +43,6 @@
 #import "HomeHotMusicCollectionCell.h"
 #import "KSPremissionAlert.h"
 #import "RecordCheckManager.h"
-#import "KSAccompanyWebViewController.h"
 
 #import "HomeHotTalentView.h"
 #import "HomeHotTalentCell.h"
@@ -1304,28 +1303,9 @@
 }
 
 - (void)displaySongDetail:(NSString *)songId {
-    // 检测权限
-    PREMISSIONTYPE micEnable = [RecordCheckManager checkPermissionShowAlert:NO showInView:nil];
-    PREMISSIONTYPE cameraEnable = [RecordCheckManager checkCameraPremissionAvaiable:NO showInView:nil];
-    if (micEnable == PREMISSIONTYPE_YES && cameraEnable == PREMISSIONTYPE_YES) { // 如果麦克风和摄像头权限都有
-        // 跳转到播放页面
-        KSAccompanyWebViewController *detailCtrl = [[KSAccompanyWebViewController alloc] init];
-        detailCtrl.url = [NSString stringWithFormat:@"%@/accompany?id=%@",hostURL, songId];
-        detailCtrl.hiddenNavBar = YES;
-        detailCtrl.parmDic = @{@"isOpenLight" : @(YES), @"orientation" : @(0),@"isHideTitle" : @(YES)};
-        [self.navigationController pushViewController:detailCtrl animated:YES];
-    }
-    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];
-        }
-    }
+    KSBaseWKWebViewController *ctrl = [[KSBaseWKWebViewController alloc] init];
+    ctrl.url = [NSString stringWithFormat:@"%@%@%@", WEBHOST, @"/#/music-detail?id=",songId];
+    [self.navigationController pushViewController:ctrl animated:YES];
 }
 
 - (void)showAlertWithMessage:(NSString *)message type:(CHECKDEVICETYPE)deviceType {

+ 5 - 2
KulexiuForStudent/KulexiuForStudent/Module/Home/View/HotAlbum/HomeHotAlbumCell.xib

@@ -29,8 +29,12 @@
                             </userDefinedRuntimeAttribute>
                         </userDefinedRuntimeAttributes>
                     </imageView>
-                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="albumTag_VIP" translatesAutoresizingMaskIntoConstraints="NO" id="kDC-Ga-mwz">
+                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kDC-Ga-mwz">
                         <rect key="frame" x="3" y="10" width="26" height="14"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="14" id="AsP-cc-yFn"/>
+                            <constraint firstAttribute="width" constant="26" id="OT8-nr-3ZS"/>
+                        </constraints>
                     </imageView>
                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="萨克斯新手…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1bh-Zm-ov0">
                         <rect key="frame" x="3" y="114" width="94" height="20"/>
@@ -110,7 +114,6 @@
         </collectionViewCell>
     </objects>
     <resources>
-        <image name="albumTag_VIP" width="26" height="14"/>
         <image name="album_collect" width="8" height="8"/>
         <image name="video_placeholder" width="103" height="72"/>
     </resources>

+ 0 - 40
KulexiuForStudent/KulexiuForStudent/Module/Home/View/HotMusic/HomeHotMusicCellView.m

@@ -9,8 +9,6 @@
 #import "MusicTagView.h"
 
 @interface HomeHotMusicCellView ()
-@property (weak, nonatomic) IBOutlet UIView *typeView;
-@property (weak, nonatomic) IBOutlet NSLayoutConstraint *typeViewWidth;
 
 @property (weak, nonatomic) IBOutlet UILabel *songNameLabel;
 @property (weak, nonatomic) IBOutlet UILabel *songAuth;
@@ -25,7 +23,6 @@
 
 @property (weak, nonatomic) IBOutlet UIImageView *qualityMusicTag;
 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *qualityTagWidth;
-@property (weak, nonatomic) IBOutlet NSLayoutConstraint *qualityLeft;
 
 @property (weak, nonatomic) IBOutlet UIImageView *albumTag;
 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *albumTagWidth;
@@ -47,12 +44,10 @@
     if (sourceModel.exquisiteFlag) {
         self.qualityMusicTag.hidden = NO;
         self.qualityTagWidth.constant = 14.0f;
-        self.qualityLeft.constant = 5.0f;
     }
     else {
         self.qualityMusicTag.hidden = NO;
         self.qualityTagWidth.constant = 0.0f;
-        self.qualityLeft.constant = 0.0f;
     }
     
     if (sourceModel.albumNums > 0) {
@@ -116,43 +111,8 @@
     [self configTagViewWithTagArray:tagArray maxWidth:maxWidth];
     self.lineView.hidden = hideLineView;
     
-    [self configTypeView:sourceModel.paymentType];
 }
 
-- (void)configTypeView:(NSString *)musicType {
-    [self.typeView removeAllSubViews];
-    NSArray * chargeArray = [musicType componentsSeparatedByString:@","];
-    CGFloat singleWidth = 30.0f;
-    CGFloat space = 5.0f;
-    CGFloat height = 17.0f;
-    for (NSInteger index = 0; index < chargeArray.count; index++) {
-        NSString *desc = chargeArray[index];
-        NSString *title = nil;
-        UIColor *borderColor = nil;
-        UIColor *titleColor = nil;
-        if ([desc isEqualToString:@"VIP"]) {
-            borderColor = HexRGB(0xD38535);
-            title = @"会员";
-            titleColor = HexRGB(0xCD863E);
-            
-        }
-        else if ([desc isEqualToString:@"CHARGE"]) {
-            borderColor = HexRGB(0x50A2D8);
-            title = @"点播";
-            titleColor = HexRGB(0x3591CE);
-        }
-        else {
-            borderColor = HexRGB(0x01B84F);
-            title = @"免费";
-            titleColor = HexRGB(0x01B84F);
-        }
-        CGRect frame = CGRectMake((singleWidth + space) * index, 0, singleWidth, height);
-        MusicTagView *typeView = [[MusicTagView alloc] initWithTitle:title titleColor:titleColor borderColor:borderColor];
-        typeView.frame = frame;
-        [self.typeView addSubview:typeView];
-    }
-    self.typeViewWidth.constant = [self getWidthWithTypeCount:chargeArray.count singleWidth:singleWidth space:space];
-}
 
 - (CGFloat)getWidthWithTypeCount:(NSInteger)count singleWidth:(CGFloat)singleWidth space:(CGFloat)space {
     if (count == 1) {

+ 13 - 28
KulexiuForStudent/KulexiuForStudent/Module/Home/View/HotMusic/HomeHotMusicCellView.xib

@@ -4,7 +4,6 @@
     <dependencies>
         <deployment identifier="iOS"/>
         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
-        <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -14,28 +13,20 @@
             <rect key="frame" x="0.0" y="0.0" width="414" height="80"/>
             <autoresizingMask key="autoresizingMask"/>
             <subviews>
-                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="N1D-TV-iWW">
-                    <rect key="frame" x="11" y="19" width="30" height="17"/>
-                    <color key="backgroundColor" systemColor="systemBackgroundColor"/>
-                    <constraints>
-                        <constraint firstAttribute="height" constant="17" id="3Gw-3t-MVY"/>
-                        <constraint firstAttribute="width" constant="30" id="Fkh-p3-6cV"/>
-                    </constraints>
-                </view>
                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="最伟大的作品" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7xw-r5-qc1">
-                    <rect key="frame" x="85" y="17.666666666666668" width="98" height="20.000000000000004"/>
+                    <rect key="frame" x="50" y="17.5" width="98" height="20"/>
                     <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>
                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-周杰伦" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jm2-P7-5K9">
-                    <rect key="frame" x="188" y="20" width="43" height="15"/>
+                    <rect key="frame" x="153" y="20" width="43" height="15"/>
                     <fontDescription key="fontDescription" type="system" pointSize="12"/>
                     <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="yx5-8B-fUi">
-                    <rect key="frame" x="11" y="49.666666666666664" width="123" height="14.999999999999993"/>
+                    <rect key="frame" x="11" y="49.5" width="123" height="15"/>
                     <fontDescription key="fontDescription" type="system" pointSize="12"/>
                     <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
                     <nil key="highlightedColor"/>
@@ -55,28 +46,28 @@
                     </constraints>
                 </view>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="28W-1K-xs7">
-                    <rect key="frame" x="11" y="79.666666666666671" width="390" height="0.3333333333333286"/>
+                    <rect key="frame" x="11" y="79.5" width="390" height="0.5"/>
                     <color key="backgroundColor" red="0.90980392160000001" green="0.90980392160000001" blue="0.90980392160000001" alpha="1" colorSpace="calibratedRGB"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="0.5" id="MXY-Ik-nnJ"/>
                     </constraints>
                 </view>
                 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="quality_tag" translatesAutoresizingMaskIntoConstraints="NO" id="nUD-13-vp7">
-                    <rect key="frame" x="46" y="19" width="14" height="17"/>
+                    <rect key="frame" x="11" y="19" width="14" height="17"/>
                     <constraints>
                         <constraint firstAttribute="width" constant="14" id="1wc-7R-Rd1"/>
                         <constraint firstAttribute="height" constant="17" id="dpI-He-aFb"/>
                     </constraints>
                 </imageView>
                 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="music_albumTag" translatesAutoresizingMaskIntoConstraints="NO" id="Cxx-YR-LH0">
-                    <rect key="frame" x="65" y="20" width="15" height="15"/>
+                    <rect key="frame" x="30" y="20" width="15" height="15"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="15" id="Aq4-Sd-bfE"/>
                         <constraint firstAttribute="width" constant="15" id="Hqu-Jg-wlv"/>
                     </constraints>
                 </imageView>
-                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fGG-J1-J8q">
-                    <rect key="frame" x="0.0" y="0.0" width="414" height="80"/>
+                <button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fGG-J1-J8q">
+                    <rect key="frame" x="0.0" y="73" width="414" height="7"/>
                     <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                     <connections>
                         <action selector="buttonAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="fvd-A1-IJ7"/>
@@ -86,14 +77,13 @@
             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
             <constraints>
                 <constraint firstItem="Cxx-YR-LH0" firstAttribute="leading" secondItem="nUD-13-vp7" secondAttribute="trailing" constant="5" id="5pk-CX-qTO"/>
-                <constraint firstItem="nUD-13-vp7" firstAttribute="centerY" secondItem="N1D-TV-iWW" secondAttribute="centerY" id="9kp-XG-xs3"/>
+                <constraint firstItem="jm2-P7-5K9" firstAttribute="centerY" secondItem="nUD-13-vp7" secondAttribute="centerY" id="8Df-38-wBZ"/>
                 <constraint firstItem="6eO-qE-g8x" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="jm2-P7-5K9" secondAttribute="trailing" constant="10" id="BiV-XL-Qww"/>
                 <constraint firstAttribute="bottom" secondItem="28W-1K-xs7" secondAttribute="bottom" id="EEi-j6-bXC"/>
-                <constraint firstItem="N1D-TV-iWW" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="19" id="Gyv-2L-yeF"/>
                 <constraint firstItem="qrG-kH-VRz" firstAttribute="leading" secondItem="yx5-8B-fUi" secondAttribute="trailing" constant="12" id="Jbt-JJ-kdQ"/>
-                <constraint firstItem="nUD-13-vp7" firstAttribute="leading" secondItem="N1D-TV-iWW" secondAttribute="trailing" constant="5" id="LNt-pH-K0U"/>
+                <constraint firstItem="nUD-13-vp7" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="11" id="LPV-d4-FC2"/>
+                <constraint firstItem="nUD-13-vp7" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="19" id="MJK-gK-3ZK"/>
                 <constraint firstAttribute="trailing" secondItem="6eO-qE-g8x" secondAttribute="trailing" constant="19" id="OFX-bH-zcc"/>
-                <constraint firstItem="N1D-TV-iWW" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="11" id="Q0e-D9-JXV"/>
                 <constraint firstItem="6eO-qE-g8x" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="Rjr-rO-hGW"/>
                 <constraint firstItem="28W-1K-xs7" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="11" id="XMy-D4-KQK"/>
                 <constraint firstItem="qrG-kH-VRz" firstAttribute="centerY" secondItem="yx5-8B-fUi" secondAttribute="centerY" id="cMa-5P-a2v"/>
@@ -102,13 +92,14 @@
                 <constraint firstAttribute="trailing" secondItem="28W-1K-xs7" secondAttribute="trailing" constant="13" id="dez-R9-Ydg"/>
                 <constraint firstAttribute="trailing" secondItem="fGG-J1-J8q" secondAttribute="trailing" id="j3e-Gz-5as"/>
                 <constraint firstAttribute="bottom" secondItem="fGG-J1-J8q" secondAttribute="bottom" id="jNd-iF-vI9"/>
+                <constraint firstItem="Cxx-YR-LH0" firstAttribute="centerY" secondItem="nUD-13-vp7" secondAttribute="centerY" id="kZa-Al-n5x"/>
                 <constraint firstItem="fGG-J1-J8q" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="kze-In-Wh4"/>
                 <constraint firstItem="yx5-8B-fUi" firstAttribute="top" secondItem="7xw-r5-qc1" secondAttribute="bottom" constant="12" id="mYI-IW-FYA"/>
+                <constraint firstItem="7xw-r5-qc1" firstAttribute="centerY" secondItem="nUD-13-vp7" secondAttribute="centerY" id="oeg-QU-t4I"/>
                 <constraint firstItem="jm2-P7-5K9" firstAttribute="leading" secondItem="7xw-r5-qc1" secondAttribute="trailing" constant="5" id="p5D-Tn-1Ab"/>
                 <constraint firstItem="jm2-P7-5K9" firstAttribute="centerY" secondItem="7xw-r5-qc1" secondAttribute="centerY" id="rq7-V0-xTf"/>
                 <constraint firstItem="yx5-8B-fUi" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="11" id="tKz-3F-Rw0"/>
                 <constraint firstItem="fGG-J1-J8q" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="vln-aR-Mmc"/>
-                <constraint firstItem="7xw-r5-qc1" firstAttribute="centerY" secondItem="N1D-TV-iWW" secondAttribute="centerY" id="xew-7a-geL"/>
                 <constraint firstItem="7xw-r5-qc1" firstAttribute="centerY" secondItem="Cxx-YR-LH0" secondAttribute="centerY" id="zTO-MI-0nn"/>
             </constraints>
             <nil key="simulatedTopBarMetrics"/>
@@ -119,14 +110,11 @@
                 <outlet property="albumTagLeft" destination="5pk-CX-qTO" id="ucF-sm-pgl"/>
                 <outlet property="albumTagWidth" destination="Hqu-Jg-wlv" id="t2J-kH-tD9"/>
                 <outlet property="lineView" destination="28W-1K-xs7" id="4mk-r2-0Cz"/>
-                <outlet property="qualityLeft" destination="LNt-pH-K0U" id="aqL-h3-zpK"/>
                 <outlet property="qualityMusicTag" destination="nUD-13-vp7" id="gbb-4d-GRc"/>
                 <outlet property="qualityTagWidth" destination="1wc-7R-Rd1" id="LMy-l9-qZs"/>
                 <outlet property="songAuth" destination="jm2-P7-5K9" id="rS6-tU-qwV"/>
                 <outlet property="songNameLabel" destination="7xw-r5-qc1" id="fzV-Mi-66B"/>
                 <outlet property="tagView" destination="qrG-kH-VRz" id="za1-QD-1A2"/>
-                <outlet property="typeView" destination="N1D-TV-iWW" id="vWO-Qp-ugc"/>
-                <outlet property="typeViewWidth" destination="Fkh-p3-6cV" id="9xQ-hg-cUm"/>
                 <outlet property="uploadName" destination="yx5-8B-fUi" id="WSv-Gx-SCl"/>
             </connections>
             <point key="canvasLocation" x="101.44927536231884" y="62.946428571428569"/>
@@ -136,8 +124,5 @@
         <image name="home_music_play" width="24" height="24"/>
         <image name="music_albumTag" width="15" height="15"/>
         <image name="quality_tag" width="14" height="17"/>
-        <systemColor name="systemBackgroundColor">
-            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-        </systemColor>
     </resources>
 </document>

+ 0 - 2
KulexiuForStudent/KulexiuForStudent/Module/Live/View/SeatContentView.m

@@ -67,10 +67,8 @@
             make.right.mas_equalTo(bgView.mas_right).offset(-3);
         }];
         
-        
         self.nameLabel.font = [UIFont systemFontOfSize:9.0f weight:UIFontWeightMedium];
         self.nameLabel.text = [NSString returnNoNullStringWithString:[RCIMClient sharedRCIMClient].currentUserInfo.name];
-        
     }
     else { // 其他人
         [self.userAvatar setImage:[UIImage imageNamed:USERDEFAULT_LOGO]];

+ 1 - 0
KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfo.h

@@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic, strong) NSString *gender;
 @property (nonatomic, strong) NSString *idCardNo;
 @property (nonatomic, strong) NSString *birthdate;
+@property (nonatomic, strong) NSString *imUserId;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict;
 - (instancetype)initWithDictionary:(NSDictionary *)dict;

+ 7 - 0
KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfo.m

@@ -25,6 +25,7 @@ NSString *const kUserInfoEmail = @"email";
 NSString *const kUserInfoGender = @"gender";
 NSString *const kUserInfoIdCardNo = @"idCardNo";
 NSString *const kUserInfoBirthdate = @"birthdate";
+NSString *const kUserInfoImUserId = @"imUserId";
 
 
 @interface UserInfo ()
@@ -52,6 +53,7 @@ NSString *const kUserInfoBirthdate = @"birthdate";
 @synthesize gender = _gender;
 @synthesize idCardNo = _idCardNo;
 @synthesize birthdate = _birthdate;
+@synthesize imUserId = _imUserId;
 
 + (instancetype)modelObjectWithDictionary:(NSDictionary *)dict
 {
@@ -82,6 +84,7 @@ NSString *const kUserInfoBirthdate = @"birthdate";
             self.gender = [self objectOrNilForKey:kUserInfoGender fromDictionary:dict];
             self.idCardNo = [self objectOrNilForKey:kUserInfoIdCardNo fromDictionary:dict];
         self.birthdate = [self objectOrNilForKey:kUserInfoBirthdate fromDictionary:dict];
+        self.imUserId = [self objectOrNilForKey:kUserInfoImUserId fromDictionary:dict];
     }
     
     return self;
@@ -108,6 +111,7 @@ NSString *const kUserInfoBirthdate = @"birthdate";
     [mutableDict setValue:self.gender forKey:kUserInfoGender];
     [mutableDict setValue:self.idCardNo forKey:kUserInfoIdCardNo];
     [mutableDict setValue:self.birthdate forKey:kUserInfoBirthdate];
+    [mutableDict setValue:self.imUserId forKey:kUserInfoImUserId];
     return [NSDictionary dictionaryWithDictionary:mutableDict];
 }
 
@@ -151,6 +155,7 @@ NSString *const kUserInfoBirthdate = @"birthdate";
     self.gender = [aDecoder decodeObjectForKey:kUserInfoGender];
     self.idCardNo = [aDecoder decodeObjectForKey:kUserInfoIdCardNo];
     self.birthdate = [aDecoder decodeObjectForKey:kUserInfoBirthdate];
+    self.imUserId = [aDecoder decodeObjectForKey:kUserInfoImUserId];
     return self;
 }
 
@@ -174,6 +179,7 @@ NSString *const kUserInfoBirthdate = @"birthdate";
     [aCoder encodeObject:_gender forKey:kUserInfoGender];
     [aCoder encodeObject:_idCardNo forKey:kUserInfoIdCardNo];
     [aCoder encodeObject:_birthdate forKey:kUserInfoBirthdate];
+    [aCoder encodeObject:_imUserId forKey:kUserInfoImUserId];
 }
 
 - (id)copyWithZone:(NSZone *)zone
@@ -199,6 +205,7 @@ NSString *const kUserInfoBirthdate = @"birthdate";
         copy.gender = [self.gender copyWithZone:zone];
         copy.idCardNo = [self.idCardNo copyWithZone:zone];
         copy.birthdate = [self.birthdate copyWithZone:zone];
+        copy.imUserId = [self.imUserId copyWithZone:zone];
     }
     
     return copy;

+ 8 - 1
KulexiuForStudent/KulexiuForStudent/Module/Login/Model/UserInfoManager.m

@@ -131,6 +131,7 @@
 }
 
 - (void)queryUserInfoConnectRongCloud:(BOOL)connectRM {
+
     [KSNetworkingManager queryUserInfo:KS_GET success:^(NSDictionary * _Nonnull dic) {
         if ([dic integerValueForKey:@"code"] == 200 && [dic boolValueForKey:@"status"]) {
             // 保存用户信息
@@ -146,6 +147,9 @@
             NSString *uid = self.userInfo.userId;
             UserDefaultSet(uid, UIDKey);
             
+            // 融云ID
+            NSString *rongCloudId = self.userInfo.imUserId;
+            UserDefaultSet(rongCloudId, RongCloudID);
             
             NSString *rongToken = UserDefault(RongTokenKey);
             BOOL needConnect = NO;
@@ -159,7 +163,7 @@
             [[NSUserDefaults standardUserDefaults] synchronize];
             
             RCUserInfo *currentUserInfo =
-            [[RCUserInfo alloc] initWithUserId:UserDefault(UIDKey) name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
+            [[RCUserInfo alloc] initWithUserId:UserDefault(RongCloudID) name:UserDefault(NicknameKey) portrait:UserDefault(AvatarUrlKey)];
             [RCIM sharedRCIM].currentUserInfo = currentUserInfo;
             
             if (connectRM) {
@@ -349,6 +353,9 @@
             
             NSString *uid = self.userInfo.userId;
             UserDefaultSet(uid, UIDKey);
+            // 融云ID
+            NSString *rongCloudId = self.userInfo.imUserId;
+            UserDefaultSet(rongCloudId, RongCloudID);
             NSString *rongToken = UserDefault(RongTokenKey);
             BOOL needConnect = NO;
             if ([NSString isEmptyString:rongToken]) {

+ 5 - 12
KulexiuForStudent/KulexiuForStudent/Module/SealClass/Sections/Classroom/View/Chat/MessageManager/MessageHelper.m

@@ -49,24 +49,17 @@
             [self.delegate onSendMessage:message didCompleteWithError:error];
         }
     };
-    RoomMember *currentMember = [ClassroomService sharedService].currentRoom.currentMember;
-    if ([NSString isEmptyString:currentMember.headUrl]) {
-        content.senderUserInfo = [[RCUserInfo alloc] initWithUserId:currentMember.userId name:currentMember.name portrait:UserDefaultObjectForKey(AvatarUrlKey)];
+    RCUserInfo *userInfo = [RCIM sharedRCIM].currentUserInfo;
+    if ([NSString isEmptyString:userInfo.portraitUri]) {
+        content.senderUserInfo = [[RCUserInfo alloc] initWithUserId:userInfo.userId name:userInfo.name portrait:UserDefaultObjectForKey(AvatarUrlKey)];
     }
     else {
-        content.senderUserInfo = [[RCUserInfo alloc] initWithUserId:currentMember.userId name:currentMember.name portrait:currentMember.headUrl];
+        content.senderUserInfo = [[RCUserInfo alloc] initWithUserId:userInfo.userId name:userInfo.name portrait:userInfo.portraitUri];
     }
     
     message = [[RCIM sharedRCIM] sendMessage:conversationType targetId:targetId content:content pushContent:pushContent pushData:pushData success:success error:error];
     
-//    message = [IMClient
-//               sendMessage:conversationType
-//               targetId:targetId
-//               content:content
-//               pushContent:pushContent
-//               pushData:pushData
-//               success:success
-//               error:error];
+
     if (self.delegate && [self.delegate respondsToSelector:@selector(willSendMessage:)]) {
         [self.delegate willSendMessage:message];
     }