fancy 5 лет назад
Родитель
Сommit
897ec61f61
100 измененных файлов с 758 добавлено и 112 удалено
  1. 80 1
      o2ios/O2Platform.xcodeproj/project.pbxproj
  2. 130 0
      o2ios/O2Platform/App/IM-聊天/IMConversationListViewController.swift
  3. 39 0
      o2ios/O2Platform/App/IM-聊天/IMViewModel.swift
  4. 72 0
      o2ios/O2Platform/App/IM-聊天/Model/IMConversationInfo.swift
  5. 28 0
      o2ios/O2Platform/App/IM-聊天/O2IM.swift
  6. 98 0
      o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.swift
  7. 93 0
      o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.xib
  8. 82 68
      o2ios/O2Platform/App/O2MainController.swift
  9. 29 31
      o2ios/O2Platform/App/contacts/contacts.storyboard
  10. 17 8
      o2ios/O2Platform/Extension/Bundle+Extension.swift
  11. 16 4
      o2ios/O2Platform/Extension/Date+Extension.swift
  12. 2 0
      o2ios/O2Platform/Extension/Notification+Extension.swift
  13. 72 0
      o2ios/O2Platform/Framework/O2API/Communicate/CommunicateAPI.swift
  14. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/Info.plist
  15. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_01.png
  16. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_02.png
  17. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_03.png
  18. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_04.png
  19. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_05.png
  20. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_06.png
  21. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_07.png
  22. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_08.png
  23. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_09.png
  24. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_10.png
  25. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_11.png
  26. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_12.png
  27. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_13.png
  28. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_14.png
  29. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_15.png
  30. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_16.png
  31. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_17.png
  32. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_18.png
  33. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_19.png
  34. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_20.png
  35. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_21.png
  36. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_22.png
  37. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_23.png
  38. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_24.png
  39. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_25.png
  40. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_26.png
  41. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_27.png
  42. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_28.png
  43. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_29.png
  44. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_30.png
  45. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_31.png
  46. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_32.png
  47. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_33.png
  48. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_34.png
  49. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_35.png
  50. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_36.png
  51. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_37.png
  52. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_38.png
  53. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_39.png
  54. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_40.png
  55. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_41.png
  56. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_42.png
  57. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_43.png
  58. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_44.png
  59. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_45.png
  60. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_46.png
  61. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_47.png
  62. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_48.png
  63. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_49.png
  64. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_50.png
  65. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_51.png
  66. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_52.png
  67. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_53.png
  68. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_54.png
  69. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_55.png
  70. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_56.png
  71. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_57.png
  72. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_58.png
  73. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_59.png
  74. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_60.png
  75. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_61.png
  76. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_62.png
  77. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_63.png
  78. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_64.png
  79. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_65.png
  80. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_66.png
  81. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_67.png
  82. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_68.png
  83. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_69.png
  84. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_70.png
  85. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_71.png
  86. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_72.png
  87. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_73.png
  88. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_74.png
  89. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_75.png
  90. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_76.png
  91. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_77.png
  92. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_78.png
  93. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_79.png
  94. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_80.png
  95. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_81.png
  96. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_82.png
  97. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_83.png
  98. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_84.png
  99. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_85.png
  100. BIN
      o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_86.png

+ 80 - 1
o2ios/O2Platform.xcodeproj/project.pbxproj

@@ -56,6 +56,14 @@
 		B108F402229E34D400778050 /* LBXScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108F3FB229E34D300778050 /* LBXScanViewController.swift */; };
 		B108F402229E34D400778050 /* LBXScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108F3FB229E34D300778050 /* LBXScanViewController.swift */; };
 		B10A2F56233DDA990011CE3D /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B10A2F55233DDA990011CE3D /* AdSupport.framework */; };
 		B10A2F56233DDA990011CE3D /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B10A2F55233DDA990011CE3D /* AdSupport.framework */; };
 		B10A2F58233DDAE10011CE3D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B10A2F57233DDAE10011CE3D /* Security.framework */; };
 		B10A2F58233DDAE10011CE3D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B10A2F57233DDAE10011CE3D /* Security.framework */; };
+		B1173A5B2488C546005075F0 /* IMConversationListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1173A5A2488C546005075F0 /* IMConversationListViewController.swift */; };
+		B1173A5E2488C5DF005075F0 /* CommunicateAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1173A5D2488C5DF005075F0 /* CommunicateAPI.swift */; };
+		B1173A602488C82F005075F0 /* IMViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1173A5F2488C82F005075F0 /* IMViewModel.swift */; };
+		B1173A632488C8EA005075F0 /* IMConversationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1173A622488C8EA005075F0 /* IMConversationInfo.swift */; };
+		B1173A672488CD5B005075F0 /* IMConversationItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1173A652488CD5B005075F0 /* IMConversationItemCell.swift */; };
+		B1173A682488CD5B005075F0 /* IMConversationItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1173A662488CD5B005075F0 /* IMConversationItemCell.xib */; };
+		B1173A6A2488D4AD005075F0 /* O2IM.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1173A692488D4AD005075F0 /* O2IM.swift */; };
+		B1173B5E2489F48C005075F0 /* O2Emoji.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B1173B2C2489F48C005075F0 /* O2Emoji.bundle */; };
 		B1298E50236692AB006E9236 /* CloudFileListBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E4F236692AB006E9236 /* CloudFileListBaseController.swift */; };
 		B1298E50236692AB006E9236 /* CloudFileListBaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E4F236692AB006E9236 /* CloudFileListBaseController.swift */; };
 		B1298E7C23669BA2006E9236 /* CloudFileTypeListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E7B23669BA2006E9236 /* CloudFileTypeListController.swift */; };
 		B1298E7C23669BA2006E9236 /* CloudFileTypeListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E7B23669BA2006E9236 /* CloudFileTypeListController.swift */; };
 		B1298E7E2366AE4C006E9236 /* CloudFileImageCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E7D2366AE4C006E9236 /* CloudFileImageCollectionController.swift */; };
 		B1298E7E2366AE4C006E9236 /* CloudFileImageCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E7D2366AE4C006E9236 /* CloudFileImageCollectionController.swift */; };
@@ -1212,6 +1220,13 @@
 			remoteGlobalIDString = 183276F1FBCA05D9F840C64172C84A44;
 			remoteGlobalIDString = 183276F1FBCA05D9F840C64172C84A44;
 			remoteInfo = YHPopupView;
 			remoteInfo = YHPopupView;
 		};
 		};
+		B1173A582488C3DD005075F0 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 891B2270823847ED23F2ECFC28F935EC;
+			remoteInfo = Starscream;
+		};
 		B14A2292224CBC2E00745E0A /* PBXContainerItemProxy */ = {
 		B14A2292224CBC2E00745E0A /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			isa = PBXContainerItemProxy;
 			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
 			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
@@ -1359,6 +1374,14 @@
 		B108F3FB229E34D300778050 /* LBXScanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanViewController.swift; sourceTree = "<group>"; };
 		B108F3FB229E34D300778050 /* LBXScanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanViewController.swift; sourceTree = "<group>"; };
 		B10A2F55233DDA990011CE3D /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
 		B10A2F55233DDA990011CE3D /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
 		B10A2F57233DDAE10011CE3D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
 		B10A2F57233DDAE10011CE3D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
+		B1173A5A2488C546005075F0 /* IMConversationListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMConversationListViewController.swift; sourceTree = "<group>"; };
+		B1173A5D2488C5DF005075F0 /* CommunicateAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunicateAPI.swift; sourceTree = "<group>"; };
+		B1173A5F2488C82F005075F0 /* IMViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMViewModel.swift; sourceTree = "<group>"; };
+		B1173A622488C8EA005075F0 /* IMConversationInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMConversationInfo.swift; sourceTree = "<group>"; };
+		B1173A652488CD5B005075F0 /* IMConversationItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMConversationItemCell.swift; sourceTree = "<group>"; };
+		B1173A662488CD5B005075F0 /* IMConversationItemCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMConversationItemCell.xib; sourceTree = "<group>"; };
+		B1173A692488D4AD005075F0 /* O2IM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2IM.swift; sourceTree = "<group>"; };
+		B1173B2C2489F48C005075F0 /* O2Emoji.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = O2Emoji.bundle; sourceTree = "<group>"; };
 		B1298E4F236692AB006E9236 /* CloudFileListBaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileListBaseController.swift; sourceTree = "<group>"; };
 		B1298E4F236692AB006E9236 /* CloudFileListBaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileListBaseController.swift; sourceTree = "<group>"; };
 		B1298E7B23669BA2006E9236 /* CloudFileTypeListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileTypeListController.swift; sourceTree = "<group>"; };
 		B1298E7B23669BA2006E9236 /* CloudFileTypeListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileTypeListController.swift; sourceTree = "<group>"; };
 		B1298E7D2366AE4C006E9236 /* CloudFileImageCollectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileImageCollectionController.swift; sourceTree = "<group>"; };
 		B1298E7D2366AE4C006E9236 /* CloudFileImageCollectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileImageCollectionController.swift; sourceTree = "<group>"; };
@@ -1542,7 +1565,7 @@
 		B1FFF885223A23B200C170FD /* O2FlutterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2FlutterViewController.swift; sourceTree = "<group>"; };
 		B1FFF885223A23B200C170FD /* O2FlutterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2FlutterViewController.swift; sourceTree = "<group>"; };
 		B1FFF890223A4DA700C170FD /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
 		B1FFF890223A4DA700C170FD /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
 		B1FFF891223A4DA700C170FD /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
 		B1FFF891223A4DA700C170FD /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
-		C33461DCBCEEAF5B8597D54E /* Pods______.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods______.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		C33461DCBCEEAF5B8597D54E /* Pods______.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = "Pods______.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
 		E40502C220722208009A8D30 /* ImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerController.swift; sourceTree = "<group>"; };
 		E40502C220722208009A8D30 /* ImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerController.swift; sourceTree = "<group>"; };
 		E40502C320722208009A8D30 /* ImageRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageRow.swift; sourceTree = "<group>"; };
 		E40502C320722208009A8D30 /* ImageRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageRow.swift; sourceTree = "<group>"; };
 		E40502C420722208009A8D30 /* ImageCheckRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCheckRow.swift; sourceTree = "<group>"; };
 		E40502C420722208009A8D30 /* ImageCheckRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCheckRow.swift; sourceTree = "<group>"; };
@@ -2516,6 +2539,7 @@
 				B10AC5D721058DAE00179587 /* RxSwift.framework */,
 				B10AC5D721058DAE00179587 /* RxSwift.framework */,
 				B10AC5D921058DAE00179587 /* SDWebImage.framework */,
 				B10AC5D921058DAE00179587 /* SDWebImage.framework */,
 				B10AC5DF21058DAE00179587 /* SnapKit.framework */,
 				B10AC5DF21058DAE00179587 /* SnapKit.framework */,
+				B1173A592488C3DD005075F0 /* Starscream.framework */,
 				B10AC5E321058DAE00179587 /* SwiftValidator.framework */,
 				B10AC5E321058DAE00179587 /* SwiftValidator.framework */,
 				B10AC5E521058DAE00179587 /* SwiftyJSON.framework */,
 				B10AC5E521058DAE00179587 /* SwiftyJSON.framework */,
 				B10AC5E721058DAE00179587 /* SwiftyTimer.framework */,
 				B10AC5E721058DAE00179587 /* SwiftyTimer.framework */,
@@ -2526,6 +2550,43 @@
 			name = Products;
 			name = Products;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		B1173A262488C3DD005075F0 /* IM-聊天 */ = {
+			isa = PBXGroup;
+			children = (
+				B1173A642488CD37005075F0 /* View */,
+				B1173A612488C8D3005075F0 /* Model */,
+				B1173A5A2488C546005075F0 /* IMConversationListViewController.swift */,
+				B1173A5F2488C82F005075F0 /* IMViewModel.swift */,
+				B1173A692488D4AD005075F0 /* O2IM.swift */,
+			);
+			path = "IM-聊天";
+			sourceTree = "<group>";
+		};
+		B1173A5C2488C568005075F0 /* Communicate */ = {
+			isa = PBXGroup;
+			children = (
+				B1173A5D2488C5DF005075F0 /* CommunicateAPI.swift */,
+			);
+			path = Communicate;
+			sourceTree = "<group>";
+		};
+		B1173A612488C8D3005075F0 /* Model */ = {
+			isa = PBXGroup;
+			children = (
+				B1173A622488C8EA005075F0 /* IMConversationInfo.swift */,
+			);
+			path = Model;
+			sourceTree = "<group>";
+		};
+		B1173A642488CD37005075F0 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				B1173A652488CD5B005075F0 /* IMConversationItemCell.swift */,
+				B1173A662488CD5B005075F0 /* IMConversationItemCell.xib */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		B12FD1502283CDF400E636BA /* theme */ = {
 		B12FD1502283CDF400E636BA /* theme */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -2787,6 +2848,7 @@
 		B1F79C44233B5F9B004D0AEE /* Resources */ = {
 		B1F79C44233B5F9B004D0AEE /* Resources */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				B1173B2C2489F48C005075F0 /* O2Emoji.bundle */,
 				B19776E7217D9D810019F3A8 /* beep.wav */,
 				B19776E7217D9D810019F3A8 /* beep.wav */,
 				E4B888231D9D48F1002E1A46 /* images */,
 				E4B888231D9D48F1002E1A46 /* images */,
 				E4B888291D9D48F1002E1A46 /* 隶变体.ttf */,
 				E4B888291D9D48F1002E1A46 /* 隶变体.ttf */,
@@ -2872,6 +2934,7 @@
 				E45CD4211DFE503C008F99AD /* Scan-二维码扫码 */,
 				E45CD4211DFE503C008F99AD /* Scan-二维码扫码 */,
 				E4C24C22208D7EDE00E426B0 /* Contact-通讯录 */,
 				E4C24C22208D7EDE00E426B0 /* Contact-通讯录 */,
 				E4B8875E1D9D48F1002E1A46 /* contacts */,
 				E4B8875E1D9D48F1002E1A46 /* contacts */,
+				B1173A262488C3DD005075F0 /* IM-聊天 */,
 				E428AF3720A95D3800D964B9 /* NewAttance-考勤打卡 */,
 				E428AF3720A95D3800D964B9 /* NewAttance-考勤打卡 */,
 				E40E246E20B7DA3C009F8BE7 /* meeting-会议 */,
 				E40E246E20B7DA3C009F8BE7 /* meeting-会议 */,
 				B19091FD2107145F009A7906 /* Calendar-日程管理 */,
 				B19091FD2107145F009A7906 /* Calendar-日程管理 */,
@@ -3408,6 +3471,7 @@
 		E4B69721207602840062F6E8 /* O2API */ = {
 		E4B69721207602840062F6E8 /* O2API */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				B1173A5C2488C568005075F0 /* Communicate */,
 				B18FFF3323756B24001B2887 /* JpushAPI */,
 				B18FFF3323756B24001B2887 /* JpushAPI */,
 				B107453721A52B9A0015F1B2 /* PersonalAPI */,
 				B107453721A52B9A0015F1B2 /* PersonalAPI */,
 				B1B6A8F7217710A400C10F3C /* FaceRecognizeAPI */,
 				B1B6A8F7217710A400C10F3C /* FaceRecognizeAPI */,
@@ -5297,6 +5361,13 @@
 			remoteRef = B10AC5F021058DAE00179587 /* PBXContainerItemProxy */;
 			remoteRef = B10AC5F021058DAE00179587 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
 		};
+		B1173A592488C3DD005075F0 /* Starscream.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = Starscream.framework;
+			remoteRef = B1173A582488C3DD005075F0 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
 		B14A2293224CBC2E00745E0A /* IQKeyboardManagerSwift.framework */ = {
 		B14A2293224CBC2E00745E0A /* IQKeyboardManagerSwift.framework */ = {
 			isa = PBXReferenceProxy;
 			isa = PBXReferenceProxy;
 			fileType = wrapper.framework;
 			fileType = wrapper.framework;
@@ -5401,6 +5472,7 @@
 				E4B8871E1D9D477A002E1A46 /* Assets.xcassets in Resources */,
 				E4B8871E1D9D477A002E1A46 /* Assets.xcassets in Resources */,
 				E46E6CA51DD41F5D00AB7561 /* ZSSsuperscript.png in Resources */,
 				E46E6CA51DD41F5D00AB7561 /* ZSSsuperscript.png in Resources */,
 				E4C24BC020844F3C00E426B0 /* 定位2.png in Resources */,
 				E4C24BC020844F3C00E426B0 /* 定位2.png in Resources */,
+				B1173A682488CD5B005075F0 /* IMConversationItemCell.xib in Resources */,
 				B197771D217D9D810019F3A8 /* beep.wav in Resources */,
 				B197771D217D9D810019F3A8 /* beep.wav in Resources */,
 				E40E24C920B7DA3C009F8BE7 /* OOMeetingPersonTableViewCell.xib in Resources */,
 				E40E24C920B7DA3C009F8BE7 /* OOMeetingPersonTableViewCell.xib in Resources */,
 				E4B2321C20B3E94E0082F30A /* OOAttanceCheckinPromptView.xib in Resources */,
 				E4B2321C20B3E94E0082F30A /* OOAttanceCheckinPromptView.xib in Resources */,
@@ -5507,6 +5579,7 @@
 				E46E6CAF1DD41F5D00AB7561 /* ZSSunlink.png in Resources */,
 				E46E6CAF1DD41F5D00AB7561 /* ZSSunlink.png in Resources */,
 				E40E24C320B7DA3C009F8BE7 /* OOMeetingInforItemCell.xib in Resources */,
 				E40E24C320B7DA3C009F8BE7 /* OOMeetingInforItemCell.xib in Resources */,
 				E46E6C811DD41F5D00AB7561 /* ZSShorizontalrule.png in Resources */,
 				E46E6C811DD41F5D00AB7561 /* ZSShorizontalrule.png in Resources */,
+				B1173B5E2489F48C005075F0 /* O2Emoji.bundle in Resources */,
 				E46E6C7F1DD41F5D00AB7561 /* ZSSh6.png in Resources */,
 				E46E6C7F1DD41F5D00AB7561 /* ZSSh6.png in Resources */,
 				E46E6C9C1DD41F5D00AB7561 /* ZSSquicklink@2x.png in Resources */,
 				E46E6C9C1DD41F5D00AB7561 /* ZSSquicklink@2x.png in Resources */,
 				E46E6C901DD41F5D00AB7561 /* ZSSleftjustify@2x.png in Resources */,
 				E46E6C901DD41F5D00AB7561 /* ZSSleftjustify@2x.png in Resources */,
@@ -5854,6 +5927,7 @@
 				E4B888711D9D48F1002E1A46 /* ContactSearchViewController.swift in Sources */,
 				E4B888711D9D48F1002E1A46 /* ContactSearchViewController.swift in Sources */,
 				B130A7852281597000282AD1 /* DeviceManagerViewModel.swift in Sources */,
 				B130A7852281597000282AD1 /* DeviceManagerViewModel.swift in Sources */,
 				E40E24BF20B7DA3C009F8BE7 /* OOMeetingRoomDeviceListView.swift in Sources */,
 				E40E24BF20B7DA3C009F8BE7 /* OOMeetingRoomDeviceListView.swift in Sources */,
+				B1173A632488C8EA005075F0 /* IMConversationInfo.swift in Sources */,
 				E4A748D51EC15EF100163F58 /* TaskAttachmentPreviewController.swift in Sources */,
 				E4A748D51EC15EF100163F58 /* TaskAttachmentPreviewController.swift in Sources */,
 				E4B888A51D9D48F1002E1A46 /* MJRefreshBackStateFooter.m in Sources */,
 				E4B888A51D9D48F1002E1A46 /* MJRefreshBackStateFooter.m in Sources */,
 				E4B8885E1D9D48F1002E1A46 /* O2CollectionView.swift in Sources */,
 				E4B8885E1D9D48F1002E1A46 /* O2CollectionView.swift in Sources */,
@@ -5863,9 +5937,11 @@
 				E4D2310F209C40F600837868 /* OOPersonCollectionViewCell.swift in Sources */,
 				E4D2310F209C40F600837868 /* OOPersonCollectionViewCell.swift in Sources */,
 				E4C24B4A20844F3C00E426B0 /* JCMessageImageCollectionViewCell.swift in Sources */,
 				E4C24B4A20844F3C00E426B0 /* JCMessageImageCollectionViewCell.swift in Sources */,
 				E4C24B6920844F3C00E426B0 /* DLSlideView.m in Sources */,
 				E4C24B6920844F3C00E426B0 /* DLSlideView.m in Sources */,
+				B1173A672488CD5B005075F0 /* IMConversationItemCell.swift in Sources */,
 				B1534E3F21F712EA00CC8C35 /* O2DemoAlertView.swift in Sources */,
 				B1534E3F21F712EA00CC8C35 /* O2DemoAlertView.swift in Sources */,
 				E4C24B7F20844F3C00E426B0 /* ImageFileCell.swift in Sources */,
 				E4C24B7F20844F3C00E426B0 /* ImageFileCell.swift in Sources */,
 				B165CD602242093500373B66 /* AlertViewController.swift in Sources */,
 				B165CD602242093500373B66 /* AlertViewController.swift in Sources */,
+				B1173A5E2488C5DF005075F0 /* CommunicateAPI.swift in Sources */,
 				E441994A206C8A100050AE0C /* OORegisterTableView.swift in Sources */,
 				E441994A206C8A100050AE0C /* OORegisterTableView.swift in Sources */,
 				E40E24A920B7DA3C009F8BE7 /* OOMeetingCreateViewModel.swift in Sources */,
 				E40E24A920B7DA3C009F8BE7 /* OOMeetingCreateViewModel.swift in Sources */,
 				E40C41ED1E7F7C0D00568805 /* ZoneSubCategoryViewController.swift in Sources */,
 				E40C41ED1E7F7C0D00568805 /* ZoneSubCategoryViewController.swift in Sources */,
@@ -5901,6 +5977,7 @@
 				B1DE856623603408003C36E2 /* DispatchQueue+Extension.swift in Sources */,
 				B1DE856623603408003C36E2 /* DispatchQueue+Extension.swift in Sources */,
 				E4B69772207630240062F6E8 /* String+Extenstion.swift in Sources */,
 				E4B69772207630240062F6E8 /* String+Extenstion.swift in Sources */,
 				B175007A233C6908003DA7B9 /* BlockLongPress.swift in Sources */,
 				B175007A233C6908003DA7B9 /* BlockLongPress.swift in Sources */,
+				B1173A5B2488C546005075F0 /* IMConversationListViewController.swift in Sources */,
 				E4B69734207602A40062F6E8 /* OOAPIContext.swift in Sources */,
 				E4B69734207602A40062F6E8 /* OOAPIContext.swift in Sources */,
 				09E02E881F16319600579887 /* DiskFetcher.swift in Sources */,
 				09E02E881F16319600579887 /* DiskFetcher.swift in Sources */,
 				E4C24B5520844F3C00E426B0 /* SAIToolboxInputView.swift in Sources */,
 				E4C24B5520844F3C00E426B0 /* SAIToolboxInputView.swift in Sources */,
@@ -6009,6 +6086,7 @@
 				B1EE2CCE2281729400842F48 /* QDatePicker.swift in Sources */,
 				B1EE2CCE2281729400842F48 /* QDatePicker.swift in Sources */,
 				E4B6975C20762EA00062F6E8 /* OOUIDownButtonTextField.swift in Sources */,
 				E4B6975C20762EA00062F6E8 /* OOUIDownButtonTextField.swift in Sources */,
 				E4C24C0720844F4400E426B0 /* JCSearchFriendViewController.swift in Sources */,
 				E4C24C0720844F4400E426B0 /* JCSearchFriendViewController.swift in Sources */,
+				B1173A602488C82F005075F0 /* IMViewModel.swift in Sources */,
 				E46E6CBB1DD41F5D00AB7561 /* HRBrightnessCursor.m in Sources */,
 				E46E6CBB1DD41F5D00AB7561 /* HRBrightnessCursor.m in Sources */,
 				E4B697E920764A2D0062F6E8 /* OOWorkAPI.swift in Sources */,
 				E4B697E920764A2D0062F6E8 /* OOWorkAPI.swift in Sources */,
 				E40E24C720B7DA3C009F8BE7 /* OOFormSegueItemView.swift in Sources */,
 				E40E24C720B7DA3C009F8BE7 /* OOFormSegueItemView.swift in Sources */,
@@ -6423,6 +6501,7 @@
 				E4C24B8C20844F3C00E426B0 /* JCMessageNoticeContentView.swift in Sources */,
 				E4C24B8C20844F3C00E426B0 /* JCMessageNoticeContentView.swift in Sources */,
 				E4C24C3E208D7EDE00E426B0 /* OOContactViewModel.swift in Sources */,
 				E4C24C3E208D7EDE00E426B0 /* OOContactViewModel.swift in Sources */,
 				E4D2312E20A29E7500837868 /* OOAppMainCollectionHeaderView.swift in Sources */,
 				E4D2312E20A29E7500837868 /* OOAppMainCollectionHeaderView.swift in Sources */,
+				B1173A6A2488D4AD005075F0 /* O2IM.swift in Sources */,
 				E4C24B5220844F3C00E426B0 /* SAIToolboxItemView.swift in Sources */,
 				E4C24B5220844F3C00E426B0 /* SAIToolboxItemView.swift in Sources */,
 				E4C24B3C20844F3C00E426B0 /* Date+JChat.swift in Sources */,
 				E4C24B3C20844F3C00E426B0 /* Date+JChat.swift in Sources */,
 				E4C24C0120844F4400E426B0 /* JCUserInfoCell.swift in Sources */,
 				E4C24C0120844F4400E426B0 /* JCUserInfoCell.swift in Sources */,

+ 130 - 0
o2ios/O2Platform/App/IM-聊天/IMConversationListViewController.swift

@@ -0,0 +1,130 @@
+//
+//  IMConversationListViewController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+
+class IMConversationListViewController: UIViewController {
+
+    fileprivate lazy var tableview: UITableView = {
+        var tableview = UITableView(frame: CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height))
+        tableview.delegate = self
+        tableview.dataSource = self
+        tableview.backgroundColor = UIColor(netHex: 0xe8edf3)
+        tableview.register(UINib(nibName: "IMConversationItemCell", bundle: nil), forCellReuseIdentifier: "IMConversationItemCell")
+        tableview.separatorStyle = .none
+        return tableview
+    }()
+
+    fileprivate lazy var emptyView: UIView = {
+        let view = UIView(frame: CGRect(x: 0, y: 36, width: self.view.width, height: self.view.height - 36))
+        view.isHidden = true
+        view.backgroundColor = .white
+        let tips = UILabel()
+        tips.text = "暂无会话"
+        tips.textColor = UIColor(netHex: 0x666666)
+        tips.sizeToFit()
+        tips.center = CGPoint(x: view.centerX, y: view.height / 2 - 60)
+        view.addSubview(tips)
+        return view
+    }()
+
+    private lazy var viewModel: IMViewModel = {
+        return IMViewModel()
+    }()
+
+    private var conversationList: [IMConversationInfo] = []
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        view.addSubview(tableview)
+        view.addSubview(emptyView)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(receiveMessageFromWs(notice:)), name: OONotification.websocket.notificationName, object: nil)
+        
+         
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        getConversationList()
+    }
+
+    func getConversationList() {
+        viewModel.myConversationList().then { (list) in
+            self.conversationList = list
+            DispatchQueue.main.async {
+                if self.conversationList.count > 0 {
+                    self.emptyView.isHidden = true
+                } else {
+                    self.emptyView.isHidden = false
+                }
+                self.tableview.reloadData()
+            }
+
+        }.catch { (err) in
+            DispatchQueue.main.async { self.emptyView.isHidden = false }
+        }
+    }
+
+    //接收websocket消息
+    @objc private func receiveMessageFromWs(notice: Notification) {
+        DDLogDebug("接收到websocket im 消息")
+        if let message = notice.object as? IMMessageInfo {
+            if self.conversationList.contains(where: { (info) -> Bool in
+                return info.id == message.conversationId
+            }) {
+                DDLogDebug("有对应的会话 刷新列表")
+                var newList: [IMConversationInfo]  = []
+                self.conversationList.forEach { (info) in
+                    if message.conversationId != nil && info.id == message.conversationId {
+                        info.lastMessage = message
+                        info.unreadNumber = (info.unreadNumber ?? 0) + 1
+                    }
+                    newList.append(info)
+                }
+                self.conversationList = newList
+                DispatchQueue.main.async {
+                    self.tableview.reloadData()
+                }
+            }else {
+                DDLogDebug("没有对应的会话 重新获取会话列表")
+                self.getConversationList()
+            }
+        }else {
+            DDLogError("不正确的消息类型。。。")
+        }
+    }
+    
+    
+
+}
+
+// MARK: - tableview delegate
+extension IMConversationListViewController: UITableViewDelegate, UITableViewDataSource {
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        return self.conversationList.count
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        return tableView.dequeueReusableCell(withIdentifier: "IMConversationItemCell", for: indexPath)
+    }
+    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
+        guard let c = cell as? IMConversationItemCell else {
+            return
+        }
+        c.bindConversation(conversation: self.conversationList[indexPath.row])
+    }
+    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        return 64
+    }
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        DDLogDebug("点击了 row \(indexPath.row)")
+    }
+    //todo can edit
+
+}

+ 39 - 0
o2ios/O2Platform/App/IM-聊天/IMViewModel.swift

@@ -0,0 +1,39 @@
+//
+//  IMViewModel.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Promises
+
+
+class IMViewModel: NSObject {
+    override init() {
+        super.init()
+    }
+    
+    
+    let communicateAPI = OOMoyaProvider<CommunicateAPI>()
+}
+
+extension IMViewModel {
+    
+    func myConversationList() -> Promise<[IMConversationInfo]> {
+        return Promise { fulfill, reject in
+            self.communicateAPI.request(.myConversationList, completion: { result in
+                let response = OOResult<BaseModelClass<[IMConversationInfo]>>(result)
+                if response.isResultSuccess() {
+                    if let list = response.model?.data {
+                        fulfill(list)
+                    }else {
+                        reject(OOAppError.apiEmptyResultError)
+                    }
+                }else {
+                    reject(response.error!)
+                }
+            })
+        }
+    }
+}

+ 72 - 0
o2ios/O2Platform/App/IM-聊天/Model/IMConversationInfo.swift

@@ -0,0 +1,72 @@
+//
+//  IMConversation.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+import HandyJSON
+
+
+class IMConversationInfo: NSObject, DataModel {
+    @objc var id: String?
+    @objc var title: String?
+    @objc var type: String? //会话类型 单人 、 群.
+    @objc var personList: [String]?
+    @objc var adminPerson: String?
+    @objc var note: String?
+    
+    @objc var lastMessageTime: String?
+    @objc var createTime: String?
+    @objc var updateTime: String?
+    var unreadNumber: Int?
+    var isTop: Bool?
+    
+    @objc var lastMessage: IMMessageInfo?
+    
+    required override init(){}
+    
+    func mapping(mapper: HelpingMapper) {
+        
+    }
+}
+
+
+class IMMessageInfo: NSObject, DataModel {
+    @objc var id: String?
+    @objc var conversationId: String?
+    @objc var body: String?
+    @objc var createPerson: String?
+    @objc var createTime: String?
+    @objc var updateTime: String?
+    
+     required override init(){}
+       
+       func mapping(mapper: HelpingMapper) {
+           
+       }
+}
+
+class IMMessageBodyInfo: NSObject, DataModel {
+    @objc var id: String?
+   @objc var type: String?
+   @objc var body: String?
+    
+    
+    required override init(){}
+    
+    func mapping(mapper: HelpingMapper) {
+        
+    }
+}
+
+//websocket 消息对象
+class WsMessage: NSObject, DataModel {
+    @objc var type: String? //im_create
+    @objc var body: IMMessageInfo? //这个对象只有 type=im_create的时候才是这个对象
+    required override init(){}
+    
+    func mapping(mapper: HelpingMapper) {
+        
+    }
+}

+ 28 - 0
o2ios/O2Platform/App/IM-聊天/O2IM.swift

@@ -0,0 +1,28 @@
+//
+//  O2IM.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Foundation
+
+//心跳消息
+let o2_im_ws_heartbeat = "heartbeat"
+
+
+let o2_im_conversation_type_single = "single"
+
+let o2_im_msg_type_text = "text"
+let o2_im_msg_type_emoji = "emoji"
+
+
+//表情的字符串转化为O2Emoji.bundle里面的图片路径 [01] -> im_emotion_01
+func o2ImEmojiPath(emojiBody: String) -> String {
+    if emojiBody.length == 4 {
+        let s = emojiBody.subString(from: 1, to: 3)
+        return "im_emotion_\(s)"
+    }
+    return ""
+}

+ 98 - 0
o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.swift

@@ -0,0 +1,98 @@
+//
+//  IMConversationItemCell.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import O2OA_Auth_SDK
+import CocoaLumberjack
+
+class IMConversationItemCell: UITableViewCell {
+
+    @IBOutlet weak var avatarImg: UIImageView!
+    @IBOutlet weak var nameLabel: UILabel!
+    @IBOutlet weak var timeLabel: UILabel!
+    @IBOutlet weak var messageLabel: UILabel!
+    
+    @IBOutlet weak var emojiImg: UIImageView!
+    
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        // Initialization code
+    }
+
+    override func setSelected(_ selected: Bool, animated: Bool) {
+        super.setSelected(selected, animated: animated)
+
+        // Configure the view for the selected state
+    }
+    
+    func bindConversation(conversation: IMConversationInfo) {
+        //avatar name
+        if conversation.type == o2_im_conversation_type_single {
+            var person = ""
+            conversation.personList?.forEach({ (p) in
+                if  p != O2AuthSDK.shared.myInfo()?.distinguishedName {
+                    person = p
+                }
+            })
+            if person != "" {
+                //头像
+                let urlstr = AppDelegate.o2Collect.generateURLWithAppContextKey(ContactContext.contactsContextKeyV2, query: ContactContext.personIconByNameQueryV2, parameter: ["##name##":person as AnyObject], generateTime: false)
+                DDLogDebug("头像url \(String(describing: urlstr))")
+                if let u = URL(string: urlstr!) {
+                    self.avatarImg.hnk_setImageFromURL(u)
+                }else {
+                    DDLogError("错误, 没有生成头像url")
+                    self.avatarImg.image = UIImage(named: "icon_men")
+                }
+                //姓名
+                self.nameLabel.text = person.split("@").first ?? ""
+            }else {
+                self.avatarImg.image = UIImage(named: "icon_men")
+                self.nameLabel.text = ""
+            }
+        }else {//todo 群组头像 ?
+            self.nameLabel.text = conversation.title
+        }
+        //time
+        if let time = conversation.lastMessage?.createTime {
+            DDLogDebug("time: \(time)")
+            let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            DDLogDebug("date \(date.description)")
+            self.timeLabel.text = date.friendlyTime()
+        }
+        // message
+        if let msgBody = conversation.lastMessage?.body, let body = parseJson(msg: msgBody) {
+            if body.type == o2_im_msg_type_text {
+                self.messageLabel.text = body.body
+                self.messageLabel.isHidden = false
+                self.emojiImg.isHidden = true
+            }else if body.type == o2_im_msg_type_emoji {
+                self.messageLabel.isHidden = true
+                self.emojiImg.isHidden = false
+//                self.emojiImg.image = UIImage(named: "setting_myCRM")
+                //todo emoji表情导入
+                let bundle = Bundle().o2EmojiBundle(anyClass: IMConversationItemCell.self)
+                let path = o2ImEmojiPath(emojiBody: body.body!)
+                DDLogDebug("path: \(path)")
+                self.emojiImg.image = UIImage(named: path, in: bundle, compatibleWith: nil)
+            }else {
+                self.messageLabel.isHidden = true
+                self.emojiImg.isHidden = true
+            }
+        }
+        
+    }
+    
+    private func parseJson(msg: String) -> IMMessageBodyInfo? {
+        return IMMessageBodyInfo.deserialize(from: msg)
+    }
+    
+    
+    
+}

+ 93 - 0
o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.xib

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" 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="16087"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="64" id="KGk-i7-Jjw" customClass="IMConversationItemCell" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="64"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="64"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="i51-Sc-dds">
+                        <rect key="frame" x="10" y="10" width="44" height="44"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="44" id="0Cn-m9-oMp"/>
+                            <constraint firstAttribute="height" constant="44" id="Eds-PW-EC8"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="22"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </imageView>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="姓名" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bOp-mm-qCN">
+                        <rect key="frame" x="66" y="10" width="154" height="21"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                        <nil key="textColor"/>
+                        <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="URQ-HD-MDc">
+                        <rect key="frame" x="257" y="10" width="58" height="17"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <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="I3j-lM-VtV" customClass="IMCon">
+                        <rect key="frame" x="70" y="37" width="71.5" height="17"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" systemColor="systemGrayColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="pgV-nP-wwV">
+                        <rect key="frame" x="70" y="34" width="22" height="22"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="22" id="GMk-WU-WAB"/>
+                            <constraint firstAttribute="height" constant="22" id="wqz-nd-Maf"/>
+                        </constraints>
+                    </imageView>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ckc-YE-j5q">
+                        <rect key="frame" x="66" y="63" width="254" height="1"/>
+                        <color key="backgroundColor" systemColor="opaqueSeparatorColor" red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="1" id="szG-5G-RRm"/>
+                        </constraints>
+                    </view>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="bottom" secondItem="I3j-lM-VtV" secondAttribute="bottom" constant="10" id="0mD-L5-TRo"/>
+                    <constraint firstAttribute="trailing" secondItem="ckc-YE-j5q" secondAttribute="trailing" id="2LG-5s-Yui"/>
+                    <constraint firstItem="pgV-nP-wwV" firstAttribute="leading" secondItem="i51-Sc-dds" secondAttribute="trailing" constant="16" id="4Ao-s1-kAM"/>
+                    <constraint firstItem="I3j-lM-VtV" firstAttribute="leading" secondItem="i51-Sc-dds" secondAttribute="trailing" constant="16" id="BFD-a2-hUs"/>
+                    <constraint firstItem="URQ-HD-MDc" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="IES-nF-jpE"/>
+                    <constraint firstAttribute="trailing" secondItem="URQ-HD-MDc" secondAttribute="trailing" constant="5" id="Jeh-u4-Tnd"/>
+                    <constraint firstItem="bOp-mm-qCN" firstAttribute="leading" secondItem="i51-Sc-dds" secondAttribute="trailing" constant="12" id="RCn-dh-ggD"/>
+                    <constraint firstItem="i51-Sc-dds" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="Z9Q-tH-mWi"/>
+                    <constraint firstAttribute="bottom" secondItem="i51-Sc-dds" secondAttribute="bottom" constant="10" id="Zew-6c-hWd"/>
+                    <constraint firstItem="bOp-mm-qCN" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="iUq-ik-5sX"/>
+                    <constraint firstAttribute="bottom" secondItem="ckc-YE-j5q" secondAttribute="bottom" id="nX2-Nw-uiy"/>
+                    <constraint firstItem="ckc-YE-j5q" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="66" id="t0M-PG-f03"/>
+                    <constraint firstAttribute="bottom" secondItem="pgV-nP-wwV" secondAttribute="bottom" constant="8" id="tXP-Lu-4aH"/>
+                    <constraint firstItem="i51-Sc-dds" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="10" id="xep-37-rIl"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
+            <connections>
+                <outlet property="avatarImg" destination="i51-Sc-dds" id="k5V-7P-msX"/>
+                <outlet property="emojiImg" destination="pgV-nP-wwV" id="RRM-lj-KXN"/>
+                <outlet property="messageLabel" destination="I3j-lM-VtV" id="6z4-xX-xTv"/>
+                <outlet property="nameLabel" destination="bOp-mm-qCN" id="iqM-q2-qcC"/>
+                <outlet property="timeLabel" destination="URQ-HD-MDc" id="NbV-D2-ATA"/>
+            </connections>
+            <point key="canvasLocation" x="-65.217391304347828" y="-31.473214285714285"/>
+        </tableViewCell>
+    </objects>
+</document>

+ 82 - 68
o2ios/O2Platform/App/O2MainController.swift

@@ -12,9 +12,9 @@ import O2OA_Auth_SDK
 import Starscream
 import Starscream
 
 
 class O2MainController: UITabBarController, UITabBarControllerDelegate {
 class O2MainController: UITabBarController, UITabBarControllerDelegate {
-    
-    static var tabBarVC:O2MainController!
-    
+
+    static var tabBarVC: O2MainController!
+
     static func genernateVC() -> O2MainController {
     static func genernateVC() -> O2MainController {
 //        guard let vc = tabBarVC else {
 //        guard let vc = tabBarVC else {
 //            tabBarVC = O2MainController()
 //            tabBarVC = O2MainController()
@@ -23,21 +23,21 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
 //        return vc
 //        return vc
         return O2MainController()
         return O2MainController()
     }
     }
-    
-    private var currentIndex:Int = 0
+
+    private var currentIndex: Int = 0
     // demo服务器弹出公告
     // demo服务器弹出公告
     private var demoAlertView = O2DemoAlertView()
     private var demoAlertView = O2DemoAlertView()
-    private let viewModel:OOLoginViewModel = {
+    private let viewModel: OOLoginViewModel = {
         return OOLoginViewModel()
         return OOLoginViewModel()
     }()
     }()
-    
-    
+
+
     override func viewDidLoad() {
     override func viewDidLoad() {
         super.viewDidLoad()
         super.viewDidLoad()
         if UIDevice.deviceModelReadable() != "Simulator" {
         if UIDevice.deviceModelReadable() != "Simulator" {
             self.checkAppVersion()
             self.checkAppVersion()
         }
         }
-        
+
         self.delegate = self
         self.delegate = self
         _initControllers()
         _initControllers()
         selectedIndex = 2
         selectedIndex = 2
@@ -50,12 +50,12 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
         //连接websocket
         //连接websocket
         self._startWebsocket()
         self._startWebsocket()
     }
     }
-    
+
     deinit {
     deinit {
         //关闭websocket
         //关闭websocket
         self._stopWebsocket()
         self._stopWebsocket()
     }
     }
-    
+
     override func viewDidAppear(_ animated: Bool) {
     override func viewDidAppear(_ animated: Bool) {
         // 判断是否 第一次安装 是否是连接的demo服务器
         // 判断是否 第一次安装 是否是连接的demo服务器
         if let unit = O2AuthSDK.shared.bindUnit() {
         if let unit = O2AuthSDK.shared.bindUnit() {
@@ -68,7 +68,7 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
             }
             }
         }
         }
     }
     }
-    
+
     //MARK: -- delegate
     //MARK: -- delegate
     func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
     func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
 //        if currentIndex == 2 && tabBarController.selectedIndex == 2 {
 //        if currentIndex == 2 && tabBarController.selectedIndex == 2 {
@@ -86,20 +86,21 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
 //        }
 //        }
         self.currentIndex = tabBarController.selectedIndex
         self.currentIndex = tabBarController.selectedIndex
     }
     }
-    
+
     private func _initControllers() {
     private func _initControllers() {
         //消息
         //消息
-        let conversationVC = JCConversationListViewController()
-        conversationVC.title  = "消息"
+//        let conversationVC = JCConversationListViewController()
+        let conversationVC = IMConversationListViewController()
+        conversationVC.title = "消息"
         let messages = ZLNavigationController(rootViewController: conversationVC)
         let messages = ZLNavigationController(rootViewController: conversationVC)
-        
-        messages.tabBarItem = UITabBarItem(title: "消息", image:UIImage(named: "icon_news_nor"), selectedImage: O2ThemeManager.image(for: "Icon.icon_news_pre"))
-        
+
+        messages.tabBarItem = UITabBarItem(title: "消息", image: UIImage(named: "icon_news_nor"), selectedImage: O2ThemeManager.image(for: "Icon.icon_news_pre"))
+
         //通讯录
         //通讯录
         let addressVC = OOTabBarHelper.getVC(storyboardName: "contacts", vcName: nil)
         let addressVC = OOTabBarHelper.getVC(storyboardName: "contacts", vcName: nil)
         let address = ZLNavigationController(rootViewController: addressVC)
         let address = ZLNavigationController(rootViewController: addressVC)
-        address.tabBarItem = UITabBarItem(title: "通讯录", image:UIImage(named: "icon_address_g"), selectedImage: O2ThemeManager.image(for: "Icon.icon_address_list_pro"))
-        
+        address.tabBarItem = UITabBarItem(title: "通讯录", image: UIImage(named: "icon_address_g"), selectedImage: O2ThemeManager.image(for: "Icon.icon_address_list_pro"))
+
         // main
         // main
         let mainVC = mainController()
         let mainVC = mainController()
         mainVC.tabBarItem = UITabBarItem(title: nil, image: UIImage(named: "icon_zhuye_nor"), selectedImage: O2ThemeManager.image(for: "Icon.icon_zhuye_pre"))
         mainVC.tabBarItem = UITabBarItem(title: nil, image: UIImage(named: "icon_zhuye_nor"), selectedImage: O2ThemeManager.image(for: "Icon.icon_zhuye_pre"))
@@ -114,17 +115,17 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
         //应用
         //应用
         let appsVC = OOTabBarHelper.getVC(storyboardName: "apps", vcName: nil)
         let appsVC = OOTabBarHelper.getVC(storyboardName: "apps", vcName: nil)
         let apps = ZLNavigationController(rootViewController: appsVC)
         let apps = ZLNavigationController(rootViewController: appsVC)
-        apps.tabBarItem = UITabBarItem(title: "应用", image:UIImage(named: "icon_yingyong"), selectedImage: O2ThemeManager.image(for: "Icon.icon_yingyong_pro"))
-        
+        apps.tabBarItem = UITabBarItem(title: "应用", image: UIImage(named: "icon_yingyong"), selectedImage: O2ThemeManager.image(for: "Icon.icon_yingyong_pro"))
+
         //设置
         //设置
         let settingsVC = OOTabBarHelper.getVC(storyboardName: "setting", vcName: nil)
         let settingsVC = OOTabBarHelper.getVC(storyboardName: "setting", vcName: nil)
-        let settings =   ZLNavigationController(rootViewController: settingsVC)
-        settings.tabBarItem = UITabBarItem(title: "设置", image:UIImage(named: "setting_normal"), selectedImage: O2ThemeManager.image(for: "Icon.setting_selected"))
-        
+        let settings = ZLNavigationController(rootViewController: settingsVC)
+        settings.tabBarItem = UITabBarItem(title: "设置", image: UIImage(named: "setting_normal"), selectedImage: O2ThemeManager.image(for: "Icon.setting_selected"))
+
         self.viewControllers = [messages, address, mainVC, apps, settings]
         self.viewControllers = [messages, address, mainVC, apps, settings]
-        
+
     }
     }
-    
+
     private func mainController() -> UIViewController {
     private func mainController() -> UIViewController {
         let appid = O2AuthSDK.shared.customStyle()?.indexPortal
         let appid = O2AuthSDK.shared.customStyle()?.indexPortal
         let indexType = O2AuthSDK.shared.customStyle()?.indexType ?? "default"
         let indexType = O2AuthSDK.shared.customStyle()?.indexType ?? "default"
@@ -136,39 +137,39 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
                 mail.isIndexShow = true
                 mail.isIndexShow = true
                 let nav = ZLNavigationController(rootViewController: mail)
                 let nav = ZLNavigationController(rootViewController: mail)
                 return nav
                 return nav
-            }else {
+            } else {
                 let nav = ZLNavigationController(rootViewController: destVC)
                 let nav = ZLNavigationController(rootViewController: destVC)
                 return nav
                 return nav
             }
             }
-        }else{
+        } else {
             let destVC = OOTabBarHelper.getVC(storyboardName: "task", vcName: nil)
             let destVC = OOTabBarHelper.getVC(storyboardName: "task", vcName: nil)
             let nav = ZLNavigationController(rootViewController: destVC)
             let nav = ZLNavigationController(rootViewController: destVC)
             return nav
             return nav
         }
         }
     }
     }
-    
+
     private func _loginIM() {
     private func _loginIM() {
         viewModel.registerIM().then { (result) in
         viewModel.registerIM().then { (result) in
             self.viewModel.loginIM().then({ (result) in
             self.viewModel.loginIM().then({ (result) in
                 Log.debug(message: "IM登陆完成")
                 Log.debug(message: "IM登陆完成")
             })
             })
-            }.catch { (imError) in
-                let error = imError as! OOLoginError
-                switch error {
-                case .imRegisterFail(let myErr):
-                    Log.debug(message: myErr.errorDescription!)
-                    self.viewModel.loginIM().then({ (result) in
-                        Log.debug(message: "IM登陆完成")
-                    }).catch({ (loginError) in
-                        Log.error(message: "im Login Error \(loginError)")
-                    })
-                    break
-                default:
-                    break
-                }
+        }.catch { (imError) in
+            let error = imError as! OOLoginError
+            switch error {
+            case .imRegisterFail(let myErr):
+                Log.debug(message: myErr.errorDescription!)
+                self.viewModel.loginIM().then({ (result) in
+                    Log.debug(message: "IM登陆完成")
+                }).catch({ (loginError) in
+                    Log.error(message: "im Login Error \(loginError)")
+                })
+                break
+            default:
+                break
+            }
         }
         }
     }
     }
-    
+
     private func checkAppVersion() {
     private func checkAppVersion() {
         O2VersionManager.shared.checkAppUpdate { (info, error) in
         O2VersionManager.shared.checkAppUpdate { (info, error) in
             if let iosInfo = info {
             if let iosInfo = info {
@@ -183,31 +184,31 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
                 alertController.addAction(cancelAction)
                 alertController.addAction(cancelAction)
                 alertController.addAction(okAction)
                 alertController.addAction(okAction)
                 UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
                 UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
-            }else {
+            } else {
                 DDLogInfo("没有版本更新:\(error ?? "")")
                 DDLogInfo("没有版本更新:\(error ?? "")")
             }
             }
         }
         }
     }
     }
-    
-   
-    
+
+
+
     // MARK: - websocket
     // MARK: - websocket
-    private var timer:Timer?
+    private var timer: Timer?
     private var isWsOpen = false
     private var isWsOpen = false
-    
+
     private func _startWebsocket() {
     private func _startWebsocket() {
         DDLogDebug("启动websocket连接。。。。。。")
         DDLogDebug("启动websocket连接。。。。。。")
-       let url = AppDelegate.o2Collect.generateWebsocketURL()
-       DDLogDebug("这个是wsurl :\(url)")
-       O2WebsocketManager.instance.startConnect(wsUrl: url, delegate: self)
-   }
-    
+        let url = AppDelegate.o2Collect.generateWebsocketURL()
+        DDLogDebug("这个是wsurl :\(url)")
+        O2WebsocketManager.instance.startConnect(wsUrl: url, delegate: self)
+    }
+
     private func _stopWebsocket() {
     private func _stopWebsocket() {
         DDLogDebug("关闭websocket连接。。。。。。")
         DDLogDebug("关闭websocket连接。。。。。。")
         self.stopTiming()
         self.stopTiming()
         O2WebsocketManager.instance.closeConnect()
         O2WebsocketManager.instance.closeConnect()
     }
     }
-    
+
     private func startTiming() {
     private func startTiming() {
         DDLogDebug("开启定时器 。。。。。。")
         DDLogDebug("开启定时器 。。。。。。")
         if timer != nil {
         if timer != nil {
@@ -227,21 +228,34 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
     //发送心跳
     //发送心跳
     @objc private func sendHeartbeatMsg() {
     @objc private func sendHeartbeatMsg() {
         if isWsOpen {
         if isWsOpen {
-            O2WebsocketManager.instance.send(msg: "heartbeat")
-        }else {//重新启动
+            O2WebsocketManager.instance.send(msg: o2_im_ws_heartbeat)
+        } else { //重新启动
             _startWebsocket()
             _startWebsocket()
         }
         }
     }
     }
-    
+
 }
 }
 
 
 extension O2MainController: WebSocketDelegate {
 extension O2MainController: WebSocketDelegate {
-    
+
 
 
     func didReceive(event: WebSocketEvent, client: WebSocket) {
     func didReceive(event: WebSocketEvent, client: WebSocket) {
         switch event {
         switch event {
         case .text(let text):
         case .text(let text):
-            DDLogDebug("接收的ws消息:\(text)")
+            if text != o2_im_ws_heartbeat { //忽略心跳消息
+                DDLogDebug("接收的ws消息:\(text)")
+                //判断type im消息就发送通知
+                do {
+                    if let dicArr = try JSONSerialization.jsonObject(with: String(text).data(using: .utf8)!, options: .allowFragments) as? [String: AnyObject] {
+                        if let type = dicArr["type"] as? String, type == "im_create" {
+                            if let messageInfo = WsMessage.deserialize(from: text) {
+                                DDLogDebug("接收到im消息 发送通知。。")
+                                NotificationCenter.post(customeNotification: OONotification.websocket, object: messageInfo.body)
+                            }
+                        }
+                    }
+                } catch { }
+            }
             break
             break
         case .connected(let headers):
         case .connected(let headers):
             DDLogDebug("websocket is connected: \(headers)")
             DDLogDebug("websocket is connected: \(headers)")
@@ -251,16 +265,16 @@ extension O2MainController: WebSocketDelegate {
         case .disconnected(let reason, let code):
         case .disconnected(let reason, let code):
             DDLogDebug("websocket is disconnected: \(reason) with code: \(code)")
             DDLogDebug("websocket is disconnected: \(reason) with code: \(code)")
             isWsOpen = false
             isWsOpen = false
-             break
+            break
         case .binary(let data):
         case .binary(let data):
             DDLogDebug("Received binary data: \(data.count)")
             DDLogDebug("Received binary data: \(data.count)")
-             break
+            break
         case .ping(_):
         case .ping(_):
             break
             break
         case .pong(_):
         case .pong(_):
             break
             break
         case .viablityChanged(_):
         case .viablityChanged(_):
-             DDLogDebug("websocket viablityChanged")
+            DDLogDebug("websocket viablityChanged")
             break
             break
         case .reconnectSuggested(_):
         case .reconnectSuggested(_):
             DDLogDebug("websocket reconnectSuggested")
             DDLogDebug("websocket reconnectSuggested")
@@ -268,14 +282,14 @@ extension O2MainController: WebSocketDelegate {
         case .cancelled:
         case .cancelled:
             DDLogDebug("websocket is canceled")
             DDLogDebug("websocket is canceled")
             isWsOpen = false
             isWsOpen = false
-             break
+            break
         case .error(let error):
         case .error(let error):
             DDLogError("websocket is error, \(String(describing: error?.localizedDescription))")
             DDLogError("websocket is error, \(String(describing: error?.localizedDescription))")
             isWsOpen = false
             isWsOpen = false
             break
             break
         }
         }
     }
     }
-    
-    
+
+
 }
 }
 
 

+ 29 - 31
o2ios/O2Platform/App/contacts/contacts.storyboard

@@ -1,11 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="iDJ-yD-7GA">
-    <device id="retina4_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="iDJ-yD-7GA">
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
     <dependencies>
         <deployment identifier="iOS"/>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     </dependencies>
     <scenes>
     <scenes>
@@ -22,7 +20,7 @@
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="EyC-x7-vmj" id="9oF-MQ-3Ei">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="EyC-x7-vmj" id="9oF-MQ-3Ei">
-                                    <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ptf-Ml-OFP">
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ptf-Ml-OFP">
@@ -56,7 +54,7 @@
                                 <rect key="frame" x="0.0" y="105.5" width="375" height="50"/>
                                 <rect key="frame" x="0.0" y="105.5" width="375" height="50"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="b8p-Kf-TPW" id="9SB-Vc-9hf">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="b8p-Kf-TPW" id="9SB-Vc-9hf">
-                                    <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cZm-m3-L0j">
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cZm-m3-L0j">
@@ -110,7 +108,7 @@
             <objects>
             <objects>
                 <tableViewController storyboardIdentifier="ContactPersonInfoV2" title="个人详细信息" useStoryboardIdentifierAsRestorationIdentifier="YES" id="3YZ-RH-20k" customClass="ContactPersonInfoV2ViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                 <tableViewController storyboardIdentifier="ContactPersonInfoV2" title="个人详细信息" useStoryboardIdentifierAsRestorationIdentifier="YES" id="3YZ-RH-20k" customClass="ContactPersonInfoV2ViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="vqn-wS-u18">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="vqn-wS-u18">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                         <view key="tableHeaderView" contentMode="scaleToFill" id="iVq-2P-h4E">
                         <view key="tableHeaderView" contentMode="scaleToFill" id="iVq-2P-h4E">
@@ -228,7 +226,7 @@
                             </constraints>
                             </constraints>
                         </view>
                         </view>
                         <view key="tableFooterView" contentMode="scaleToFill" id="Btm-sH-ehp">
                         <view key="tableFooterView" contentMode="scaleToFill" id="Btm-sH-ehp">
-                            <rect key="frame" x="0.0" y="402" width="375" height="44"/>
+                            <rect key="frame" x="0.0" y="430" width="375" height="44"/>
                             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                             <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                             <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                         </view>
                         </view>
@@ -237,7 +235,7 @@
                                 <rect key="frame" x="0.0" y="358" width="375" height="44"/>
                                 <rect key="frame" x="0.0" y="358" width="375" height="44"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uPu-jr-Eup" id="7cS-du-cCp">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uPu-jr-Eup" id="7cS-du-cCp">
-                                    <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="名称" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ay2-QP-fxz">
                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="名称" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ay2-QP-fxz">
@@ -298,7 +296,7 @@
             <objects>
             <objects>
                 <tableViewController storyboardIdentifier="companyDept" title="公司部门" useStoryboardIdentifierAsRestorationIdentifier="YES" id="AmI-yp-X5H" customClass="ContactCompanyDeptController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                 <tableViewController storyboardIdentifier="companyDept" title="公司部门" useStoryboardIdentifierAsRestorationIdentifier="YES" id="AmI-yp-X5H" customClass="ContactCompanyDeptController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="18" sectionFooterHeight="18" id="RsD-Jy-sNh">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="18" sectionFooterHeight="18" id="RsD-Jy-sNh">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <prototypes>
                         <prototypes>
@@ -306,11 +304,11 @@
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="7bY-dM-eEp" id="mz8-vc-d4J">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="7bY-dM-eEp" id="mz8-vc-d4J">
-                                    <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Prg-Tx-oEu">
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Prg-Tx-oEu">
-                                            <rect key="frame" x="16" y="12" width="30" height="25.5"/>
+                                            <rect key="frame" x="16" y="12" width="30" height="26"/>
                                             <constraints>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="30" id="spI-VN-QSv"/>
                                                 <constraint firstAttribute="width" constant="30" id="spI-VN-QSv"/>
                                             </constraints>
                                             </constraints>
@@ -357,7 +355,7 @@
             <objects>
             <objects>
                 <tableViewController id="P8m-JR-nYf" customClass="ContactSearchViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                 <tableViewController id="P8m-JR-nYf" customClass="ContactSearchViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="18" sectionFooterHeight="18" id="U3c-0i-9CP">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="18" sectionFooterHeight="18" id="U3c-0i-9CP">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <prototypes>
                         <prototypes>
@@ -365,7 +363,7 @@
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="j4U-nO-WUz" id="xGE-eP-qH3">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="j4U-nO-WUz" id="xGE-eP-qH3">
-                                    <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="spM-02-Z2O">
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="spM-02-Z2O">
@@ -415,7 +413,7 @@
             <objects>
             <objects>
                 <tableViewController title="我的群组" id="LsC-tt-HCK" customClass="ContactGroupPersonController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                 <tableViewController title="我的群组" id="LsC-tt-HCK" customClass="ContactGroupPersonController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="QdT-78-ZZu">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="QdT-78-ZZu">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <prototypes>
                         <prototypes>
@@ -423,11 +421,11 @@
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="VH3-gE-Egt" id="r7U-bZ-8Ro">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="VH3-gE-Egt" id="r7U-bZ-8Ro">
-                                    <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2Yy-Gs-zHR">
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2Yy-Gs-zHR">
-                                            <rect key="frame" x="16" y="10" width="30" height="23.5"/>
+                                            <rect key="frame" x="16" y="10" width="30" height="24"/>
                                             <constraints>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="30" id="TbG-w1-qGK"/>
                                                 <constraint firstAttribute="width" constant="30" id="TbG-w1-qGK"/>
                                             </constraints>
                                             </constraints>
@@ -477,7 +475,7 @@
                         <viewControllerLayoutGuide type="bottom" id="MLL-Af-ftg"/>
                         <viewControllerLayoutGuide type="bottom" id="MLL-Af-ftg"/>
                     </layoutGuides>
                     </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="miS-ZM-vE9">
                     <view key="view" contentMode="scaleToFill" id="miS-ZM-vE9">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                         <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                     </view>
                     </view>
@@ -491,7 +489,7 @@
             <objects>
             <objects>
                 <tableViewController storyboardIdentifier="DeptPerson" title="部门个人" useStoryboardIdentifierAsRestorationIdentifier="YES" id="rtm-Ih-lnV" customClass="ContactDeptPersonController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                 <tableViewController storyboardIdentifier="DeptPerson" title="部门个人" useStoryboardIdentifierAsRestorationIdentifier="YES" id="rtm-Ih-lnV" customClass="ContactDeptPersonController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="18" sectionFooterHeight="18" id="JaW-sK-m2q">
                     <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="18" sectionFooterHeight="18" id="JaW-sK-m2q">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                         <view key="tableFooterView" contentMode="scaleToFill" id="885-HT-Hf5">
                         <view key="tableFooterView" contentMode="scaleToFill" id="885-HT-Hf5">
@@ -504,11 +502,11 @@
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <rect key="frame" x="0.0" y="55.5" width="375" height="50"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eVD-9I-9Fp" id="KbZ-H9-Myg">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eVD-9I-9Fp" id="KbZ-H9-Myg">
-                                    <rect key="frame" x="0.0" y="0.0" width="375" height="49.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UbD-xq-ZqX">
                                         <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UbD-xq-ZqX">
-                                            <rect key="frame" x="10" y="0.0" width="355" height="49.5"/>
+                                            <rect key="frame" x="10" y="0.0" width="355" height="50"/>
                                         </scrollView>
                                         </scrollView>
                                     </subviews>
                                     </subviews>
                                     <constraints>
                                     <constraints>
@@ -526,7 +524,7 @@
                                 <rect key="frame" x="0.0" y="105.5" width="375" height="50"/>
                                 <rect key="frame" x="0.0" y="105.5" width="375" height="50"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Tw8-69-DnB" id="gPk-m5-2mE">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Tw8-69-DnB" id="gPk-m5-2mE">
-                                    <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Nq8-LU-vKm">
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Nq8-LU-vKm">
@@ -560,7 +558,7 @@
                                 <rect key="frame" x="0.0" y="155.5" width="375" height="50"/>
                                 <rect key="frame" x="0.0" y="155.5" width="375" height="50"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vd8-tW-njc" id="Zue-nP-fAf">
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vd8-tW-njc" id="Zue-nP-fAf">
-                                    <rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="348" height="50"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Zkg-Zp-guU">
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Zkg-Zp-guU">
@@ -611,7 +609,7 @@
                 <navigationController automaticallyAdjustsScrollViewInsets="NO" id="cvC-Xd-NbA" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                 <navigationController automaticallyAdjustsScrollViewInsets="NO" id="cvC-Xd-NbA" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <toolbarItems/>
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="Ih6-yy-4wj">
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="Ih6-yy-4wj">
-                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
                         <autoresizingMask key="autoresizingMask"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     </navigationBar>
                     <nil name="viewControllers"/>
                     <nil name="viewControllers"/>
@@ -624,6 +622,12 @@
             <point key="canvasLocation" x="-767" y="1340"/>
             <point key="canvasLocation" x="-767" y="1340"/>
         </scene>
         </scene>
     </scenes>
     </scenes>
+    <inferredMetricsTieBreakers>
+        <segue reference="ou3-1r-djP"/>
+        <segue reference="JCQ-fv-wZ7"/>
+        <segue reference="5hh-6u-Olo"/>
+        <segue reference="EGH-4l-bNL"/>
+    </inferredMetricsTieBreakers>
     <resources>
     <resources>
         <image name="Shapes" width="25" height="25"/>
         <image name="Shapes" width="25" height="25"/>
         <image name="icon_boy_1" width="50" height="50"/>
         <image name="icon_boy_1" width="50" height="50"/>
@@ -633,10 +637,4 @@
         <image name="personDefaultIcon" width="24" height="24"/>
         <image name="personDefaultIcon" width="24" height="24"/>
         <image name="pic_beijing1" width="375" height="230"/>
         <image name="pic_beijing1" width="375" height="230"/>
     </resources>
     </resources>
-    <inferredMetricsTieBreakers>
-        <segue reference="Sy2-Dk-jgV"/>
-        <segue reference="aMD-xA-Tv2"/>
-        <segue reference="maa-Lm-CVS"/>
-        <segue reference="EGH-4l-bNL"/>
-    </inferredMetricsTieBreakers>
 </document>
 </document>

+ 17 - 8
o2ios/O2Platform/Extension/Bundle+Extension.swift

@@ -15,33 +15,42 @@ import Foundation
 //private  let _bundle:UnsafePointer<Void> =  unsafeBitCast(0,to: UnsafePointer<Void>.self)
 //private  let _bundle:UnsafePointer<Void> =  unsafeBitCast(0,to: UnsafePointer<Void>.self)
 
 
 class BundleEx: Bundle {
 class BundleEx: Bundle {
-    
+
     override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
     override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
         if let bundle = languageBundle() {
         if let bundle = languageBundle() {
             return bundle.localizedString(forKey: key, value: value, table: tableName)
             return bundle.localizedString(forKey: key, value: value, table: tableName)
-        }else{
+        } else {
             return super.localizedString(forKey: key, value: value, table: tableName)
             return super.localizedString(forKey: key, value: value, table: tableName)
         }
         }
     }
     }
-    
-    
+
+
 }
 }
 
 
-extension Bundle{
+extension Bundle {
 //    private struct Static {
 //    private struct Static {
 //        static let onceToken: Static = { Static() }()
 //        static let onceToken: Static = { Static() }()
 //    }
 //    }
 //
 //
-    func onLanguage(){
+    func onLanguage() {
         //替换NSBundle.mainBundle()为自定义的BundleEx
         //替换NSBundle.mainBundle()为自定义的BundleEx
         DispatchQueue.once(token: "language") {
         DispatchQueue.once(token: "language") {
             object_setClass(Bundle.main, BundleEx.self)
             object_setClass(Bundle.main, BundleEx.self)
         }
         }
     }
     }
-    
+
     //当前语言的bundle
     //当前语言的bundle
-    func languageBundle() -> Bundle?{
+    func languageBundle() -> Bundle? {
         return Languager.standardLanguager().currentLanguageBundle
         return Languager.standardLanguager().currentLanguageBundle
     }
     }
+
+    //o2 表情包读取
+    func o2EmojiBundle(anyClass: AnyClass) -> Bundle {
+        var bundle: Bundle = Bundle.main
+        if let resource = Bundle(for: anyClass.self).path(forResource: "O2Emoji", ofType: "bundle") {
+            bundle = Bundle(path: resource) ?? Bundle.main
+        }
+        return bundle
+    }
 }
 }
 
 

+ 16 - 4
o2ios/O2Platform/Extension/Date+Extension.swift

@@ -211,6 +211,13 @@ extension Date {
         return self.year == date.year
         return self.year == date.year
     }
     }
     
     
+    /**间隔天数
+     */
+    func betweenDays(_ date: Date) -> Int {
+        let components = Calendar.current.dateComponents([.day], from: self, to: date)
+        return abs(components.day ?? 0)
+    }
+    
     func haveSameYearAndMonth(_ date: Date) -> Bool {
     func haveSameYearAndMonth(_ date: Date) -> Bool {
         return self.haveSameYear(date) && self.month == date.month
         return self.haveSameYear(date) && self.month == date.month
     }
     }
@@ -285,11 +292,16 @@ extension Date {
                 returnTimeString = "\(gap)天前"
                 returnTimeString = "\(gap)天前"
             }
             }
         }else if now.haveSameYear(self) {
         }else if now.haveSameYear(self) {
-            let gap = now.month - self.month
-            if gap < 4 {
-                returnTimeString = "\(gap)个月前"
+            let days = now.betweenDays(self)
+            if days > 30 {
+                let gap = now.month - self.month
+                if gap < 4 {
+                    returnTimeString = "\(gap)个月前"
+                }else {
+                    returnTimeString = self.formatterDate(formatter: "yyyy-MM-dd")
+                }
             }else {
             }else {
-                returnTimeString = self.formatterDate(formatter: "yyyy-MM-dd")
+               returnTimeString = "\(days)天前"
             }
             }
         }else {
         }else {
             returnTimeString = self.formatterDate(formatter: "yyyy-MM-dd")
             returnTimeString = self.formatterDate(formatter: "yyyy-MM-dd")

+ 2 - 0
o2ios/O2Platform/Extension/Notification+Extension.swift

@@ -22,6 +22,8 @@ enum OONotification:String {
     //重载门户webview
     //重载门户webview
     case reloadPortal
     case reloadPortal
     
     
+    case websocket
+    
     
     
     
     
     var stringValue:String {
     var stringValue:String {

+ 72 - 0
o2ios/O2Platform/Framework/O2API/Communicate/CommunicateAPI.swift

@@ -0,0 +1,72 @@
+//
+//  CommunicateAPI.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Moya
+import O2OA_Auth_SDK
+
+// MARK: - 消息模块
+
+enum CommunicateAPI {
+    case myConversationList
+    
+    
+}
+
+extension CommunicateAPI: OOAPIContextCapable {
+    var apiContextKey: String {
+           return "x_message_assemble_communicate"
+       }
+}
+
+// 是否需要xtoken
+extension CommunicateAPI: OOAccessTokenAuthorizable {
+    var shouldAuthorize: Bool {
+        return true
+    }
+}
+
+extension CommunicateAPI: TargetType {
+    var baseURL: URL {
+        let model  = O2AuthSDK.shared.centerServerInfo()?.assembles?["x_message_assemble_communicate"]
+        let baseURLString = "\(model?.httpProtocol ?? "http")://\(model?.host ?? ""):\(model?.port ?? 0)\(model?.context ?? "")"
+        return URL(string: baseURLString)!
+    }
+    
+    
+    var path: String {
+        switch self {
+        case .myConversationList:
+            return "/jaxrs/im/conversation/list/my"
+        
+        }
+    }
+    
+    var method: Moya.Method {
+        switch self {
+        case .myConversationList:
+            return .get
+         
+        }
+    }
+    
+    var sampleData: Data {
+        return "".data(using: String.Encoding.utf8)!
+    }
+    
+    var task: Task {
+        switch self {
+        case .myConversationList:
+            return .requestPlain
+        }
+    }
+    
+    var headers: [String : String]? {
+        return nil
+    }
+   
+}

BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/Info.plist


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_01.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_02.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_03.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_04.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_05.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_06.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_07.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_08.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_09.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_10.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_11.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_12.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_13.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_14.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_15.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_16.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_17.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_18.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_19.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_20.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_21.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_22.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_23.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_24.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_25.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_26.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_27.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_28.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_29.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_30.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_31.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_32.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_33.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_34.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_35.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_36.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_37.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_38.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_39.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_40.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_41.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_42.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_43.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_44.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_45.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_46.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_47.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_48.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_49.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_50.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_51.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_52.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_53.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_54.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_55.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_56.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_57.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_58.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_59.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_60.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_61.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_62.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_63.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_64.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_65.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_66.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_67.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_68.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_69.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_70.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_71.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_72.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_73.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_74.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_75.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_76.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_77.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_78.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_79.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_80.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_81.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_82.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_83.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_84.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_85.png


BIN
o2ios/O2Platform/Resources/O2Emoji.bundle/im_emotion_86.png


Некоторые файлы не были показаны из-за большого количества измененных файлов