Browse Source

图片消息

fancy 5 years ago
parent
commit
d2741220a0
33 changed files with 642 additions and 200 deletions
  1. 285 151
      o2ios/O2Platform/App/IM-聊天/IMChatViewController.swift
  2. 60 5
      o2ios/O2Platform/App/IM-聊天/IMChatViewController.xib
  3. 11 12
      o2ios/O2Platform/App/IM-聊天/IMConversationListViewController.swift
  4. 19 0
      o2ios/O2Platform/App/IM-聊天/IMViewModel.swift
  5. 5 0
      o2ios/O2Platform/App/IM-聊天/Model/IMConversationInfo.swift
  6. 6 0
      o2ios/O2Platform/App/IM-聊天/O2IM.swift
  7. 41 2
      o2ios/O2Platform/App/IM-聊天/View/IMChatMessageSendViewCell.swift
  8. 65 26
      o2ios/O2Platform/App/IM-聊天/View/IMChatMessageViewCell.swift
  9. 5 1
      o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.swift
  10. 1 1
      o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.xib
  11. 10 1
      o2ios/O2Platform/App/Work-工作/c/TodoTaskDetailViewController.swift
  12. 6 0
      o2ios/O2Platform/Assets.xcassets/im/Contents.json
  13. 0 0
      o2ios/O2Platform/Assets.xcassets/im/chat_bubble_incomming.imageset/Contents.json
  14. 0 0
      o2ios/O2Platform/Assets.xcassets/im/chat_bubble_incomming.imageset/chat_bubble_incomming@2x.png
  15. 0 0
      o2ios/O2Platform/Assets.xcassets/im/chat_bubble_incomming.imageset/chat_bubble_incomming@3x.png
  16. 0 0
      o2ios/O2Platform/Assets.xcassets/im/chat_bubble_outgoing.imageset/Contents.json
  17. 0 0
      o2ios/O2Platform/Assets.xcassets/im/chat_bubble_outgoing.imageset/chat_bubble_outgoing@2x.png
  18. 0 0
      o2ios/O2Platform/Assets.xcassets/im/chat_bubble_outgoing.imageset/chat_bubble_outgoing@3x.png
  19. 21 0
      o2ios/O2Platform/Assets.xcassets/im/chat_camera.imageset/Contents.json
  20. BIN
      o2ios/O2Platform/Assets.xcassets/im/chat_camera.imageset/chat_camera.png
  21. 21 0
      o2ios/O2Platform/Assets.xcassets/im/chat_image.imageset/Contents.json
  22. BIN
      o2ios/O2Platform/Assets.xcassets/im/chat_image.imageset/chat_image@2x.png
  23. 21 0
      o2ios/O2Platform/Assets.xcassets/im/chat_img.imageset/Contents.json
  24. BIN
      o2ios/O2Platform/Assets.xcassets/im/chat_img.imageset/chat_img.png
  25. 21 0
      o2ios/O2Platform/Assets.xcassets/im/chat_location.imageset/Contents.json
  26. BIN
      o2ios/O2Platform/Assets.xcassets/im/chat_location.imageset/chat_location.png
  27. 21 0
      o2ios/O2Platform/Assets.xcassets/im/chat_mic.imageset/Contents.json
  28. BIN
      o2ios/O2Platform/Assets.xcassets/im/chat_mic.imageset/chat_mic.png
  29. 0 0
      o2ios/O2Platform/Assets.xcassets/im/group_default.imageset/Contents.json
  30. 0 0
      o2ios/O2Platform/Assets.xcassets/im/group_default.imageset/group_default@2x.png
  31. 11 1
      o2ios/O2Platform/Framework/O2API/Communicate/CommunicateAPI.swift
  32. 4 0
      o2ios/O2Platform/Framework/Utils/FileUtil.swift
  33. 8 0
      o2ios/O2Platform/config/O2URLContext.swift

+ 285 - 151
o2ios/O2Platform/App/IM-聊天/IMChatViewController.swift

@@ -9,6 +9,11 @@
 import UIKit
 import CocoaLumberjack
 import O2OA_Auth_SDK
+import BSImagePicker
+import Photos
+import Alamofire
+import AlamofireImage
+import SwiftyJSON
 
 class IMChatViewController: UIViewController {
 
@@ -21,13 +26,13 @@ class IMChatViewController: UIViewController {
     @IBOutlet weak var bottomBarHeightConstraint: NSLayoutConstraint!
     //底部工具栏
     @IBOutlet weak var bottomBar: UIView!
-    
+
     private let emojiBarHeight = 256
     //表情窗口
     private lazy var emojiBar: IMChatEmojiBarView = {
-       let view = Bundle.main.loadNibNamed("IMChatEmojiBarView", owner: self, options: nil)?.first as! IMChatEmojiBarView
+        let view = Bundle.main.loadNibNamed("IMChatEmojiBarView", owner: self, options: nil)?.first as! IMChatEmojiBarView
         view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: emojiBarHeight.toCGFloat)
-       return view
+        return view
     }()
 
     private lazy var viewModel: IMViewModel = {
@@ -39,7 +44,8 @@ class IMChatViewController: UIViewController {
     private var chatMessageList: [IMMessageInfo] = []
     private var page = 1
     private var isShowEmoji = false
-    private var bottomBarHeight = 64
+    private var bottomBarHeight = 64 //底部输入框 表情按钮 的高度
+    private let bottomToolbarHeight = 46 //底部工具栏 麦克风 相册 相机等按钮的位置
 
 
     // MARK: - functions
@@ -55,7 +61,7 @@ class IMChatViewController: UIViewController {
         self.messageInputView.delegate = self
 
         //底部安全距离 老机型没有
-        self.bottomBarHeight = Int(iPhoneX ? 64 + IPHONEX_BOTTOM_SAFE_HEIGHT: 64)
+        self.bottomBarHeight = Int(iPhoneX ? 64 + IPHONEX_BOTTOM_SAFE_HEIGHT: 64) + self.bottomToolbarHeight
         self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
         self.bottomBar.topBorder(width: 1, borderColor: base_gray_color.alpha(0.5))
         self.messageInputView.backgroundColor = base_gray_color
@@ -65,184 +71,312 @@ class IMChatViewController: UIViewController {
             if let c = self.conversation {
                 var person = ""
                 c.personList?.forEach({ (p) in
-                    if  p != O2AuthSDK.shared.myInfo()?.distinguishedName {
+                    if p != O2AuthSDK.shared.myInfo()?.distinguishedName {
                         person = p
                     }
-                })
-                if !person.isEmpty {
-                    self.title = person.split("@").first ?? ""
+                    })
+                    if !person.isEmpty {
+                        self.title = person.split("@").first ?? ""
+                    }
                 }
+            } else {
+                self.title = self.conversation?.title
             }
-        }else {
-            self.title = self.conversation?.title
+            //获取聊天数据
+            self.loadMsgList(page: page)
+            //阅读
+            self.viewModel.readConversation(conversationId: self.conversation?.id)
         }
-        //获取聊天数据
-        self.loadMsgList(page: page)
-        //阅读
-        self.viewModel.readConversation(conversationId: self.conversation?.id)
-    }
-    
-    override func viewWillAppear(_ animated: Bool) {
-         NotificationCenter.default.addObserver(self, selector: #selector(receiveMessageFromWs(notice:)), name: OONotification.websocket.notificationName, object: nil)
-    }
-    override func viewWillDisappear(_ animated: Bool) {
-        NotificationCenter.default.removeObserver(self)
-    }
-    
-    
-    @objc private func receiveMessageFromWs(notice: Notification) {
-        DDLogDebug("接收到websocket im 消息")
-        if let message = notice.object as? IMMessageInfo {
-            if message.conversationId == self.conversation?.id {
-                self.chatMessageList.append(message)
-                self.scrollMessageToBottom()
-                self.viewModel.readConversation(conversationId: self.conversation?.id)
+
+        override func viewWillAppear(_ animated: Bool) {
+            NotificationCenter.default.addObserver(self, selector: #selector(receiveMessageFromWs(notice:)), name: OONotification.websocket.notificationName, object: nil)
+        }
+        override func viewWillDisappear(_ animated: Bool) {
+            NotificationCenter.default.removeObserver(self)
+        }
+
+
+        @objc private func receiveMessageFromWs(notice: Notification) {
+            DDLogDebug("接收到websocket im 消息")
+            if let message = notice.object as? IMMessageInfo {
+                if message.conversationId == self.conversation?.id {
+                    self.chatMessageList.append(message)
+                    self.scrollMessageToBottom()
+                    self.viewModel.readConversation(conversationId: self.conversation?.id)
+                }
             }
         }
-    }
 
-    //获取消息
-    private func loadMsgList(page: Int) {
-        if let c = self.conversation, let id = c.id {
-            self.viewModel.myMsgPageList(page: page, conversationId: id).then { (list) in
-                self.chatMessageList = list
-                self.scrollMessageToBottom()
+        //获取消息
+        private func loadMsgList(page: Int) {
+            if let c = self.conversation, let id = c.id {
+                self.viewModel.myMsgPageList(page: page, conversationId: id).then { (list) in
+                    self.chatMessageList = list
+                    self.scrollMessageToBottom()
+                }
+            } else {
+                self.showError(title: "参数错误!!!")
             }
-        } else {
-            self.showError(title: "参数错误!!!")
         }
-    }
-    //刷新tableview 滚动到底部
-    private func scrollMessageToBottom() {
-        DispatchQueue.main.async {
-            self.tableView.reloadData()
-            if self.chatMessageList.count > 0 {
-                self.tableView.scrollToRow(at: IndexPath(row: self.chatMessageList.count-1, section: 0), at: .bottom, animated: true)
+        //刷新tableview 滚动到底部
+        private func scrollMessageToBottom() {
+            DispatchQueue.main.async {
+                self.tableView.reloadData()
+                if self.chatMessageList.count > 0 {
+                    self.tableView.scrollToRow(at: IndexPath(row: self.chatMessageList.count - 1, section: 0), at: .bottom, animated: true)
+                }
             }
         }
-    }
-    
-    //发送文本消息
-    private func sendTextMessage() {
-        guard let msg = self.messageInputView.text else {
-            return
-        }
-        self.messageInputView.text = ""
-        let body = IMMessageBodyInfo()
-        body.type = o2_im_msg_type_text
-        body.body = msg
-        sendMessage(body: body)
-    }
-    //发送表情消息
-    private func sendEmojiMessage(emoji: String) {
-        let body = IMMessageBodyInfo()
-        body.type = o2_im_msg_type_emoji
-        body.body = emoji
-        sendMessage(body: body)
-    }
-    
-    //发送消息到服务器
-    private func sendMessage(body: IMMessageBodyInfo) {
-        let message = IMMessageInfo()
-        message.body = body.toJSONString()
-        message.id = UUID().uuidString
-        message.conversationId = self.conversation?.id
-        message.createPerson = O2AuthSDK.shared.myInfo()?.distinguishedName
-        message.createTime = Date().formatterDate(formatter: "yyyy-MM-dd HH:mm:ss")
-        //添加到界面
-        self.chatMessageList.append(message)
-        self.scrollMessageToBottom()
+
+        //发送文本消息
+        private func sendTextMessage() {
+            guard let msg = self.messageInputView.text else {
+                return
+            }
+            self.messageInputView.text = ""
+            let body = IMMessageBodyInfo()
+            body.type = o2_im_msg_type_text
+            body.body = msg
+            sendMessage(body: body)
+        }
+        //发送表情消息
+        private func sendEmojiMessage(emoji: String) {
+            let body = IMMessageBodyInfo()
+            body.type = o2_im_msg_type_emoji
+            body.body = emoji
+            sendMessage(body: body)
+        }
+
         //发送消息到服务器
-        self.viewModel.sendMsg(msg: message)
-            .then { (result)  in
-                DDLogDebug("发送消息成功 \(result)")
-                self.viewModel.readConversation(conversationId: self.conversation?.id)
-        }.catch { (error) in
-            DDLogError(error.localizedDescription)
-            self.showError(title: "发送消息失败!")
+        private func sendMessage(body: IMMessageBodyInfo) {
+            let message = IMMessageInfo()
+            message.body = body.toJSONString()
+            message.id = UUID().uuidString
+            message.conversationId = self.conversation?.id
+            message.createPerson = O2AuthSDK.shared.myInfo()?.distinguishedName
+            message.createTime = Date().formatterDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            //添加到界面
+            self.chatMessageList.append(message)
+            self.scrollMessageToBottom()
+            //发送消息到服务器
+            self.viewModel.sendMsg(msg: message)
+                .then { (result) in
+                    DDLogDebug("发送消息成功 \(result)")
+                    self.viewModel.readConversation(conversationId: self.conversation?.id)
+                }.catch { (error) in
+                    DDLogError(error.localizedDescription)
+                    self.showError(title: "发送消息失败!")
+            }
         }
-    }
 
+        //选择照片
+        private func chooseImageOrTakePhoto() {
+            let vc = FileBSImagePickerViewController()
+            bs_presentImagePickerController(vc, animated: true, select: { (asset) in
+                //选中一个
+            }, deselect: { (asset) in
+                    //取消选中一个
+                }, cancel: { (assets) in
+                    //取消
+                }, finish: { (assets) in
+                    //结果
+                    if assets.count > 0 {
+                        switch assets[0].mediaType {
+                        case .image:
+                            let options = PHImageRequestOptions()
+                            options.isSynchronous = true
+                            options.deliveryMode = .fastFormat
+                            options.resizeMode = .none
+                            PHImageManager.default().requestImageData(for: assets[0], options: options) { (imageData, result, imageOrientation, dict) in
+                                guard let data = imageData else {
+                                    return
+                                }
+                                var newData = data
+                                //处理图片旋转的问题
+                                if imageOrientation != UIImage.Orientation.up {
+                                    let newImage = UIImage(data: data)?.fixOrientation()
+                                    if newImage != nil {
+                                        newData = newImage!.pngData()!
+                                    }
+                                }
+                                var fileName = ""
+                                if dict?["PHImageFileURLKey"] != nil {
+                                    let fileURL = dict?["PHImageFileURLKey"] as! URL
+                                    fileName = fileURL.lastPathComponent
+                                } else {
+                                    fileName = "\(UUID().uuidString).png"
+                                }
+                                let localFilePath = self.storageLocalImage(imageData: newData, fileName: fileName)
+                                let msgId = self.prepareForSendImageMsg(filePath: localFilePath)
+                                self.uploadImageAndSendMsg(messageId: msgId, imageData: newData, fileName: fileName)
+                            }
+                            break
+                        default:
+                            //
+                            DDLogError("不支持的类型")
+                            self.showError(title: "不支持的类型!")
+                            break
+                        }
+                    }
+                }, completion: nil)
+        }
+        //临时存储本地
+        private func storageLocalImage(imageData: Data, fileName: String) -> String {
+            let fileTempPath = FileUtil.share.cacheDir().appendingPathComponent(fileName)
+            do {
+                try imageData.write(to: fileTempPath)
+                return fileTempPath.path
+            } catch {
+                print(error.localizedDescription)
+                return fileTempPath.path
+            }
+        }
+        //发送消息前 先载入界面
+        private func prepareForSendImageMsg(filePath: String) -> String {
+            let body = IMMessageBodyInfo()
+            body.type = o2_im_msg_type_image
+            body.body = o2_im_msg_body_image
+            body.fileTempPath = filePath
+            let message = IMMessageInfo()
+            let msgId = UUID().uuidString
+            message.body = body.toJSONString()
+            message.id = msgId
+            message.conversationId = self.conversation?.id
+            message.createPerson = O2AuthSDK.shared.myInfo()?.distinguishedName
+            message.createTime = Date().formatterDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            //添加到界面
+            self.chatMessageList.append(message)
+            self.scrollMessageToBottom()
+            return msgId
+        }
 
-    // MARK: - IBAction
-    //点击表情按钮
-    @IBAction func clickEmojiBtn(_ sender: UIButton) {
-        self.isShowEmoji.toggle()
-        self.view.endEditing(true)
-        if self.isShowEmoji {
-            self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat + self.emojiBarHeight.toCGFloat
-            self.emojiBar.delegate = self
-            self.emojiBar.translatesAutoresizingMaskIntoConstraints = false
-            self.bottomBar.addSubview(self.emojiBar)
-            let top = NSLayoutConstraint(item: self.emojiBar, attribute: .top, relatedBy: .equal, toItem: self.emojiBar.superview!, attribute: .top, multiplier: 1, constant: CGFloat(self.bottomBarHeight))
-            let width = NSLayoutConstraint(item: self.emojiBar, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: SCREEN_WIDTH)
-            let height = NSLayoutConstraint(item: self.emojiBar, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: self.emojiBarHeight.toCGFloat)
-            NSLayoutConstraint.activate([top, width, height])
-        } else {
-            self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
-            self.emojiBar.removeFromSuperview()
+        //上传图片到服务器并发送消息
+        private func uploadImageAndSendMsg(messageId: String, imageData: Data, fileName: String) {
+            guard let cId = self.conversation?.id else {
+                return
+            }
+            self.viewModel.uploadFile(conversationId: cId, type:o2_im_msg_type_image, fileName: fileName, file: imageData).then{ attachId in
+                DDLogDebug("上传图片成功: \(attachId)")
+                 guard let message = self.chatMessageList.first (where: { (info) -> Bool in
+                     return info.id == messageId
+                 }) else {
+                    DDLogDebug("没有找到对应的消息")
+                     return
+                 }
+                 let body = IMMessageBodyInfo.deserialize(from: message.body)
+                 body?.fileId = attachId
+                 body?.fileTempPath = nil
+                 message.body = body?.toJSONString()
+                 //发送消息到服务器
+                 self.viewModel.sendMsg(msg: message)
+                     .then { (result) in
+                         DDLogDebug("图片消息 发送成功 \(result)")
+                         self.viewModel.readConversation(conversationId: self.conversation?.id)
+                     }.catch { (error) in
+                         DDLogError(error.localizedDescription)
+                         self.showError(title: "发送消息失败!")
+                 }
+            }.catch { err in
+                self.showError(title: "上传错误,\(err.localizedDescription)")
+            }
+            
+           
+        }
+
+
+        // MARK: - IBAction
+        //点击表情按钮
+        @IBAction func clickEmojiBtn(_ sender: UIButton) {
+            self.isShowEmoji.toggle()
+            self.view.endEditing(true)
+            if self.isShowEmoji {
+                self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat + self.emojiBarHeight.toCGFloat
+                self.emojiBar.delegate = self
+                self.emojiBar.translatesAutoresizingMaskIntoConstraints = false
+                self.bottomBar.addSubview(self.emojiBar)
+                let top = NSLayoutConstraint(item: self.emojiBar, attribute: .top, relatedBy: .equal, toItem: self.emojiBar.superview!, attribute: .top, multiplier: 1, constant: CGFloat(self.bottomBarHeight))
+                let width = NSLayoutConstraint(item: self.emojiBar, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: SCREEN_WIDTH)
+                let height = NSLayoutConstraint(item: self.emojiBar, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: self.emojiBarHeight.toCGFloat)
+                NSLayoutConstraint.activate([top, width, height])
+            } else {
+                self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
+                self.emojiBar.removeFromSuperview()
+            }
+            self.view.layoutIfNeeded()
+        }
+
+        @IBAction func micBtnClick(_ sender: UIButton) {
+            DDLogDebug("点击了麦克风按钮")
         }
-        self.view.layoutIfNeeded()
-    }
 
+        @IBAction func imgBtnClick(_ sender: UIButton) {
+            DDLogDebug("点击了图片按钮")
+            self.chooseImageOrTakePhoto()
+        }
+        @IBAction func cameraBtnClick(_ sender: UIButton) {
+            DDLogDebug("点击了相机按钮")
+        }
+        @IBAction func locationBtnClick(_ sender: UIButton) {
+            DDLogDebug("点击了位置按钮")
+        }
 
 
-}
+    }
 
 // MARK: - 表情点击 delegate
-extension IMChatViewController: IMChatEmojiBarClickDelegate {
-    func clickEmoji(emoji: String) {
-        DDLogDebug("发送表情消息 \(emoji)")
-        self.sendEmojiMessage(emoji: emoji)
+    extension IMChatViewController: IMChatEmojiBarClickDelegate {
+        func clickEmoji(emoji: String) {
+            DDLogDebug("发送表情消息 \(emoji)")
+            self.sendEmojiMessage(emoji: emoji)
+        }
     }
-}
 
 // MARK: - tableview delegate
-extension IMChatViewController: UITableViewDelegate, UITableViewDataSource {
+    extension IMChatViewController: UITableViewDelegate, UITableViewDataSource {
 
-    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-        return self.chatMessageList.count
-    }
+        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+            return self.chatMessageList.count
+        }
 
-    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
-        let msg = self.chatMessageList[indexPath.row]
-        if msg.createPerson == O2AuthSDK.shared.myInfo()?.distinguishedName { //发送者
-            if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageSendViewCell", for: indexPath) as? IMChatMessageSendViewCell {
-                cell.setContent(item: self.chatMessageList[indexPath.row])
-                return cell
-            }
-        }else {
-            if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageViewCell", for: indexPath) as? IMChatMessageViewCell {
-                cell.setContent(item: self.chatMessageList[indexPath.row])
-                return cell
+        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+            let msg = self.chatMessageList[indexPath.row]
+            if msg.createPerson == O2AuthSDK.shared.myInfo()?.distinguishedName { //发送者
+                if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageSendViewCell", for: indexPath) as? IMChatMessageSendViewCell {
+                    cell.setContent(item: self.chatMessageList[indexPath.row])
+                    return cell
+                }
+            } else {
+                if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageViewCell", for: indexPath) as? IMChatMessageViewCell {
+                    cell.setContent(item: self.chatMessageList[indexPath.row])
+                    return cell
+                }
             }
+            return UITableViewCell()
         }
-        return UITableViewCell()
-    }
-    
-    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-        tableView.deselectRow(at: indexPath, animated: false)
-    }
 
-}
+        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+            tableView.deselectRow(at: indexPath, animated: false)
+        }
 
-// MARK: - textField delegate
-extension IMChatViewController: UITextFieldDelegate {
-    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
-        DDLogDebug("准备开始输入......")
-        closeEmoji()
-        return true
     }
 
-    private func closeEmoji() {
-        self.isShowEmoji = false
-        self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
-        self.view.layoutIfNeeded()
-    }
+// MARK: - textField delegate
+    extension IMChatViewController: UITextFieldDelegate {
+        func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
+            DDLogDebug("准备开始输入......")
+            closeEmoji()
+            return true
+        }
 
-    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
-        DDLogDebug("回车。。。。")
-        self.sendTextMessage()
-        return true
+        private func closeEmoji() {
+            self.isShowEmoji = false
+            self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
+            self.view.layoutIfNeeded()
+        }
+
+        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+            DDLogDebug("回车。。。。")
+            self.sendTextMessage()
+            return true
+        }
     }
-}

+ 60 - 5
o2ios/O2Platform/App/IM-聊天/IMChatViewController.xib

@@ -22,11 +22,6 @@
             <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
             <subviews>
-                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ZIb-3p-hnq">
-                    <rect key="frame" x="0.0" y="44" width="414" height="754"/>
-                    <color key="backgroundColor" red="0.95294117649999999" green="0.95294117649999999" blue="0.95294117649999999" alpha="1" colorSpace="calibratedRGB"/>
-                    <color key="sectionIndexBackgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                </tableView>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sDg-us-Ed9">
                     <rect key="frame" x="0.0" y="798" width="414" height="98"/>
                     <subviews>
@@ -49,17 +44,73 @@
                                 <action selector="clickEmojiBtn:" destination="-1" eventType="touchUpInside" id="hZk-xk-g8t"/>
                             </connections>
                         </button>
+                        <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="H2g-NL-0Ps">
+                            <rect key="frame" x="14" y="53" width="386" height="36"/>
+                            <subviews>
+                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dw7-Gt-B9S">
+                                    <rect key="frame" x="0.0" y="2" width="96.5" height="32"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="32" id="L8w-G8-QcX"/>
+                                    </constraints>
+                                    <state key="normal" image="chat_mic"/>
+                                    <connections>
+                                        <action selector="micBtnClick:" destination="-1" eventType="touchUpInside" id="qN7-d7-8AE"/>
+                                    </connections>
+                                </button>
+                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="maW-x1-6ob">
+                                    <rect key="frame" x="96.5" y="2" width="96.5" height="32"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="32" id="NCL-G0-g4l"/>
+                                    </constraints>
+                                    <state key="normal" image="chat_img"/>
+                                    <connections>
+                                        <action selector="imgBtnClick:" destination="-1" eventType="touchUpInside" id="Jbr-NQ-U7b"/>
+                                    </connections>
+                                </button>
+                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zj7-bo-0tf">
+                                    <rect key="frame" x="193" y="2" width="96.5" height="32"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="32" id="mDx-JV-z4Q"/>
+                                    </constraints>
+                                    <state key="normal" image="chat_camera"/>
+                                    <connections>
+                                        <action selector="cameraBtnClick:" destination="-1" eventType="touchUpInside" id="v70-6D-pKx"/>
+                                    </connections>
+                                </button>
+                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eXj-l2-Ioo">
+                                    <rect key="frame" x="289.5" y="2" width="96.5" height="32"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="32" id="Fae-3Q-Qrq"/>
+                                    </constraints>
+                                    <state key="normal" image="chat_location"/>
+                                    <connections>
+                                        <action selector="locationBtnClick:" destination="-1" eventType="touchUpInside" id="Jwe-pL-EpP"/>
+                                    </connections>
+                                </button>
+                            </subviews>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="36" id="xmi-XZ-ezm"/>
+                            </constraints>
+                        </stackView>
                     </subviews>
                     <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                     <constraints>
+                        <constraint firstItem="H2g-NL-0Ps" firstAttribute="top" secondItem="8BW-XG-rBx" secondAttribute="bottom" constant="5" id="1hG-6h-KgV"/>
                         <constraint firstAttribute="trailing" secondItem="oTD-nU-xkE" secondAttribute="trailing" constant="12" id="BtK-YW-2fb"/>
                         <constraint firstItem="oTD-nU-xkE" firstAttribute="top" secondItem="sDg-us-Ed9" secondAttribute="top" constant="12" id="JKE-h8-gll"/>
                         <constraint firstItem="oTD-nU-xkE" firstAttribute="leading" secondItem="8BW-XG-rBx" secondAttribute="trailing" constant="24" id="Mzm-dM-gqy"/>
+                        <constraint firstItem="H2g-NL-0Ps" firstAttribute="leading" secondItem="sDg-us-Ed9" secondAttribute="leading" constant="14" id="Nkm-xr-kRS"/>
                         <constraint firstItem="8BW-XG-rBx" firstAttribute="top" secondItem="sDg-us-Ed9" secondAttribute="top" constant="12" id="hnf-bY-DYH"/>
                         <constraint firstItem="8BW-XG-rBx" firstAttribute="leading" secondItem="sDg-us-Ed9" secondAttribute="leading" constant="14" id="kAO-OU-1mN"/>
+                        <constraint firstAttribute="trailing" secondItem="H2g-NL-0Ps" secondAttribute="trailing" constant="14" id="nDu-Mf-6te"/>
                         <constraint firstAttribute="height" constant="98" id="qiu-7O-AwO"/>
                     </constraints>
                 </view>
+                <tableView clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ZIb-3p-hnq">
+                    <rect key="frame" x="0.0" y="24" width="414" height="720"/>
+                    <color key="backgroundColor" red="0.95294117649999999" green="0.95294117649999999" blue="0.95294117649999999" alpha="1" colorSpace="calibratedRGB"/>
+                    <color key="sectionIndexBackgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                </tableView>
             </subviews>
             <color key="backgroundColor" systemColor="systemGray6Color" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
             <constraints>
@@ -76,6 +127,10 @@
         </view>
     </objects>
     <resources>
+        <image name="chat_camera" width="42" height="32"/>
         <image name="chat_emoji" width="24" height="24"/>
+        <image name="chat_img" width="32" height="32"/>
+        <image name="chat_location" width="41" height="32"/>
+        <image name="chat_mic" width="32" height="32"/>
     </resources>
 </document>

+ 11 - 12
o2ios/O2Platform/App/IM-聊天/IMConversationListViewController.swift

@@ -198,22 +198,21 @@ extension IMConversationListViewController: UITableViewDelegate, UITableViewData
     }
 
     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
-        }
-        if self.instantMsgList.count > 0 {
-            if indexPath.row == 0 {
-                c.setInstantContent(item: self.instantMsgList.last!)
+        if let cell = tableView.dequeueReusableCell(withIdentifier: "IMConversationItemCell", for: indexPath) as? IMConversationItemCell {
+            if self.instantMsgList.count > 0 {
+                if indexPath.row == 0 {
+                    cell.setInstantContent(item: self.instantMsgList.last!)
+                }else {
+                    cell.bindConversation(conversation: self.conversationList[indexPath.row - 1])
+                }
             }else {
-                c.bindConversation(conversation: self.conversationList[indexPath.row - 1])
+                cell.bindConversation(conversation: self.conversationList[indexPath.row])
             }
-        }else {
-            c.bindConversation(conversation: self.conversationList[indexPath.row])
+            return cell
         }
+        return UITableViewCell()
     }
+
     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
         return 64
     }

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

@@ -75,6 +75,25 @@ extension IMViewModel {
                 })
         }
     }
+    
+    //上传文件
+    func uploadFile(conversationId: String, type: String, fileName: String, file: Data) -> Promise<String> {
+       return Promise { fulfill, reject in
+           self.communicateAPI.request(.imUploadFile(conversationId, type, fileName, file), completion: { (result) in
+               let response = OOResult<BaseModelClass<OOCommonIdModel>>(result)
+               if response.isResultSuccess() {
+                   if let id = response.model?.data {
+                       fulfill(id.id ?? "")
+                   }else {
+                       reject(OOAppError.apiEmptyResultError)
+                   }
+               }else {
+                   reject(response.error!)
+               }
+           })
+       }
+   }
+   
 
     //查询会话列表
     func myConversationList() -> Promise<[IMConversationInfo]> {

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

@@ -62,6 +62,11 @@ class IMMessageBodyInfo: NSObject, DataModel {
     @objc var id: String?
     @objc var type: String?
     @objc var body: String?
+    @objc var fileId: String? //文件id
+    @objc var fileTempPath: String? //本地临时文件地址
+    @objc var address: String? //type=location的时候位置信息
+    var latitude: Double?//type=location的时候位置信息
+    var longitude: Double?//type=location的时候位置信息
 
 
     required override init() { }

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

@@ -15,8 +15,14 @@ let o2_im_ws_heartbeat = "heartbeat"
 let o2_im_conversation_type_single = "single"
 let o2_im_conversation_type_group = "group"
 
+//消息分类
 let o2_im_msg_type_text = "text"
 let o2_im_msg_type_emoji = "emoji"
+let o2_im_msg_type_image = "image"
+
+//消息body
+let o2_im_msg_body_image = "[图片]"
+let o2_im_msg_body_video = "[视频]"
 
 
 //表情的字符串转化为O2Emoji.bundle里面的图片路径 [01] -> im_emotion_01

+ 41 - 2
o2ios/O2Platform/App/IM-聊天/View/IMChatMessageSendViewCell.swift

@@ -7,6 +7,7 @@
 //
 
 import UIKit
+import CocoaLumberjack
 
 class IMChatMessageSendViewCell: UITableViewCell {
     @IBOutlet weak var timeLabel: UILabel!
@@ -48,14 +49,52 @@ class IMChatMessageSendViewCell: UITableViewCell {
         }
         self.messageBackgroundView.removeSubviews()
         if let jsonBody = item.body, let body = parseJson(msg: jsonBody) {
-            if body.type == o2_im_msg_type_emoji {
+            if o2_im_msg_type_emoji == body.type {
                 emojiMsgRender(emoji: body.body!)
-            }else {
+            }else if o2_im_msg_type_image == body.type {
+                imageMsgRender(info: body)
+            } else {
                 textMsgRender(msg: body.body!)
             }
         }
     }
     
+    //图片消息
+    private func imageMsgRender(info: IMMessageBodyInfo) {
+        let width: CGFloat = 144
+        let height: CGFloat = 192
+        self.messageBgWidth.constant = width + 20
+        self.messageBgHeight.constant = height + 20
+        //图片
+        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
+        if let fileId = info.fileId {
+            DDLogDebug("fileId  :\(fileId)")
+            let urlStr = AppDelegate.o2Collect.generateURLWithAppContextKey(
+                CommunicateContext.communicateContextKey,
+                query: CommunicateContext.imDownloadImageWithSizeQuery,
+                parameter: ["##id##": fileId as AnyObject,
+                    "##width##": "144" as AnyObject,
+                    "##height##": "192" as AnyObject], generateTime: false)
+            if let url = URL(string: urlStr!) {
+                imageView.hnk_setImageFromURL(url)
+            } else {
+                imageView.image = UIImage(named: "chat_image")
+            }
+        } else if let filePath = info.fileTempPath {
+            DDLogDebug("filePath  :\(filePath)")
+            imageView.hnk_setImageFromFile(filePath)
+        } else {
+            imageView.image = UIImage(named: "chat_image")
+        }
+        imageView.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(imageView)
+        let top = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: imageView.superview!, attribute: .top, multiplier: 1, constant: 10)
+        let bottom = NSLayoutConstraint(item: imageView.superview!, attribute: .bottom, relatedBy: .equal, toItem: imageView, attribute: .bottom, multiplier: 1, constant: 10)
+        let left = NSLayoutConstraint(item: imageView, attribute: .leading, relatedBy: .equal, toItem: imageView.superview!, attribute: .leading, multiplier: 1, constant: 10)
+        let right = NSLayoutConstraint(item: imageView.superview!, attribute: .trailing, relatedBy: .equal, toItem: imageView, attribute: .trailing, multiplier: 1, constant: 10)
+        NSLayoutConstraint.activate([top, bottom, left, right])
+
+    }
     
     private func emojiMsgRender(emoji: String) {
         let emojiSize = 36

+ 65 - 26
o2ios/O2Platform/App/IM-聊天/View/IMChatMessageViewCell.swift

@@ -18,16 +18,16 @@ class IMChatMessageViewCell: UITableViewCell {
     @IBOutlet weak var messageBackgroundWidth: NSLayoutConstraint!
     @IBOutlet weak var messageBackgroundHeight: NSLayoutConstraint!
     private let messageWidth = 176
-    
+
     override func awakeFromNib() {
         super.awakeFromNib()
-        
+
     }
 
     override func setSelected(_ selected: Bool, animated: Bool) {
         super.setSelected(selected, animated: animated)
     }
-   
+
     //普通通知消息
     func setInstantContent(item: InstantMessage) {
         if let time = item.createTime {
@@ -41,43 +41,43 @@ class IMChatMessageViewCell: UITableViewCell {
             if type.starts(with: "task_") {
                 self.avatarImage.image = UIImage(named: "icon_daiban")
                 self.titleLabel.text = "待办消息"
-            }else if type.starts(with: "taskCompleted_") {
+            } else if type.starts(with: "taskCompleted_") {
                 self.avatarImage.image = UIImage(named: "icon_taskcompleted")
                 self.titleLabel.text = "已办消息"
-            }else if type.starts(with: "read_") {
+            } else if type.starts(with: "read_") {
                 self.avatarImage.image = UIImage(named: "icon_read")
                 self.titleLabel.text = "待阅消息"
-            }else if type.starts(with: "readCompleted_") {
+            } else if type.starts(with: "readCompleted_") {
                 self.avatarImage.image = UIImage(named: "icon_readcompleted")
                 self.titleLabel.text = "已阅消息"
-            }else if type.starts(with: "review_") || type.starts(with: "work_") || type.starts(with: "process_") {
+            } else if type.starts(with: "review_") || type.starts(with: "work_") || type.starts(with: "process_") {
                 self.avatarImage.image = UIImage(named: "icon_daiban")
                 self.titleLabel.text = "工作消息"
-            }else if type.starts(with: "meeting_") {
+            } else if type.starts(with: "meeting_") {
                 self.avatarImage.image = UIImage(named: "icon_meeting")
                 self.titleLabel.text = "会议消息"
-            }else if type.starts(with: "attachment_") {
+            } else if type.starts(with: "attachment_") {
                 self.avatarImage.image = UIImage(named: "icon_yunpan")
                 self.titleLabel.text = "云盘消息"
-            }else if type.starts(with: "calendar_") {
+            } else if type.starts(with: "calendar_") {
                 self.avatarImage.image = UIImage(named: "icon_calendar")
                 self.titleLabel.text = "日历消息"
-            }else if type.starts(with: "cms_") {
+            } else if type.starts(with: "cms_") {
                 self.avatarImage.image = UIImage(named: "icon_cms")
                 self.titleLabel.text = "信息中心消息"
-            }else if type.starts(with: "bbs_") {
+            } else if type.starts(with: "bbs_") {
                 self.avatarImage.image = UIImage(named: "icon_bbs")
                 self.titleLabel.text = "论坛消息"
-            }else if type.starts(with: "mind_") {
+            } else if type.starts(with: "mind_") {
                 self.avatarImage.image = UIImage(named: "icon_mindMap")
                 self.titleLabel.text = "脑图消息"
-            }else {
+            } else {
                 self.avatarImage.image = UIImage(named: "icon_email")
                 self.titleLabel.text = "其他消息"
             }
         }
     }
-    
+
     //聊天消息
     func setContent(item: IMMessageInfo) {
         //time
@@ -87,15 +87,15 @@ class IMChatMessageViewCell: UITableViewCell {
         }
         //name avatart
         if let person = item.createPerson {
-            let urlstr = AppDelegate.o2Collect.generateURLWithAppContextKey(ContactContext.contactsContextKeyV2, query: ContactContext.personIconByNameQueryV2, parameter: ["##name##":person as AnyObject], generateTime: false)
+            let urlstr = AppDelegate.o2Collect.generateURLWithAppContextKey(ContactContext.contactsContextKeyV2, query: ContactContext.personIconByNameQueryV2, parameter: ["##name##": person as AnyObject], generateTime: false)
             if let u = URL(string: urlstr!) {
                 self.avatarImage.hnk_setImageFromURL(u)
-            }else {
+            } else {
                 self.avatarImage.image = UIImage(named: "icon_men")
             }
             //姓名
             self.titleLabel.text = person.split("@").first ?? ""
-        }else {
+        } else {
             self.avatarImage.image = UIImage(named: "icon_men")
             self.titleLabel.text = ""
         }
@@ -103,12 +103,51 @@ class IMChatMessageViewCell: UITableViewCell {
         if let jsonBody = item.body, let body = parseJson(msg: jsonBody) {
             if body.type == o2_im_msg_type_emoji {
                 emojiMsgRender(emoji: body.body!)
-            }else {
+            } else if body.type == o2_im_msg_type_image {
+                imageMsgRender(info: body)
+            } else {
                 textMsgRender(msg: body.body!)
             }
         }
     }
-    
+
+    //图片消息
+    private func imageMsgRender(info: IMMessageBodyInfo) {
+        let width: CGFloat = 144
+        let height: CGFloat = 192
+        self.messageBackgroundWidth.constant = width + 20
+        self.messageBackgroundHeight.constant = height + 20
+        //图片
+        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
+        if let fileId = info.fileId {
+            DDLogDebug("file id :\(fileId)")
+            let urlStr = AppDelegate.o2Collect.generateURLWithAppContextKey(
+                CommunicateContext.communicateContextKey,
+                query: CommunicateContext.imDownloadImageWithSizeQuery,
+                parameter: ["##id##": fileId as AnyObject,
+                    "##width##": "144" as AnyObject,
+                    "##height##": "192" as AnyObject], generateTime: false)
+            if let url = URL(string: urlStr!) {
+                imageView.hnk_setImageFromURL(url)
+            } else {
+                imageView.image = UIImage(named: "chat_image")
+            }
+        } else if let filePath = info.fileTempPath {
+            DDLogDebug("filePath  :\(filePath)")
+            imageView.hnk_setImageFromFile(filePath)
+        } else {
+            imageView.image = UIImage(named: "chat_image")
+        }
+        imageView.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(imageView)
+        let top = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: imageView.superview!, attribute: .top, multiplier: 1, constant: 10)
+        let bottom = NSLayoutConstraint(item: imageView.superview!, attribute: .bottom, relatedBy: .equal, toItem: imageView, attribute: .bottom, multiplier: 1, constant: 10)
+        let left = NSLayoutConstraint(item: imageView, attribute: .leading, relatedBy: .equal, toItem: imageView.superview!, attribute: .leading, multiplier: 1, constant: 10)
+        let right = NSLayoutConstraint(item: imageView.superview!, attribute: .trailing, relatedBy: .equal, toItem: imageView, attribute: .trailing, multiplier: 1, constant: 10)
+        NSLayoutConstraint.activate([top, bottom, left, right])
+
+    }
+
     private func emojiMsgRender(emoji: String) {
         let emojiSize = 36
         let width = CGFloat(emojiSize + 20)
@@ -130,12 +169,12 @@ class IMChatMessageViewCell: UITableViewCell {
         emojiImage.translatesAutoresizingMaskIntoConstraints = false
         self.messageBackgroundView.addSubview(emojiImage)
         let top = NSLayoutConstraint(item: emojiImage, attribute: .top, relatedBy: .equal, toItem: emojiImage.superview!, attribute: .top, multiplier: 1, constant: 10)
-        let bottom = NSLayoutConstraint(item: emojiImage.superview! , attribute: .bottom, relatedBy: .equal, toItem: emojiImage, attribute: .bottom, multiplier: 1, constant: 10)
+        let bottom = NSLayoutConstraint(item: emojiImage.superview!, attribute: .bottom, relatedBy: .equal, toItem: emojiImage, attribute: .bottom, multiplier: 1, constant: 10)
         let left = NSLayoutConstraint(item: emojiImage, attribute: .leading, relatedBy: .equal, toItem: emojiImage.superview!, attribute: .leading, multiplier: 1, constant: 10)
         let right = NSLayoutConstraint(item: emojiImage.superview!, attribute: .trailing, relatedBy: .equal, toItem: emojiImage, attribute: .trailing, multiplier: 1, constant: 10)
         NSLayoutConstraint.activate([top, bottom, left, right])
     }
-    
+
     private func textMsgRender(msg: String) {
         let size = calTextSize(str: msg)
         self.messageBackgroundWidth.constant = size.width + 20
@@ -156,7 +195,7 @@ class IMChatMessageViewCell: UITableViewCell {
         let right = NSLayoutConstraint(item: label.superview!, attribute: .trailing, relatedBy: .equal, toItem: label, attribute: .trailing, multiplier: 1, constant: 10)
         NSLayoutConstraint.activate([top, left, right])
     }
-    
+
     private func generateMessagelabel(str: String, size: CGSize) -> UILabel {
         let label = UILabel(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
         label.text = str
@@ -166,13 +205,13 @@ class IMChatMessageViewCell: UITableViewCell {
         label.preferredMaxLayoutWidth = size.width
         return label
     }
-    
-    
+
+
     private func calTextSize(str: String) -> CGSize {
         let size = CGSize(width: messageWidth.toCGFloat, height: CGFloat(MAXFLOAT))
         return str.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], context: nil).size
     }
-    
+
     //解析json为消息对象
     private func parseJson(msg: String) -> IMMessageBodyInfo? {
         return IMMessageBodyInfo.deserialize(from: msg)

+ 5 - 1
o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.swift

@@ -91,7 +91,11 @@ class IMConversationItemCell: UITableViewCell {
                 let bundle = Bundle().o2EmojiBundle(anyClass: IMConversationItemCell.self)
                 let path = o2ImEmojiPath(emojiBody: body.body!)
                 self.emojiImg.image = UIImage(named: path, in: bundle, compatibleWith: nil)
-            }else {
+            }else if  body.type == o2_im_msg_type_image {
+                self.messageLabel.text = body.body
+                self.messageLabel.isHidden = false
+                self.emojiImg.isHidden = true
+            } else {
                 self.messageLabel.isHidden = true
                 self.emojiImg.isHidden = true
             }

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

@@ -44,7 +44,7 @@
                         <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">
+                    <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">
                         <rect key="frame" x="70" y="37" width="245" 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"/>

+ 10 - 1
o2ios/O2Platform/App/Work-工作/c/TodoTaskDetailViewController.swift

@@ -903,10 +903,19 @@ extension TodoTaskDetailViewController: O2WKScriptMessageHandlerImplement {
                         DispatchQueue.main.async {
                             self.showLoading(title: "上传中...")
                         }
+                        var newData = imageData
+                        //处理图片旋转的问题
+                        if imageOrientation != UIImage.Orientation.up && imageData != nil {
+                            let newImage = UIImage(data: imageData!)?.fixOrientation()
+                            if newImage != nil {
+                                newData = newImage?.pngData()
+                            }
+                        }
+                        
                         DispatchQueue.global(qos: .userInitiated).async {
                             Alamofire.upload(multipartFormData: { (mData) in
                                 //mData.append(fileURL, withName: "file")
-                                mData.append(imageData!, withName: "file", fileName: fileName, mimeType: "application/octet-stream")
+                                mData.append(newData!, withName: "file", fileName: fileName, mimeType: "application/octet-stream")
                                 let siteData = site.data(using: String.Encoding.utf8, allowLossyConversion: false)
                                 mData.append(siteData!, withName: "site")
                             }, to: url, encodingCompletion: { (encodingResult) in

+ 6 - 0
o2ios/O2Platform/Assets.xcassets/im/Contents.json

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

+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/chat_bubble_incomming.imageset/Contents.json → o2ios/O2Platform/Assets.xcassets/im/chat_bubble_incomming.imageset/Contents.json


+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/chat_bubble_incomming.imageset/chat_bubble_incomming@2x.png → o2ios/O2Platform/Assets.xcassets/im/chat_bubble_incomming.imageset/chat_bubble_incomming@2x.png


+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/chat_bubble_incomming.imageset/chat_bubble_incomming@3x.png → o2ios/O2Platform/Assets.xcassets/im/chat_bubble_incomming.imageset/chat_bubble_incomming@3x.png


+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/chat_bubble_outgoing.imageset/Contents.json → o2ios/O2Platform/Assets.xcassets/im/chat_bubble_outgoing.imageset/Contents.json


+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/chat_bubble_outgoing.imageset/chat_bubble_outgoing@2x.png → o2ios/O2Platform/Assets.xcassets/im/chat_bubble_outgoing.imageset/chat_bubble_outgoing@2x.png


+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/chat_bubble_outgoing.imageset/chat_bubble_outgoing@3x.png → o2ios/O2Platform/Assets.xcassets/im/chat_bubble_outgoing.imageset/chat_bubble_outgoing@3x.png


+ 21 - 0
o2ios/O2Platform/Assets.xcassets/im/chat_camera.imageset/Contents.json

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

BIN
o2ios/O2Platform/Assets.xcassets/im/chat_camera.imageset/chat_camera.png


+ 21 - 0
o2ios/O2Platform/Assets.xcassets/im/chat_image.imageset/Contents.json

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

BIN
o2ios/O2Platform/Assets.xcassets/im/chat_image.imageset/chat_image@2x.png


+ 21 - 0
o2ios/O2Platform/Assets.xcassets/im/chat_img.imageset/Contents.json

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

BIN
o2ios/O2Platform/Assets.xcassets/im/chat_img.imageset/chat_img.png


+ 21 - 0
o2ios/O2Platform/Assets.xcassets/im/chat_location.imageset/Contents.json

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

BIN
o2ios/O2Platform/Assets.xcassets/im/chat_location.imageset/chat_location.png


+ 21 - 0
o2ios/O2Platform/Assets.xcassets/im/chat_mic.imageset/Contents.json

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

BIN
o2ios/O2Platform/Assets.xcassets/im/chat_mic.imageset/chat_mic.png


+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/group_default.imageset/Contents.json → o2ios/O2Platform/Assets.xcassets/im/group_default.imageset/Contents.json


+ 0 - 0
o2ios/O2Platform/Assets.xcassets/首页/group_default.imageset/group_default@2x.png → o2ios/O2Platform/Assets.xcassets/im/group_default.imageset/group_default@2x.png


+ 11 - 1
o2ios/O2Platform/Framework/O2API/Communicate/CommunicateAPI.swift

@@ -18,6 +18,7 @@ enum CommunicateAPI {
     case readConversation(String)
     case instantMessageList(Int)
     case createConversation(IMConversationInfo)
+    case imUploadFile(String, String, String, Data)
     
     
 }
@@ -57,6 +58,8 @@ extension CommunicateAPI: TargetType {
             return "/jaxrs/instant/list/currentperson/noim/count/\(count)/desc"
         case .createConversation(_):
             return "/jaxrs/im/conversation"
+        case .imUploadFile(let conversationId, let type, _, _):
+            return "/jaxrs/im/msg/upload/\(conversationId)/type/\(type)"
         }
     }
     
@@ -64,7 +67,7 @@ extension CommunicateAPI: TargetType {
         switch self {
         case .myConversationList, .instantMessageList(_):
             return .get
-        case .msgListByPaging(_, _, _), .sendMsg(_), .createConversation(_):
+        case .msgListByPaging(_, _, _), .sendMsg(_), .createConversation(_), .imUploadFile(_, _, _, _):
             return .post
         case .readConversation(_):
             return .put
@@ -87,6 +90,13 @@ extension CommunicateAPI: TargetType {
             return .requestParameters(parameters: msg.toJSON()!, encoding: JSONEncoding.default)
         case .createConversation(let conv):
             return .requestParameters(parameters: conv.toJSON()!, encoding: JSONEncoding.default)
+        case .imUploadFile(_, _, let fileName, let data):
+            //字符串类型 文件名
+            let strData = fileName.data(using: .utf8)
+            let fileNameData = MultipartFormData(provider: .data(strData!), name: "fileName")
+            //文件类型
+            let fileData = MultipartFormData(provider: .data(data), name: "file", fileName: fileName)
+            return .uploadMultipart([fileData, fileNameData])
         }
     }
     

+ 4 - 0
o2ios/O2Platform/Framework/Utils/FileUtil.swift

@@ -104,6 +104,10 @@ public class FileUtil {
         return NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
     }
     
+    public func cacheDir() -> URL {
+        return FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
+    }
+    
     public func cacheDirectoryPath(file: String) -> String {
         return (self.cacheDirectory() as NSString).appendingPathComponent(file)
     }

+ 8 - 0
o2ios/O2Platform/config/O2URLContext.swift

@@ -261,6 +261,14 @@ struct BBSContext {
     
 }
 
+struct CommunicateContext {
+    static let communicateContextKey = "x_message_assemble_communicate"
+    static let imUploadFileQuery = "jaxrs/im/msg/upload/##conversationId##/type/##type##"
+    //文件打开地址
+    static let imDownloadFileQuery = "jaxrs/im/msg/download/##id##"
+    //图片根据尺寸压缩 0<width<5000 0<height<5000
+    static let imDownloadImageWithSizeQuery = "jaxrs/im/msg/download/##id##/image/width/##width##/height/##height##"
+}
 
 struct DesktopContext {
     static let DesktopContextKey = "x_desktop"