Эх сурвалжийг харах

Merge branch 'develop' into 'feature/MinderEditor.add_export'

# Conflicts:
#   o2web/source/x_component_MinderEditor/MainMenu.js
蔡祥熠 5 жил өмнө
parent
commit
bb0157f6e6
100 өөрчлөгдсөн 8088 нэмэгдсэн , 2356 устгасан
  1. 21 3
      gulpfile.js
  2. 3 0
      o2android/app/build.gradle
  3. 4 2
      o2android/app/src/main/AndroidManifest.xml
  4. 4 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2App.kt
  5. 18 38
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/bbs/view/BBSWebViewSubjectActivity.kt
  6. 84 56
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/CloudDriveActivity.kt
  7. 1 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/CloudDriveCooperationFileFragment.kt
  8. 84 54
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/v2/CloudDiskFileDownloadHelper.kt
  9. 44 62
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/viewer/CloudDrivePictureViewerFragment.kt
  10. 49 37
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/cms/view/CMSWebViewPresenter.kt
  11. 385 40
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatActivity.kt
  12. 5 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatContract.kt
  13. 94 19
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatMessageAdapter.kt
  14. 97 15
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatPresenter.kt
  15. 4 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2IM.kt
  16. 291 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2LocationActivity.kt
  17. 46 5
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/fm/O2IMConversationFragment.kt
  18. 0 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/meeting/invited/MeetingDetailInfoActivity.kt
  19. 16 73
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/meeting/invited/MeetingDetailInfoPresenter.kt
  20. 41 8
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainActivity.kt
  21. 107 54
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/webview/DownloadDocument.kt
  22. 93 74
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/webview/TaskWebViewPresenter.kt
  23. 12 2
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/service/PictureLoaderService.kt
  24. 73 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/O2FileDownloadHelper.kt
  25. 13 0
      o2android/app/src/main/res/drawable/f5_circle.xml
  26. 5 4
      o2android/app/src/main/res/layout/activity_local_image_view.xml
  27. 38 2
      o2android/app/src/main/res/layout/activity_o2_chat.xml
  28. 38 0
      o2android/app/src/main/res/layout/activity_o2_location.xml
  29. 15 0
      o2android/app/src/main/res/layout/fragment_main_bottom_bar_image.xml
  30. 46 0
      o2android/app/src/main/res/layout/item_o2_chat_message_text_left.xml
  31. 46 0
      o2android/app/src/main/res/layout/item_o2_chat_message_text_right.xml
  32. 11 0
      o2android/app/src/main/res/menu/menu_location_send.xml
  33. BIN
      o2android/app/src/main/res/mipmap-xhdpi/chat_icon_audio_play.png
  34. BIN
      o2android/app/src/main/res/mipmap-xhdpi/chat_location_background.png
  35. BIN
      o2android/app/src/main/res/mipmap-xhdpi/group_default.png
  36. 3 0
      o2android/app/src/main/res/values/strings.xml
  37. 2 2
      o2android/gradle.properties
  38. 24 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/APIAddressHelper.kt
  39. 1 8
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/BBSAssembleControlService.kt
  40. 0 9
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/CMSAssembleControlService.kt
  41. 0 10
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/CloudFileControlService.kt
  42. 1 8
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/FileAssembleControlService.kt
  43. 0 8
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/MeetingAssembleControlService.kt
  44. 16 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/MessageCommunicateService.kt
  45. 1 9
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssembleExpressService.kt
  46. 19 19
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/ProcessAssembleSurfaceService.kt
  47. 13 26
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/im/IMMessage.kt
  48. 12 7
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/im/IMMessageBody.kt
  49. 12 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/im/IMMessageFileData.kt
  50. 1 0
      o2ios/.gitignore
  51. 303 57
      o2ios/O2Platform.xcodeproj/project.pbxproj
  52. 14 4
      o2ios/O2Platform/App/Applications/c/MailViewController.swift
  53. 56 0
      o2ios/O2Platform/App/BBS-论坛/BBSViewModel.swift
  54. 230 94
      o2ios/O2Platform/App/BBS-论坛/bbs.storyboard
  55. 0 3
      o2ios/O2Platform/App/BBS-论坛/c/BBSReplySubjectViewController.swift
  56. 82 0
      o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectAttachmentViewController.swift
  57. 1 1
      o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectCreateTableViewController.swift
  58. 55 34
      o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectDetailViewController.swift
  59. 4 3
      o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectListViewController.swift
  60. 176 141
      o2ios/O2Platform/App/BBS-论坛/m/OOBBSModels.swift
  61. 72 0
      o2ios/O2Platform/App/BBS-论坛/v/BBSSubjectAttachmentViewCell.swift
  62. 62 0
      o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarEditRemarkViewController.swift
  63. 33 8
      o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarEventViewController.swift
  64. 11 0
      o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarLeftMenuController.swift
  65. 405 54
      o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarViewController.swift
  66. 12 0
      o2ios/O2Platform/App/Calendar-日程管理/Model/OOCalendarModels.swift
  67. 1428 1209
      o2ios/O2Platform/App/Calendar-日程管理/calendar.storyboard
  68. 4 6
      o2ios/O2Platform/App/Cms-内容管理/c/CMSItemDetailViewController.swift
  69. 47 28
      o2ios/O2Platform/App/File-云盘/c/FileBSImagePickerViewController.swift
  70. 2 3
      o2ios/O2Platform/App/File-云盘/c/MainFileViewController.swift
  71. 560 0
      o2ios/O2Platform/App/IM-聊天/IMChatViewController.swift
  72. 136 0
      o2ios/O2Platform/App/IM-聊天/IMChatViewController.xib
  73. 240 0
      o2ios/O2Platform/App/IM-聊天/IMConversationListViewController.swift
  74. 64 0
      o2ios/O2Platform/App/IM-聊天/IMInstantMessageViewController.swift
  75. 30 0
      o2ios/O2Platform/App/IM-聊天/IMInstantMessageViewController.xib
  76. 141 0
      o2ios/O2Platform/App/IM-聊天/IMLocationChooseController.swift
  77. 60 0
      o2ios/O2Platform/App/IM-聊天/IMLocationChooseController.xib
  78. 51 0
      o2ios/O2Platform/App/IM-聊天/IMShowLocationViewController.swift
  79. 163 0
      o2ios/O2Platform/App/IM-聊天/IMViewModel.swift
  80. 134 0
      o2ios/O2Platform/App/IM-聊天/Model/IMConversationInfo.swift
  81. 102 0
      o2ios/O2Platform/App/IM-聊天/O2IM.swift
  82. 26 0
      o2ios/O2Platform/App/IM-聊天/View/IMAudioView.swift
  83. 57 0
      o2ios/O2Platform/App/IM-聊天/View/IMAudioView.xib
  84. 96 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatAudioView.swift
  85. 57 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatAudioView.xib
  86. 68 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiBarView.swift
  87. 43 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiBarView.xib
  88. 25 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiItemCell.swift
  89. 41 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiItemCell.xib
  90. 243 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatMessageSendViewCell.swift
  91. 84 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatMessageSendViewCell.xib
  92. 302 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatMessageViewCell.swift
  93. 84 0
      o2ios/O2Platform/App/IM-聊天/View/IMChatMessageViewCell.xib
  94. 118 0
      o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.swift
  95. 117 0
      o2ios/O2Platform/App/IM-聊天/View/IMConversationItemCell.xib
  96. 26 0
      o2ios/O2Platform/App/IM-聊天/View/IMLocationView.swift
  97. 59 0
      o2ios/O2Platform/App/IM-聊天/View/IMLocationView.xib
  98. 1 1
      o2ios/O2Platform/App/Login-绑定登录/c/OOLoginViewController.swift
  99. 69 44
      o2ios/O2Platform/App/NewAttance-考勤打卡/c/OOAttanceCheckInController.swift
  100. 1 9
      o2ios/O2Platform/App/NewAttance-考勤打卡/c/OOAttanceSettingController.swift

+ 21 - 3
gulpfile.js

@@ -466,10 +466,28 @@ function build_concat_xform(){
         .pipe(rename({ extname: '.min.js' }))
         .pipe(gulp.dest(dest))
 }
+
+function build_bundle(){
+    let path = "o2_core";
+    var src = [
+        'o2web/source/o2_lib/mootools/mootools-1.6.0_all.js',
+        'o2web/source/o2_lib/mootools/plugin/mBox.js',
+        'o2web/source/o2_core/o2.js',
+        'o2web/source/x_desktop/js/base.js',
+        "o2web/source/o2_core/o2/framework.js"
+    ];
+    var dest = 'target/o2server/servers/webServer/'+path+'/';
+    return gulp.src(src)
+        .pipe(concat('bundle.js'))
+        .pipe(gulp.dest(dest))
+        .pipe(uglify())
+        .pipe(rename({ extname: '.min.js' }))
+        .pipe(gulp.dest(dest))
+}
 // function build_concat(){
 //     return gulp.parallel(build_concat_o2, build_concat_desktop, build_concat_xform);
 // }
-exports.build_concat = gulp.parallel(build_concat_o2, build_concat_desktop, build_concat_xform);
+exports.build_concat = gulp.parallel(build_concat_o2, build_concat_desktop, build_concat_xform, build_bundle);
 
 
 function build_web_v_html() {
@@ -558,9 +576,9 @@ function chmod_commons(){
 function chmod_sh(){
     return (shell.task('chmod 777 target/o2server/*.sh'))();
 }
-exports.build_web = gulp.series(build_web_minimize, build_web_move, gulp.parallel(build_concat_o2, build_concat_desktop, build_concat_xform), build_web_v_html, build_web_v_o2);
+exports.build_web = gulp.series(build_web_minimize, build_web_move, gulp.parallel(build_concat_o2, build_concat_desktop, build_concat_xform, build_bundle), build_web_v_html, build_web_v_o2);
 if (os.platform().indexOf("win")==-1){
     exports.deploy = gulp.series(deploy_server, chmod_jvm, chmod_commons, chmod_sh);
 }else{
     exports.deploy = gulp.series(deploy_server);
-}
+}

+ 3 - 0
o2android/app/build.gradle

@@ -317,6 +317,9 @@ dependencies {
         exclude group: 'com.android.support', module: 'support-media-compat'
     }
 
+    //mp3录音
+    implementation 'com.github.zhaolewei:ZlwAudioRecorder:v1.07'
+
 
 }
 

+ 4 - 2
o2android/app/src/main/AndroidManifest.xml

@@ -41,7 +41,8 @@
         android:label="@string/app_name"
         android:roundIcon="@mipmap/logo_round"
         android:theme="@style/XBPMTheme.NoActionBar">
-        <activity android:name=".app.im.O2InstantMessageActivity"></activity>
+        <activity android:name=".app.im.O2LocationActivity"></activity>
+        <activity android:name=".app.im.O2InstantMessageActivity" />
         <activity android:name=".app.im.O2ChatActivity" />
         <activity android:name=".app.VideoPlayerActivity" />
         <activity
@@ -427,7 +428,8 @@
         <service android:name=".core.service.RestartSelfService" /> <!-- jpush -->
         <service
             android:name=".core.service.WebSocketService"
-            android:exported="false" />
+            android:exported="false" /> <!-- 录音 转mp3 service -->
+        <service android:name="com.zlw.main.recorderlib.recorder.RecordService" />
 
         <receiver
             android:name=".core.receiver.JpushNoticeBroadReceiver"

+ 4 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2App.kt

@@ -16,6 +16,7 @@ import com.baidu.mapapi.SDKInitializer
 import com.facebook.drawee.backends.pipeline.Fresco
 import com.tencent.bugly.crashreport.CrashReport
 import com.tencent.smtt.sdk.QbSdk
+import com.zlw.main.recorderlib.RecordManager
 import io.realm.Realm
 import jiguang.chat.application.JGApplication
 import jiguang.chat.entity.NotificationClickEventReceiver
@@ -116,6 +117,9 @@ class O2App : MultiDexApplication() {
         //注册日志记录器
         LogSingletonService.instance().registerApp(this)
 
+        //录音
+        RecordManager.getInstance().init(this, false)
+
         Log.i("O2app", "O2app init.....................................................")
         //stetho developer tool
 //        Stetho.initializeWithDefaults(this)

+ 18 - 38
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/bbs/view/BBSWebViewSubjectActivity.kt

@@ -24,6 +24,7 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.APIDistributeTypeEnum
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.BBSUploadImageBO
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.bbs.ReplyFormJson
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.bbs.SubjectReplyInfoJson
@@ -32,11 +33,14 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.vo.BBSWebViewAttachmentVO
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.gone
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.hideSoftInput
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.visible
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.AttachPopupWindow
 import org.jetbrains.anko.dip
 import org.jetbrains.anko.doAsync
 import org.jetbrains.anko.uiThread
+import rx.android.schedulers.AndroidSchedulers
+import rx.schedulers.Schedulers
 import java.io.DataInputStream
 import java.io.DataOutputStream
 import java.io.File
@@ -274,46 +278,22 @@ class BBSWebViewSubjectActivity : BaseMVPActivity<BBSWebViewSubjectContract.View
 
     override fun startDownLoadFile(id: String?) {
         if (!TextUtils.isEmpty(id)){
-            taskMap[id!!] = doAsync {
-                val filePath = getAttachFileLocalPath(id)
-                val file = File(filePath)
-                var downloadSuccess = false
-                try {
-                    if (!file.exists()) {
-                        val call = RetrofitClient.instance().bbsAssembleControlServiceApi()
-                                .downloadAttach(id)
-                        val response = call.execute()
-                        val input = DataInputStream(response.body()?.byteStream())
-                        val output = DataOutputStream(FileOutputStream(file))
-                        val buffer = ByteArray(4096)
-                        var count = 0
-                        do {
-                            count = input.read(buffer)
-                            if (count > 0) {
-                                output.write(buffer, 0, count)
-                            }
-                        } while (count > 0)
-                        output.close()
-                        input.close()
-                    }
-                    downloadSuccess = true
-                } catch(e: Exception) {
-                    XLog.error("下载附件异常", e)
-                }
-                uiThread {
-                    if (taskMap.containsKey(id)){
-                        taskMap.remove(id)
-                    }
-                    if (downloadSuccess) {
-                        popupWindow.notifyStatusChanged()
-                    }else{
-                        if (file.exists()){
-                            file.delete()
+            val filePath = getAttachFileLocalPath(id!!)
+            val downloadUrl = APIAddressHelper.instance()
+                    .getCommonDownloadUrl(APIDistributeTypeEnum.x_bbs_assemble_control, "jaxrs/attachment/download/$id/stream/false")
+            XLog.debug("下载附件地址: $downloadUrl")
+            O2FileDownloadHelper.download(downloadUrl, filePath)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            popupWindow.notifyStatusChanged()
+                        }
+                        onError { e, _ ->
+                            XLog.error("", e)
+                            XToast.toastShort(this@BBSWebViewSubjectActivity, "下载附件失败!")
                         }
-                        XToast.toastShort(this@BBSWebViewSubjectActivity, "下载附件失败!")
                     }
-                }
-            }
         }
     }
 

+ 84 - 56
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/CloudDriveActivity.kt

@@ -18,21 +18,17 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.organization.ContactPickerActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonFragmentPagerAdapter
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.APIDistributeTypeEnum
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.FileOperateType
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.AndroidUtils
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XToast
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.gone
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.visible
-import org.jetbrains.anko.doAsync
-import org.jetbrains.anko.uiThread
-import java.io.DataInputStream
-import java.io.DataOutputStream
+import rx.Observer
+import rx.Subscription
+import rx.android.schedulers.AndroidSchedulers
+import rx.schedulers.Schedulers
 import java.io.File
-import java.io.FileOutputStream
-import java.util.concurrent.Future
 
 
 class CloudDriveActivity : BaseMVPActivity<CloudDriveContract.View, CloudDriveContract.Presenter>(), CloudDriveContract.View {
@@ -98,9 +94,9 @@ class CloudDriveActivity : BaseMVPActivity<CloudDriveContract.View, CloudDriveCo
     override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
         if (keyCode == KeyEvent.KEYCODE_BACK) {
             //有下载文件的 取消下载
-            if (!downloadTaskMap.isEmpty()) {
+            if (downloadTaskMap.isNotEmpty()) {
                 downloadTaskMap.map {
-                    it.value.cancel(true)
+                    it.value.unsubscribe()
                 }
                 downloadTaskMap.clear()
                 yunpan_download_file_id.gone()
@@ -146,55 +142,87 @@ class CloudDriveActivity : BaseMVPActivity<CloudDriveContract.View, CloudDriveCo
         super.onActivityResult(requestCode, resultCode, data)
     }
 
-    val downloadTaskMap = HashMap<String, Future<Unit>>()
+    val downloadTaskMap = HashMap<String, Subscription>()
     fun openYunPanFile(id: String, fileName: String) {
         XLog.debug("download id:$id, , file:$fileName")
         if (!downloadTaskMap.containsKey(id)) {
             yunpan_download_file_id.visible()
-            downloadTaskMap.put(id, doAsync {
-                var downfile = true
-                val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileName
-                XLog.debug("file path $path")
-                val file = File(path)
-                if (!file.exists()) {
-                    XLog.debug("file not exist, ${file.path}")
-                    try {
-                        val call = RetrofitClient.instance().fileAssembleControlApi()
-                                .downloadFile(id)
-                        val response = call.execute()
-                        val input  = DataInputStream(response.body()?.byteStream())
-                        val output = DataOutputStream(FileOutputStream(file))
-                        val buffer = ByteArray(4096)
-                        var count = 0
-                        do {
-                            count = input.read(buffer)
-                            if (count > 0) {
-                                output.write(buffer, 0, count)
+            val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileName
+            XLog.debug("file path $path")
+            val downloadUrl = APIAddressHelper.instance()
+                    .getCommonDownloadUrl(APIDistributeTypeEnum.x_file_assemble_control, "jaxrs/attachment/$id/download/stream")
+            val subscription = O2FileDownloadHelper.download(downloadUrl, path)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(object : Observer<Boolean>{
+                        override fun onError(e: Throwable?) {
+                            yunpan_download_file_id.gone()
+                            if (downloadTaskMap.containsKey(id)){
+                                downloadTaskMap.remove(id)
                             }
-                        } while (count > 0)
-                        output.close()
-                        input.close()
-                        downfile = true
-                    }catch (e: Exception){
-                        XLog.error("download file fail", e)
-                        downfile = false
-                    }
-                }
-                uiThread {
-                    if (downloadTaskMap.containsKey(id)){
-                        downloadTaskMap.remove(id)
-                    }
-                    yunpan_download_file_id.gone()
-                    if (downfile) {
-                        AndroidUtils.openFileWithDefaultApp(this@CloudDriveActivity, file)
-                    }else {
-                        if (file.exists()){
-                            file.delete()
+                            XToast.toastShort(this@CloudDriveActivity, "下载附件失败!")
                         }
-                        XToast.toastShort(this@CloudDriveActivity, "下载附件失败!")
-                    }
-                }
-            })
+
+                        override fun onNext(t: Boolean?) {
+                            yunpan_download_file_id.gone()
+                            if (downloadTaskMap.containsKey(id)){
+                                downloadTaskMap.remove(id)
+                            }
+                            AndroidUtils.openFileWithDefaultApp(this@CloudDriveActivity, File(path))
+                        }
+
+                        override fun onCompleted() {
+
+                        }
+
+                    })
+            downloadTaskMap[id] = subscription
+
+//            downloadTaskMap.put(id, doAsync {
+//                var downfile = true
+//                val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileName
+//                XLog.debug("file path $path")
+//                val file = File(path)
+//                if (!file.exists()) {
+//                    XLog.debug("file not exist, ${file.path}")
+//                    try {
+//                        val call = RetrofitClient.instance().fileAssembleControlApi()
+//                                .downloadFile(id)
+//                        val response = call.execute()
+//                        val input  = DataInputStream(response.body()?.byteStream())
+//                        val output = DataOutputStream(FileOutputStream(file))
+//                        val buffer = ByteArray(4096)
+//                        var count = 0
+//                        do {
+//                            count = input.read(buffer)
+//                            if (count > 0) {
+//                                output.write(buffer, 0, count)
+//                            }
+//                        } while (count > 0)
+//                        output.close()
+//                        input.close()
+//                        downfile = true
+//                    }catch (e: Exception){
+//                        XLog.error("download file fail", e)
+//                        downfile = false
+//                    }
+//                }
+//                uiThread {
+//                    if (downloadTaskMap.containsKey(id)){
+//                        downloadTaskMap.remove(id)
+//                    }
+//                    yunpan_download_file_id.gone()
+//                    if (downfile) {
+//                        AndroidUtils.openFileWithDefaultApp(this@CloudDriveActivity, file)
+//                    }else {
+//                        if (file.exists()){
+//                            file.delete()
+//                        }
+//                        XToast.toastShort(this@CloudDriveActivity, "下载附件失败!")
+//                    }
+//                }
+//            })
+
         }
 
     }

+ 1 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/CloudDriveCooperationFileFragment.kt

@@ -228,7 +228,7 @@ class CloudDriveCooperationFileFragment : BaseMVPViewPagerFragment<CloudDriveCoo
                         activity.go<PictureViewActivity>(bundle)
                     } else {
                         val activity = activity as CloudDriveActivity
-                        activity.openYunPanFile(item.id, item.fileName)
+                        activity.openYunPanFile(item.id, item.name)
                     }
                 }
             }

+ 84 - 54
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/v2/CloudDiskFileDownloadHelper.kt

@@ -1,16 +1,16 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.clouddrive.v2
 
 import android.app.Activity
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.APIDistributeTypeEnum
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.O2FileDownloadHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
-import org.jetbrains.anko.doAsync
-import org.jetbrains.anko.uiThread
-import java.io.DataInputStream
-import java.io.DataOutputStream
+import rx.Observer
+import rx.Subscription
+import rx.android.schedulers.AndroidSchedulers
+import rx.schedulers.Schedulers
 import java.io.File
-import java.io.FileOutputStream
-import java.util.concurrent.Future
 
 
 /**
@@ -21,66 +21,96 @@ class CloudDiskFileDownloadHelper(val activity: Activity) {
     var showLoading: (()->Unit)? = null
     var hideLoading: (()->Unit)? = null
 
-    var downloader: Future<Unit>? = null
+//    var downloader: Future<Unit>? = null
+    var subscription: Subscription? = null
 
     /**
      * 开始下载文件
      */
     fun startDownload(fileId: String, extension: String, result: (file: File?)->Unit) {
         showLoading?.invoke()
-        downloader = activity.doAsync {
-            var downfile = true
-            val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileId + "." +extension
-            XLog.debug("file path $path")
-            val file = File(path)
-            if (!file.exists()) {
-                XLog.debug("file not exist, ${file.path}")
-                try {
-                    val call = RetrofitClient.instance().cloudFileControlApi()
-                            .downloadFile(fileId)
-                    val response = call.execute()
-                    val input  = DataInputStream(response.body()?.byteStream())
-                    val output = DataOutputStream(FileOutputStream(file))
-                    val buffer = ByteArray(4096)
-                    var count = 0
-                    do {
-                        count = input.read(buffer)
-                        if (count > 0) {
-                            output.write(buffer, 0, count)
-                        }
-                    } while (count > 0)
-                    output.close()
-                    input.close()
-                    downfile = true
-                }catch (e: Exception){
-                    XLog.error("download file fail", e)
-                    file.delete()
-                    downfile = false
-                }
-            }
 
-            uiThread {
-                XLog.debug("执行了。。。。uiThread。")
-                hideLoading?.invoke()
-                if (downfile) {
-                    result(file)
-                }else {
-                    if (file.exists()){
-                        file.delete()
+        val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileId + "." +extension
+        XLog.debug("file path $path")
+        val downloadUrl = APIAddressHelper.instance()
+                .getCommonDownloadUrl(APIDistributeTypeEnum.x_file_assemble_control, "jaxrs/attachment2/$fileId/download/stream")
+        XLog.debug("下载 文件 url: $downloadUrl")
+
+        subscription = O2FileDownloadHelper.download(downloadUrl, path)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(object : Observer<Boolean>{
+                    override fun onError(e: Throwable?) {
+                        result(null)
+                    }
+
+                    override fun onNext(t: Boolean?) {
+                        result(File(path))
+                    }
+
+                    override fun onCompleted() {
+                        hideLoading?.invoke()
                     }
-                    result(null)
-                }
-            }
-        }
+
+                })
+
+//        downloader = activity.doAsync {
+//            var downfile = true
+//            val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileId + "." +extension
+//            XLog.debug("file path $path")
+//            val file = File(path)
+//            if (!file.exists()) {
+//                XLog.debug("file not exist, ${file.path}")
+//                try {
+//                    val call = RetrofitClient.instance().cloudFileControlApi()
+//                            .downloadFile(fileId)
+//                    val response = call.execute()
+//                    val input  = DataInputStream(response.body()?.byteStream())
+//                    val output = DataOutputStream(FileOutputStream(file))
+//                    val buffer = ByteArray(4096)
+//                    var count = 0
+//                    do {
+//                        count = input.read(buffer)
+//                        if (count > 0) {
+//                            output.write(buffer, 0, count)
+//                        }
+//                    } while (count > 0)
+//                    output.close()
+//                    input.close()
+//                    downfile = true
+//                }catch (e: Exception){
+//                    XLog.error("download file fail", e)
+//                    file.delete()
+//                    downfile = false
+//                }
+//            }
+//
+//            uiThread {
+//                XLog.debug("执行了。。。。uiThread。")
+//                hideLoading?.invoke()
+//                if (downfile) {
+//                    result(fresult(file)ile)
+//                }else {
+//                    if (file.exists()){
+//                        file.delete()
+//                    }
+//                    result(null)
+//                }
+//            }
+//        }
+
+
     }
 
     /**
      * 关闭下载
      */
     fun closeDownload() {
-        if (downloader != null) {
-            hideLoading?.invoke()
-            downloader?.cancel(true)
-        }
+//        if (downloader != null) {
+//            hideLoading?.invoke()
+//            downloader?.cancel(true)
+//        }
+        hideLoading?.invoke()
+        subscription?.unsubscribe()
     }
 }

+ 44 - 62
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/clouddrive/viewer/CloudDrivePictureViewerFragment.kt

@@ -8,21 +8,16 @@ import android.widget.ImageView
 import kotlinx.android.synthetic.main.fragment_picture_viewer.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPViewPagerFragment
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.BitmapUtil
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XToast
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.APIDistributeTypeEnum
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.gone
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.visible
-import org.jetbrains.anko.doAsync
-import org.jetbrains.anko.uiThread
-import java.io.DataInputStream
-import java.io.DataOutputStream
+import rx.Observable
+import rx.Observer
+import rx.android.schedulers.AndroidSchedulers
+import rx.schedulers.Schedulers
 import java.io.File
-import java.io.FileOutputStream
-
-
 
 
 class CloudDrivePictureViewerFragment : BaseMVPViewPagerFragment<CloudDrivePictureViewerContract.View, CloudDrivePictureViewerContract.Presenter>(), CloudDrivePictureViewerContract.View {
@@ -47,59 +42,46 @@ class CloudDrivePictureViewerFragment : BaseMVPViewPagerFragment<CloudDrivePictu
         }else {
             circle_progress_fragment_picture_view.visible()
             zoomImage_fragment_picture_view.visible()
-            doAsync {
-                val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileName
-                XLog.debug("file path $path")
-                val file = File(path)
-                var bitmap:Bitmap? = null
-                if (!file.exists()) {
-                    XLog.debug("file not exist, ${file.path}")
-                    try {
-                        //下载
-                        val call = RetrofitClient.instance().fileAssembleControlApi()
-                                .downloadFile(fileId)
-                        val response = call.execute()
-                        response.errorBody()?.string()
-                        val input  = DataInputStream(response.body()?.byteStream())
-                        val output = DataOutputStream(FileOutputStream(file))
-                        val buffer = ByteArray(4096)
-                        var count = 0
-                        do {
-                            count = input.read(buffer)
-                            if (count > 0) {
-                                output.write(buffer, 0, count)
+
+            val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileName
+            XLog.debug("file path $path")
+            val downloadUrl = APIAddressHelper.instance()
+                    .getCommonDownloadUrl(APIDistributeTypeEnum.x_file_assemble_control, "jaxrs/attachment/$fileId/download/stream")
+            O2FileDownloadHelper.download(downloadUrl, path)
+                    .subscribeOn(Schedulers.io())
+                    .flatMap {
+                        var bitmap:Bitmap? = null
+                        //压缩
+                        val options = BitmapFactory.Options()
+                        options.inJustDecodeBounds = true
+                        val imageSize = getImageViewWidthAndHeight(zoomImage_fragment_picture_view)
+                        val  newW = imageSize.width
+                        val   newH = imageSize.height
+                        XLog.debug("zoomBitmap, newW:$newW,newH:$newH")
+                        options.inSampleSize = BitmapUtil.getFitInSampleSize(newW, newH, options)
+                        options.inJustDecodeBounds = false
+                        bitmap = BitmapFactory.decodeFile(path, options)
+                        Observable.just(bitmap)
+                    }
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(object : Observer<Bitmap> {
+                        override fun onError(e: Throwable?) {
+                            XLog.error("的丁大丁大", e)
+                            circle_progress_fragment_picture_view?.gone()
+                        }
+
+                        override fun onNext(bitmap: Bitmap?) {
+                            if (bitmap!=null) {
+                                zoomImage_fragment_picture_view?.setImageBitmap(bitmap)
                             }
-                        } while (count > 0)
-                        output.close()
-                        input.close()
-                    }catch (e: Exception){
-                        try {
-                            file.delete()
-                        } catch (e: Exception) {
+                            circle_progress_fragment_picture_view?.gone()
                         }
-                        XLog.error("download file fail", e)
 
-                    }
-                }
-
-                //压缩
-                val options = BitmapFactory.Options()
-                options.inJustDecodeBounds = true
-                val imageSize = getImageViewWidthAndHeight(zoomImage_fragment_picture_view)
-                val  newW = imageSize.width
-                val   newH = imageSize.height
-                XLog.debug("zoomBitmap, newW:$newW,newH:$newH")
-                options.inSampleSize = BitmapUtil.getFitInSampleSize(newW, newH, options)
-                options.inJustDecodeBounds = false
-                bitmap = BitmapFactory.decodeFile(path, options)
-
-                uiThread {
-                    circle_progress_fragment_picture_view?.gone()
-                    if (bitmap!=null) {
-                        zoomImage_fragment_picture_view?.setImageBitmap(bitmap)
-                    }
-                }
-            }
+                        override fun onCompleted() {
+                        }
+
+                    })
+
         }
     }
 

+ 49 - 37
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/cms/view/CMSWebViewPresenter.kt

@@ -3,13 +3,16 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.cms.view
 import android.text.TextUtils
 import net.muliba.accounting.app.ExceptionHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.APIDistributeTypeEnum
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.IdData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.cms.CMSDocumentAttachmentJson
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.vo.AttachmentItemVO
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileUtil
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.O2FileDownloadHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import okhttp3.MediaType
 import okhttp3.MultipartBody
@@ -100,47 +103,56 @@ class CMSWebViewPresenter : BasePresenterImpl<CMSWebViewContract.View>(), CMSWeb
                     .flatMap { res->
                         val attachInfo = res.data
                         if (attachInfo != null) {
+
                             val filePath = FileExtensionHelper.getXBPMCMSAttachFolder() + File.separator + attachInfo.name
-                            val file = File(filePath)
-                            try {
-                                if (!file.exists()) {
-                                    val call = cmsService.downloadAttach(attachmentId)
-                                    val response = call.execute()
-                                    val input = DataInputStream(response.body()?.byteStream())
-                                    val output = DataOutputStream(FileOutputStream(file))
-                                    val buffer = ByteArray(4096)
-                                    var count = 0
-                                    do {
-                                        count = input.read(buffer)
-                                        if (count > 0) {
-                                            output.write(buffer, 0, count)
-                                        }
-                                    } while (count > 0)
-                                    output.close()
-                                    input.close()
-                                }
-                            } catch (e: Exception) {
-                                XLog.error("下载附件异常", e)
-                                if (file.exists()) {
-                                    file.delete()
-                                }
-                            }
+                            val downloadUrl = APIAddressHelper.instance()
+                                    .getCommonDownloadUrl(APIDistributeTypeEnum.x_cms_assemble_control, "jaxrs/fileinfo/download/document/$attachmentId/stream")
+                            O2FileDownloadHelper.download(downloadUrl, filePath)
+                                    .flatMap {
+                                        Observable.just(File(filePath))
+                                    }
+
+
+//                            val file = File(filePath)
+//                            try {
+//                                if (!file.exists()) {
+//                                    val call = cmsService.downloadAttach(attachmentId)
+//                                    val response = call.execute()
+//                                    val input = DataInputStream(response.body()?.byteStream())
+//                                    val output = DataOutputStream(FileOutputStream(file))
+//                                    val buffer = ByteArray(4096)
+//                                    var count = 0
+//                                    do {
+//                                        count = input.read(buffer)
+//                                        if (count > 0) {
+//                                            output.write(buffer, 0, count)
+//                                        }
+//                                    } while (count > 0)
+//                                    output.close()
+//                                    input.close()
+//                                }
+//                            } catch (e: Exception) {
+//                                XLog.error("下载附件异常", e)
+//                                if (file.exists()) {
+//                                    file.delete()
+//                                }
+//                            }
+//                            Observable.create { t ->
+//                                val thisfile = File(filePath)
+//                                if (file.exists()) {
+//                                    t?.onNext(thisfile)
+//                                } else {
+//                                    t?.onError(Exception("附件下载异常,找不到文件!"))
+//                                }
+//                                t?.onCompleted()
+//                            }
+
+
+                        }else {
                             Observable.create { t ->
-                                val thisfile = File(filePath)
-                                if (file.exists()) {
-                                    t?.onNext(thisfile)
-                                } else {
-                                    t?.onError(Exception("附件下载异常,找不到文件!"))
-                                }
+                                t?.onError(Exception("没有获取到附件信息,无法下载附件!"))
                                 t?.onCompleted()
                             }
-                        }else {
-                            Observable.create(object : Observable.OnSubscribe<File> {
-                                override fun call(t: Subscriber<in File>?) {
-                                    t?.onError(Exception("没有获取到附件信息,无法下载附件!"))
-                                    t?.onCompleted()
-                                }
-                            })
                         }
                     }.observeOn(AndroidSchedulers.mainThread())
                     .subscribe({ file -> mView?.downloadAttachmentSuccess(file) }, { e ->

+ 385 - 40
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatActivity.kt

@@ -1,38 +1,48 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.im
 
 import android.app.Activity
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
+import android.app.Instrumentation
+import android.content.*
+import android.graphics.Bitmap
+import android.media.AudioFormat
+import android.media.MediaPlayer
+import android.net.Uri
 import android.os.Bundle
+import android.os.CountDownTimer
+import android.provider.MediaStore
 import android.support.v7.widget.GridLayoutManager
 import android.support.v7.widget.LinearLayoutManager
 import android.text.Editable
 import android.text.TextUtils
 import android.text.TextWatcher
+import android.view.MotionEvent
 import android.view.View
 import android.view.WindowManager
 import android.view.inputmethod.InputMethodManager
+import com.wugang.activityresult.library.ActivityResult
+import com.zlw.main.recorderlib.RecordManager
+import com.zlw.main.recorderlib.recorder.RecordConfig
+import com.zlw.main.recorderlib.recorder.RecordHelper
+import com.zlw.main.recorderlib.recorder.listener.RecordStateListener
 import kotlinx.android.synthetic.main.activity_o2_chat.*
+import net.muliba.fancyfilepickerlibrary.PicturePicker
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.webview.LocalImageViewActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecycleViewAdapter
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecyclerViewHolder
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMConversationInfo
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessage
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageBody
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.DateHelper
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XToast
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.*
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.go
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.gone
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.visible
+import java.io.File
 import java.util.*
+import kotlin.math.abs
 
 
-class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Presenter>(), O2ChatContract.View {
+class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Presenter>(), O2ChatContract.View, View.OnTouchListener {
 
     companion object {
         const val con_id_key = "con_id_key"
@@ -49,10 +59,9 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
     override fun layoutResId(): Int = R.layout.activity_o2_chat
 
 
-
     private val adapter: O2ChatMessageAdapter by lazy { O2ChatMessageAdapter() }
     private val emojiList = O2IM.im_emoji_hashMap.keys.toList().sortedBy { it }
-    private val emojiAdapter : CommonRecycleViewAdapter<String> by lazy {
+    private val emojiAdapter: CommonRecycleViewAdapter<String> by lazy {
         object : CommonRecycleViewAdapter<String>(this, emojiList, R.layout.item_o2_im_chat_emoji) {
             override fun convert(holder: CommonRecyclerViewHolder?, t: String?) {
                 if (t != null) {
@@ -69,17 +78,51 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
     private var conversationId = ""
 
     private var conversationInfo: IMConversationInfo? = null
+    //录音服务
+    private var isAudioRecordCancel = false
+    private var audioRecordTime = 0L
+    //录音计时器
+    private val audioCountDownTimer: CountDownTimer by lazy {
+        object : CountDownTimer(60 * 1000, 1000) {
+            override fun onFinish() {
+                XLog.debug("倒计时结束!")
+                endRecordAudio()
+            }
+
+            override fun onTick(millisUntilFinished: Long) {
+                val sec = ((millisUntilFinished + 15) / 1000)
+                audioRecordTime = 60 - sec
+                runOnUiThread {
+                    val times = if (audioRecordTime > 9) {
+                        "00:$audioRecordTime"
+                    } else {
+                        "00:0$audioRecordTime"
+                    }
+                    tv_o2_chat_audio_speak_duration.text = times
+                }
+                XLog.debug("倒计时还剩余:$sec 秒")
+            }
+
+        }
+    }
 
+    //media play
+    private var mPlayer: MediaPlayer? = null
 
-    private var mKeyboardHeight = 150 // 输入法默认高度为400
+    //拍照
+    private val cameraImageUri: Uri by lazy { FileUtil.getUriFromFile(this, File(FileExtensionHelper.getCameraCacheFilePath())) }
+    private val camera_result_code = 10240
 
 
 
+
+//    private var mKeyboardHeight = 150 // 输入法默认高度为400
+
+
     override fun afterSetContentView(savedInstanceState: Bundle?) {
         // 起初的布局可自动调整大小
         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE or WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
 
-
         setupToolBar(defaultTitle, setupBackButton = true)
 
         conversationId = intent.getStringExtra(con_id_key) ?: ""
@@ -92,7 +135,22 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
         rv_o2_chat_messages.adapter = adapter
         adapter.eventListener = object : O2ChatMessageAdapter.MessageEventListener {
             override fun resendClick(message: IMMessage) {
-                mPresenter.sendTextMessage(message)//重新发送
+                mPresenter.sendIMMessage(message)//重新发送
+            }
+
+            override fun playAudio(position: Int, msgBody: IMMessageBody) {
+                XLog.debug("audio play position: $position")
+                mPresenter.getFileFromNetOrLocal(position, msgBody)
+            }
+
+            override fun openOriginImage(position: Int, msgBody: IMMessageBody) {
+                 mPresenter.getFileFromNetOrLocal(position, msgBody)
+            }
+
+            override fun openLocation(msgBody: IMMessageBody) {
+                val location = O2LocationActivity.LocationData(msgBody.address, msgBody.addressDetail, msgBody.latitude, msgBody.longitude)
+                val bundle = O2LocationActivity.showLocation(location)
+                go<O2LocationActivity>(bundle)
             }
         }
         //输入法切换的时候滚动到底部
@@ -113,22 +171,77 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
             mPresenter.readConversation(conversationId)
         }
 
-
-
         initListener()
 
         getPageData()
 
+        //录音格式
+        initAudioRecord()
+
         registerBroadcast()
     }
 
 
 
+
     override fun onDestroy() {
         super.onDestroy()
         if (mReceiver != null) {
             unregisterReceiver(mReceiver)
         }
+        if (mPlayer != null) {
+            mPlayer?.release()//释放资源
+            mPlayer = null
+        }
+    }
+
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        if (resultCode == Activity.RESULT_OK && requestCode == camera_result_code) {
+            //拍照
+            XLog.debug("拍照//// ")
+            newImageMessage(FileExtensionHelper.getCameraCacheFilePath())
+        }
+    }
+
+    private var startY: Float = 0f
+    private var mCurPosY: Float = 0f
+
+    /**
+     * 录音按钮的touch事件
+     * 按住录音
+     * 释放发送语音消息
+     * 上滑取消发送
+     */
+    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
+        if (v?.id == R.id.image_o2_chat_audio_speak_btn) {
+            when (event?.action) {
+                MotionEvent.ACTION_DOWN -> {
+                    startY = event.y
+                    startRecordAudio()
+                }
+                MotionEvent.ACTION_UP -> {
+//                    if (mCurPosY - startY > 0 && (abs(mCurPosY - startY) > 100)) {
+//                        XLog.debug("audioButtonDown() 下滑 ")
+//                    } else if (mCurPosY - startY < 0 && (abs(mCurPosY - startY) > 100)) {
+//                        XLog.debug("audioButtonDown() 上滑 ")
+//                    }else {
+//                        XLog.debug("audioButtonDown() 距离不够 ")
+//                    }
+                    if (mCurPosY - startY < 0 && (abs(mCurPosY - startY) > 100)) {
+                        cancelRecordAudio()
+                    } else {
+                        endRecordAudio()
+                    }
+                }
+                MotionEvent.ACTION_MOVE -> {
+                    mCurPosY = event.y
+                }
+            }
+            return true
+
+        }
+        return false
     }
 
     override fun conversationInfo(info: IMConversationInfo) {
@@ -143,7 +256,7 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
                     title = person.substring(0, person.indexOf("@"))
                 }
             }
-        }else if(O2IM.conversation_type_group == conversationInfo?.type) {
+        } else if (O2IM.conversation_type_group == conversationInfo?.type) {
             title = conversationInfo?.title ?: defaultTitle
         }
         updateToolbarTitle(title)
@@ -155,7 +268,7 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
     }
 
     override fun backPageMessages(list: List<IMMessage>) {
-        if(list.isNotEmpty()) {
+        if (list.isNotEmpty()) {
             page++
             adapter.addPageMessage(list)
         }
@@ -175,6 +288,25 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
         adapter.sendMessageFail(id)
     }
 
+    override fun localFile(filePath: String, msgType: String, position: Int) {
+        XLog.debug("local file :$filePath type:$msgType")
+        when (msgType) {
+            MessageType.audio.key -> {
+                playAudio2(filePath, position)
+            }
+            MessageType.image.key -> {
+                //打开大图
+                go<LocalImageViewActivity>(LocalImageViewActivity.startBundle(filePath))
+            }
+            else -> AndroidUtils.openFileWithDefaultApp(this@O2ChatActivity, File(filePath))
+        }
+
+    }
+
+    override fun downloadFileFail(msg: String) {
+        XToast.toastShort(this, msg)
+    }
+
     /**
      * 监听
      */
@@ -190,7 +322,7 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
                 if (s != null && !TextUtils.isEmpty(s)) {
                     btn_o2_chat_send.visible()
                     btn_o2_chat_emotion.gone()
-                }else {
+                } else {
                     btn_o2_chat_emotion.visible()
                     btn_o2_chat_send.gone()
                 }
@@ -199,38 +331,44 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
         et_o2_chat_input.setOnClickListener {
             rv_o2_chat_emoji_box_out.postDelayed({
                 rv_o2_chat_emoji_box.gone()
+                tv_o2_chat_audio_send_box.gone()
                 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
             }, 250)
         }
         rv_o2_chat_emoji_box_out.setKeyboardListener { isActive, keyboardHeight ->
             if (isActive) { // 输入法打开
-                if (mKeyboardHeight != keyboardHeight) { // 键盘发生改变时才设置emojiView的高度,因为会触发onGlobalLayoutChanged,导致onKeyboardStateChanged再次被调用
-                    mKeyboardHeight = keyboardHeight
-                    initEmojiView() // 每次输入法弹起时,设置emojiView的高度为键盘的高度,以便下次emojiView弹出时刚好等于键盘高度
-                }
+//                if (mKeyboardHeight != keyboardHeight) { // 键盘发生改变时才设置emojiView的高度,因为会触发onGlobalLayoutChanged,导致onKeyboardStateChanged再次被调用
+//                    mKeyboardHeight = keyboardHeight
+//                    initEmojiView() // 每次输入法弹起时,设置emojiView的高度为键盘的高度,以便下次emojiView弹出时刚好等于键盘高度
+//                }
                 if (rv_o2_chat_emoji_box.visibility == View.VISIBLE) { // 表情打开状态下
                     rv_o2_chat_emoji_box.gone()
                 }
+                if (tv_o2_chat_audio_send_box.visibility == View.VISIBLE) { // 表情打开状态下
+                    tv_o2_chat_audio_send_box.gone()
+                }
             }
         }
         btn_o2_chat_emotion.setOnClickListener {
+            //关闭语音框
+            tv_o2_chat_audio_send_box.gone()
             if (rv_o2_chat_emoji_box_out.isKeyboardActive) { //输入法激活时
-                if(rv_o2_chat_emoji_box.visibility == View.GONE) {
+                if (rv_o2_chat_emoji_box.visibility == View.GONE) {
                     window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) //  不改变布局,隐藏键盘,emojiView弹出
-                    val imm =  it.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+                    val imm = it.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                     imm.hideSoftInputFromWindow(et_o2_chat_input.applicationWindowToken, 0)
                     rv_o2_chat_emoji_box.visibility = View.VISIBLE
-                }else {
+                } else {
                     rv_o2_chat_emoji_box.visibility = View.GONE
-                    val imm =  it.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+                    val imm = it.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                     imm.hideSoftInputFromWindow(et_o2_chat_input.applicationWindowToken, 0)
                     window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
                 }
-            }else {
+            } else {
                 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
-                if(rv_o2_chat_emoji_box.visibility == View.GONE) {
+                if (rv_o2_chat_emoji_box.visibility == View.GONE) {
                     rv_o2_chat_emoji_box.visibility = View.VISIBLE
-                }else {
+                } else {
                     rv_o2_chat_emoji_box.visibility = View.GONE
                 }
             }
@@ -239,21 +377,177 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
         btn_o2_chat_send.setOnClickListener {
             sendTextMessage()
         }
+
+        //bottom toolbar
+        image_o2_chat_audio_speak_btn.setOnTouchListener(this)
+        ll_o2_chat_audio_btn.setOnClickListener {
+            //关闭表情框
+            rv_o2_chat_emoji_box.gone()
+            if (rv_o2_chat_emoji_box_out.isKeyboardActive) { //输入法激活时
+                if (tv_o2_chat_audio_send_box.visibility == View.GONE) {
+                    window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) //  不改变布局,隐藏键盘,emojiView弹出
+                    val imm = it.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+                    imm.hideSoftInputFromWindow(et_o2_chat_input.applicationWindowToken, 0)
+                    tv_o2_chat_audio_send_box.visibility = View.VISIBLE
+                } else {
+                    tv_o2_chat_audio_send_box.visibility = View.GONE
+                    val imm = it.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+                    imm.hideSoftInputFromWindow(et_o2_chat_input.applicationWindowToken, 0)
+                    window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
+                }
+            } else {
+                if (tv_o2_chat_audio_send_box.visibility == View.GONE) {
+                    tv_o2_chat_audio_send_box.visibility = View.VISIBLE
+                } else {
+                    tv_o2_chat_audio_send_box.visibility = View.GONE
+                }
+            }
+        }
+        ll_o2_chat_album_btn.setOnClickListener {
+            PicturePicker()
+                    .withActivity(this)
+                    .chooseType(PicturePicker.CHOOSE_TYPE_SINGLE).forResult { files ->
+                        if (files.isNotEmpty()) {
+                            newImageMessage(files[0])
+                        }
+                    }
+        }
+        ll_o2_chat_camera_btn.setOnClickListener {
+            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
+            //return-data false 不是直接返回拍照后的照片Bitmap 因为照片太大会传输失败
+            intent.putExtra("return-data", false)
+            //改用Uri 传递
+            intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraImageUri)
+            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString())
+            intent.putExtra("noFaceDetection", true)
+            startActivityForResult(intent, camera_result_code)
+        }
+        ll_o2_chat_location_btn.setOnClickListener {
+            ActivityResult.of(this)
+                    .className(O2LocationActivity::class.java)
+                    .params(O2LocationActivity.startChooseLocation())
+                    .greenChannel()
+                    .forResult { resultCode, data ->
+                        if (resultCode == Activity.RESULT_OK) {
+                            val location = data.extras.getParcelable<O2LocationActivity.LocationData>(O2LocationActivity.RESULT_LOCATION_KEY)
+                            if (location != null) {
+                                newLocationMessage(location)
+                            }
+                        }
+                    }
+        }
     }
     // 设置表情栏的高度
-    private fun initEmojiView() {
-        val layoutParams = rv_o2_chat_emoji_box.layoutParams
-        layoutParams.height = mKeyboardHeight
-        rv_o2_chat_emoji_box.layoutParams = layoutParams
+//    private fun initEmojiView() {
+//        val layoutParams = rv_o2_chat_emoji_box.layoutParams
+//        layoutParams.height = mKeyboardHeight
+//        rv_o2_chat_emoji_box.layoutParams = layoutParams
+//    }
+
+    /**
+     * 初始化录音相关对象
+     */
+    private fun initAudioRecord() {
+        RecordManager.getInstance().changeFormat(RecordConfig.RecordFormat.MP3)
+        RecordManager.getInstance().changeRecordConfig(RecordManager.getInstance().recordConfig.setSampleRate(16000))
+        RecordManager.getInstance().changeRecordConfig(RecordManager.getInstance().recordConfig.setEncodingConfig(AudioFormat.ENCODING_PCM_8BIT))
+        RecordManager.getInstance().changeRecordDir(FileExtensionHelper.getXBPMTempFolder() + File.separator)
+        RecordManager.getInstance().setRecordStateListener(object : RecordStateListener {
+            override fun onError(error: String?) {
+                XLog.error("录音错误, $error")
+            }
+
+            override fun onStateChange(state: RecordHelper.RecordState?) {
+                when (state) {
+                    RecordHelper.RecordState.IDLE -> XLog.debug("录音状态, 空闲状态")
+                    RecordHelper.RecordState.RECORDING -> {
+                        XLog.debug("录音状态, 录音中")
+                        audioCountDownTimer.start()
+                    }
+                    RecordHelper.RecordState.PAUSE -> XLog.debug("录音状态, 暂停中")
+                    RecordHelper.RecordState.STOP -> XLog.debug("录音状态, 正在停止")
+                    RecordHelper.RecordState.FINISH -> XLog.debug("录音状态, 录音流程结束(转换结束)")
+                }
+
+            }
+        })
+        RecordManager.getInstance().setRecordResultListener { result ->
+            if (result == null) {
+                runOnUiThread { XToast.toastShort(this@O2ChatActivity, "录音失败!") }
+            } else {
+                XLog.debug("录音结束 返回结果 ${result.path} , 是否取消:$isAudioRecordCancel, 录音时间:$audioRecordTime")
+                if (audioRecordTime < 1) {
+                    runOnUiThread {
+                        XToast.toastShort(this@O2ChatActivity, "录音时间太短!")
+                    }
+                } else {
+                    newAudioMessage(result.path, "$audioRecordTime")
+                }
+            }
+        }
+    }
+
+    /**
+     * 开始录音
+     */
+    private fun startRecordAudio() {
+        XLog.debug("开始录音。。。。")
+        audioRecordTime = 0L
+        RecordManager.getInstance().start()
+        tv_o2_chat_audio_speak_title.text = resources.getText(R.string.activity_im_audio_speak_cancel)
+    }
+
+    /**
+     * 结束录音
+     */
+    private fun endRecordAudio() {
+        XLog.debug("结束录音。。。。")
+        audioCountDownTimer.cancel()
+        RecordManager.getInstance().stop()
+        tv_o2_chat_audio_speak_title.text = resources.getText(R.string.activity_im_audio_speak)
+        tv_o2_chat_audio_speak_duration.text = ""
+    }
+
+    /**
+     * 取消录音
+     */
+    private fun cancelRecordAudio() {
+        XLog.debug("取消录音。。。。。")
+        isAudioRecordCancel = true
+        audioCountDownTimer.cancel()
+        RecordManager.getInstance().stop()
+        tv_o2_chat_audio_speak_title.text = resources.getText(R.string.activity_im_audio_speak)
+        tv_o2_chat_audio_speak_duration.text = ""
     }
 
+    private fun playAudio2(filePath: String, position: Int) {
+        if (mPlayer != null) {
+            mPlayer?.release()
+            mPlayer = null
+        }
+        XLog.debug("uri : $filePath")
+        val uri = Uri.fromFile(File(filePath))
+        mPlayer = MediaPlayer.create(this@O2ChatActivity, uri)
+        mPlayer?.setOnCompletionListener {
+            XLog.debug("播音结束!")
+
+        }
+        mPlayer?.start()
+    }
 
+
+    /**
+     * 获取消息数据
+     */
     private fun getPageData() {
         mPresenter.getMessage(page + 1, conversationId)
         //更新阅读时间
         mPresenter.readConversation(conversationId)
     }
 
+    /**
+     * 滚动消息到底部
+     */
     private fun scroll2Bottom() {
         rv_o2_chat_messages.scrollToPosition(adapter.lastPosition())
     }
@@ -276,14 +570,14 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
      */
     private fun newTextMessage(text: String) {
         val time = DateHelper.now()
-        val body = IMMessageBody.Text(text)
+        val body = IMMessageBody(type = MessageType.text.key, body = text)
         val bodyJson = O2SDKManager.instance().gson.toJson(body)
         XLog.debug("body: $bodyJson")
         val uuid = UUID.randomUUID().toString()
         val message = IMMessage(uuid, conversationId, bodyJson,
                 O2SDKManager.instance().distinguishedName, time, 1)
         adapter.addMessage(message)
-        mPresenter.sendTextMessage(message)//发送到服务器
+        mPresenter.sendIMMessage(message)//发送到服务器
         scroll2Bottom()
     }
 
@@ -292,14 +586,65 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
      */
     private fun newEmojiMessage(emoji: String) {
         val time = DateHelper.now()
-        val body = IMMessageBody.Emoji(emoji)
+        val body = IMMessageBody(type = MessageType.emoji.key, body = emoji)
+        val bodyJson = O2SDKManager.instance().gson.toJson(body)
+        XLog.debug("body: $bodyJson")
+        val uuid = UUID.randomUUID().toString()
+        val message = IMMessage(uuid, conversationId, bodyJson,
+                O2SDKManager.instance().distinguishedName, time, 1)
+        adapter.addMessage(message)
+        mPresenter.sendIMMessage(message)//发送到服务器
+        scroll2Bottom()
+    }
+
+    /**
+     * 文件消息创建 并发送
+     */
+    private fun newAudioMessage(filePath: String, duration: String) {
+        val time = DateHelper.now()
+        val body = IMMessageBody(type = MessageType.audio.key, body = MessageBody.audio.body,
+                fileTempPath = filePath, audioDuration = duration)
+        val bodyJson = O2SDKManager.instance().gson.toJson(body)
+        XLog.debug("body: $bodyJson")
+        val uuid = UUID.randomUUID().toString()
+        val message = IMMessage(uuid, conversationId, bodyJson,
+                O2SDKManager.instance().distinguishedName, time, 1)
+        adapter.addMessage(message)
+        mPresenter.sendIMMessage(message)//发送到服务器
+        scroll2Bottom()
+    }
+
+    /**
+     * 图片消息 创建 并发送
+     */
+    private fun newImageMessage(filePath: String) {
+        val time = DateHelper.now()
+        val body = IMMessageBody(type = MessageType.image.key, body = MessageBody.image.body, fileTempPath = filePath)
+        val bodyJson = O2SDKManager.instance().gson.toJson(body)
+        XLog.debug("body: $bodyJson")
+        val uuid = UUID.randomUUID().toString()
+        val message = IMMessage(uuid, conversationId, bodyJson,
+                O2SDKManager.instance().distinguishedName, time, 1)
+        adapter.addMessage(message)
+        mPresenter.sendIMMessage(message)//发送到服务器
+        scroll2Bottom()
+    }
+
+    /**
+     * 位置消息 创建并发送
+     */
+    private fun newLocationMessage(location: O2LocationActivity.LocationData) {
+        val time = DateHelper.now()
+        val body = IMMessageBody(type = MessageType.location.key, body = MessageBody.location.body,
+                address = location.address, addressDetail = location.addressDetail,
+                latitude = location.latitude, longitude = location.longitude)
         val bodyJson = O2SDKManager.instance().gson.toJson(body)
         XLog.debug("body: $bodyJson")
         val uuid = UUID.randomUUID().toString()
         val message = IMMessage(uuid, conversationId, bodyJson,
                 O2SDKManager.instance().distinguishedName, time, 1)
         adapter.addMessage(message)
-        mPresenter.sendTextMessage(message)//发送到服务器
+        mPresenter.sendIMMessage(message)//发送到服务器
         scroll2Bottom()
     }
 

+ 5 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatContract.kt

@@ -4,6 +4,7 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenter
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseView
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMConversationInfo
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessage
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageBody
 
 object O2ChatContract  {
 
@@ -13,11 +14,14 @@ object O2ChatContract  {
         fun sendFail(id: String)
         fun conversationInfo(info: IMConversationInfo)
         fun conversationGetFail()
+        fun localFile(filePath: String, msgType: String, position: Int)
+        fun downloadFileFail(msg: String)
     }
     interface Presenter: BasePresenter<View> {
-        fun sendTextMessage(msg: IMMessage)
+        fun sendIMMessage(msg: IMMessage)
         fun getMessage(page: Int, conversationId: String)
         fun readConversation(conversationId: String)
         fun getConversation(id: String)
+        fun getFileFromNetOrLocal(position: Int, body: IMMessageBody)
     }
 }

+ 94 - 19
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatMessageAdapter.kt

@@ -1,24 +1,25 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.im
 
 import android.support.v7.widget.RecyclerView
+import android.text.TextUtils
 import android.view.LayoutInflater
 import android.view.ViewGroup
 import android.view.animation.Animation
 import android.view.animation.AnimationUtils
-import android.widget.ImageButton
-import android.widget.ImageView
-import android.widget.TextView
+import android.widget.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecyclerViewHolder
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessage
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageBody
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.MessageType
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.DateHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.gone
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.visible
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.imageloader.O2ImageLoaderManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.CircleImageView
+import retrofit2.http.POST
 
 
 class O2ChatMessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
@@ -120,23 +121,16 @@ class O2ChatMessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
                     time = DateHelper.imChatMessageTime(message.createTime)
                 }
             }
+            holder.setText(R.id.tv_o2_chat_message_person_name, name)
+                    .setText(R.id.tv_o2_chat_message_time, time)
+
             if (messageBody != null) {
-                if (messageBody is IMMessageBody.Text) {
-                    val textBody = holder.getView<TextView>(R.id.tv_o2_chat_message_body)
-                    textBody.text = messageBody.body
-                    textBody.visible()
-                    val imgBody = holder.getView<ImageView>(R.id.image_o2_chat_message_emoji_body)
-                    imgBody.gone()
-                    holder.setText(R.id.tv_o2_chat_message_person_name, name)
-                            .setText(R.id.tv_o2_chat_message_time, time)
-                }else if (messageBody is IMMessageBody.Emoji) {
-                    val textBody = holder.getView<TextView>(R.id.tv_o2_chat_message_body)
-                    textBody.gone()
-                    val imgBody = holder.getView<ImageView>(R.id.image_o2_chat_message_emoji_body)
-                    imgBody.setImageResource(O2IM.emojiResId(messageBody.body))
-                    imgBody.visible()
-                    holder.setText(R.id.tv_o2_chat_message_person_name, name)
-                            .setText(R.id.tv_o2_chat_message_time, time)
+                when(messageBody.type) {
+                    MessageType.text.key -> renderTextMessage(messageBody, holder)
+                    MessageType.emoji.key -> renderEmojiMessage(messageBody, holder)
+                    MessageType.image.key -> renderImageMessage(messageBody, holder, position)
+                    MessageType.audio.key -> renderAudioMessage(messageBody, holder, position)
+                    MessageType.location.key -> renderLocationMessage(messageBody, holder)
                 }
             }
 
@@ -163,9 +157,90 @@ class O2ChatMessageAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
         }
     }
 
+    private fun renderTextMessage(msgBody: IMMessageBody, holder: CommonRecyclerViewHolder) {
+        val textMessageView = holder.getView<TextView>(R.id.tv_o2_chat_message_body)
+        textMessageView.visible()
+        textMessageView.text = msgBody.body
+        val emojiMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_emoji_body)
+        emojiMessageView.gone()
+        val imageMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_image_body)
+        imageMessageView.gone()
+        val audioMessageView = holder.getView<LinearLayout>(R.id.ll_o2_chat_message_audio_body)
+        audioMessageView.gone()
+        val locationMessageView = holder.getView<RelativeLayout>(R.id.rl_o2_chat_message_location_body)
+        locationMessageView.gone()
+    }
+    private fun renderEmojiMessage(msgBody: IMMessageBody, holder: CommonRecyclerViewHolder) {
+        val textMessageView = holder.getView<TextView>(R.id.tv_o2_chat_message_body)
+        textMessageView.gone()
+        val emojiMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_emoji_body)
+        if (msgBody.body  != null) {
+            emojiMessageView.setImageResource(O2IM.emojiResId(msgBody.body!!))
+        }
+        emojiMessageView.visible()
+        val imageMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_image_body)
+        imageMessageView.gone()
+        val audioMessageView = holder.getView<LinearLayout>(R.id.ll_o2_chat_message_audio_body)
+        audioMessageView.gone()
+        val locationMessageView = holder.getView<RelativeLayout>(R.id.rl_o2_chat_message_location_body)
+        locationMessageView.gone()
+    }
+    private fun renderImageMessage(msgBody: IMMessageBody, holder: CommonRecyclerViewHolder,  position: Int) {
+        val textMessageView = holder.getView<TextView>(R.id.tv_o2_chat_message_body)
+        textMessageView.gone()
+        val emojiMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_emoji_body)
+        emojiMessageView.gone()
+        val imageMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_image_body)
+        if (!TextUtils.isEmpty(msgBody.fileId)) {
+            val url = APIAddressHelper.instance().getImImageDownloadUrlWithWH(msgBody.fileId!!, 144, 192)
+            O2ImageLoaderManager.instance().showImage(imageMessageView, url)
+        }else if (!TextUtils.isEmpty(msgBody.fileTempPath)) {
+            O2ImageLoaderManager.instance().showImage(imageMessageView, msgBody.fileTempPath!!)
+        }
+        imageMessageView.visible()
+        imageMessageView.setOnClickListener { eventListener?.openOriginImage(position, msgBody) }
+        val audioMessageView = holder.getView<LinearLayout>(R.id.ll_o2_chat_message_audio_body)
+        audioMessageView.gone()
+        val locationMessageView = holder.getView<RelativeLayout>(R.id.rl_o2_chat_message_location_body)
+        locationMessageView.gone()
+    }
+    private fun renderAudioMessage(msgBody: IMMessageBody, holder: CommonRecyclerViewHolder, position: Int) {
+        val textMessageView = holder.getView<TextView>(R.id.tv_o2_chat_message_body)
+        textMessageView.gone()
+        val emojiMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_emoji_body)
+        emojiMessageView.gone()
+        val imageMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_image_body)
+        imageMessageView.gone()
+        val audioMessageView = holder.getView<LinearLayout>(R.id.ll_o2_chat_message_audio_body)
+        val durationTv = holder.getView<TextView>(R.id.tv_o2_chat_message_audio_duration)
+        durationTv.text = "${msgBody.audioDuration}\""
+        audioMessageView.visible()
+        audioMessageView.setOnClickListener { eventListener?.playAudio(position, msgBody) }
+        val locationMessageView = holder.getView<RelativeLayout>(R.id.rl_o2_chat_message_location_body)
+        locationMessageView.gone()
+    }
+    private fun renderLocationMessage(msgBody: IMMessageBody, holder: CommonRecyclerViewHolder) {
+        val textMessageView = holder.getView<TextView>(R.id.tv_o2_chat_message_body)
+        textMessageView.gone()
+        val emojiMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_emoji_body)
+        emojiMessageView.gone()
+        val imageMessageView = holder.getView<ImageView>(R.id.image_o2_chat_message_image_body)
+        imageMessageView.gone()
+        val audioMessageView = holder.getView<LinearLayout>(R.id.ll_o2_chat_message_audio_body)
+        audioMessageView.gone()
+        val locationMessageView = holder.getView<RelativeLayout>(R.id.rl_o2_chat_message_location_body)
+        val addressTv = holder.getView<TextView>(R.id.tv_o2_chat_message_location_address)
+        addressTv.text = msgBody.address
+        locationMessageView.visible()
+        locationMessageView.setOnClickListener { eventListener?.openLocation(msgBody) }
+    }
+
 
     interface MessageEventListener {
         //重新发送消息
         fun resendClick(message: IMMessage)
+        fun playAudio(position: Int, msgBody: IMMessageBody)
+        fun openOriginImage(position: Int, msgBody: IMMessageBody)
+        fun openLocation(msgBody: IMMessageBody)
     }
 }

+ 97 - 15
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatPresenter.kt

@@ -1,14 +1,29 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.im
 
+import android.text.TextUtils
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessage
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageBody
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageForm
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.MessageType
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileUtil
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.O2FileDownloadHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
+import okhttp3.MediaType
+import okhttp3.MultipartBody
+import okhttp3.RequestBody
 import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
+import java.io.*
+import java.net.HttpURLConnection
+import java.net.URL
 
 class O2ChatPresenter : BasePresenterImpl<O2ChatContract.View>(), O2ChatContract.Presenter  {
 
@@ -32,22 +47,61 @@ class O2ChatPresenter : BasePresenterImpl<O2ChatContract.View>(), O2ChatContract
                 }
     }
 
-    override fun sendTextMessage(msg: IMMessage) {
+    override fun sendIMMessage(msg: IMMessage) {
         val service = getMessageCommunicateService(mView?.getContext())
-        service?.sendMessage(msg)?.subscribeOn(Schedulers.io())
-                ?.observeOn(AndroidSchedulers.mainThread())?.o2Subscribe {
-            onNext {
-                val id = it.data.id
-                if (id != null) {
-                    mView?.sendMessageSuccess(id)
-                }else {
-                    mView?.sendFail(msg.id)
-                }
-            }
-            onError { e, _ ->
-                XLog.error("", e)
-                mView?.sendFail(msg.id)
-            }
+        //audio 和 image 需要先上传文件 然后发送消息
+        val body = O2SDKManager.instance().gson.fromJson(msg.body, IMMessageBody::class.java)
+        if (body.type == MessageType.audio.key || body.type == MessageType.image.key) {
+            val file = File(body.fileTempPath)
+            val mediaType = FileUtil.getMIMEType(file)
+            val requestBody = RequestBody.create(MediaType.parse(mediaType), file)
+            val part = MultipartBody.Part.createFormData("file", file.name, requestBody)
+            service?.uploadFile(msg.conversationId, body.type!!, part)
+                    ?.subscribeOn(Schedulers.io())
+                    ?.flatMap { idData ->
+                        val id = idData.data.id
+                        val extension = idData.data.fileExtension
+                        if (!TextUtils.isEmpty(id)) {//消息体中添加fileId 并清楚暂存的本地地址fileTempPath
+                            body.fileId = id
+                            body.fileExtension = extension
+                            body.fileTempPath = null
+                            msg.body = O2SDKManager.instance().gson.toJson(body)
+                            service.sendMessage(msg)
+                        }else {
+                            throw Exception("上传附件失败")
+                        }
+                    }
+                    ?.observeOn(AndroidSchedulers.mainThread())
+                    ?.o2Subscribe {
+                        onNext {
+                            val id = it.data.id
+                            if (id != null) {
+                                mView?.sendMessageSuccess(id)
+                            }else {
+                                mView?.sendFail(msg.id)
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("", e)
+                            mView?.sendFail(msg.id)
+                        }
+                    }
+        }else {
+            service?.sendMessage(msg)?.subscribeOn(Schedulers.io())
+                    ?.observeOn(AndroidSchedulers.mainThread())?.o2Subscribe {
+                        onNext {
+                            val id = it.data.id
+                            if (id != null) {
+                                mView?.sendMessageSuccess(id)
+                            }else {
+                                mView?.sendFail(msg.id)
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("", e)
+                            mView?.sendFail(msg.id)
+                        }
+                    }
         }
     }
 
@@ -93,6 +147,34 @@ class O2ChatPresenter : BasePresenterImpl<O2ChatContract.View>(), O2ChatContract
                             XLog.error("read error", e)
                         }
                     }
+        }
+    }
+
+    override fun getFileFromNetOrLocal(position: Int, body: IMMessageBody) {
+        if (TextUtils.isEmpty(body.fileId) && !TextUtils.isEmpty(body.fileTempPath)) {
+            XLog.debug("本地文件。。。。。")
+            mView?.localFile(body.fileTempPath!!, body.type!!,  position)
+        }else if (!TextUtils.isEmpty(body.fileId)) {
+            val fileId = body.fileId!!
+            val path = FileExtensionHelper.getXBPMTempFolder()+ File.separator + fileId + "." +body.fileExtension
+            val downloadUrl = APIAddressHelper.instance().getImFileDownloadUrl(fileId)
+            O2FileDownloadHelper.download(downloadUrl, path)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            XLog.debug("返回下载地址:$it")
+                            mView?.localFile(path, body.type!!, position)
+                        }
+                        onError { e, _ ->
+                            XLog.error("", e)
+                            mView?.downloadFileFail("获取文件异常, ${e?.message}")
+                        }
+                    }
+
+
+
+
         }
     }
 }

+ 4 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2IM.kt

@@ -105,6 +105,10 @@ object O2IM {
         return im_emoji_hashMap[key] ?: R.mipmap.im_emotion_01
     }
 
+    enum class AudioPlayState {
+        playing,
+        idle
+    }
 
     //instant message type
 

+ 291 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2LocationActivity.kt

@@ -0,0 +1,291 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.im
+
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.support.v7.widget.Toolbar
+import android.view.Menu
+import android.view.MenuItem
+import android.widget.TextView
+import com.baidu.location.BDLocation
+import com.baidu.location.BDLocationListener
+import com.baidu.location.LocationClient
+import com.baidu.location.LocationClientOption
+import com.baidu.mapapi.map.*
+import com.baidu.mapapi.model.LatLng
+import com.baidu.mapapi.search.geocode.*
+import kotlinx.android.synthetic.main.activity_o2_location.*
+import kotlinx.android.synthetic.main.snippet_appbarlayout_toolbar.*
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XToast
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.visible
+import org.jetbrains.anko.doAsync
+
+class O2LocationActivity : AppCompatActivity(), BDLocationListener {
+
+
+    companion object{
+        const val RESULT_LOCATION_KEY = "RESULT_LOCATION_KEY"
+
+        const val mode_key = "mode_key"
+        const val location_data_key = "location_data_key"
+        /**
+         * 开始选择位置
+         */
+        fun startChooseLocation(): Bundle {
+            val bundle = Bundle()
+            bundle.putInt(mode_key, 0)
+            return bundle
+        }
+
+        /**
+         * 查看位置
+         */
+        fun showLocation(data: LocationData): Bundle {
+            val bundle = Bundle()
+            bundle.putInt(mode_key, 1)
+            bundle.putParcelable(location_data_key, data)
+            return bundle
+        }
+    }
+
+    private var mode = 0 //模式 0 选择位置 1查看位置
+    private var locationData: LocationData? = null
+
+    //百度地图
+    private var mBaiduMap: BaiduMap? = null
+    private val mLocationClient: LocationClient by lazy { LocationClient(this) }
+    private var marker: Marker? = null
+    private val geoCoder: GeoCoder by lazy { GeoCoder.newInstance() }
+
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_o2_location)
+
+        //数据初始化
+        mode = intent.getIntExtra(mode_key, 0)
+        locationData = intent.getParcelableExtra(location_data_key)
+        if (mode == 0) {
+            setupToolBar("点击地图选择位置")
+        }else {
+            if (locationData == null) {
+                XToast.toastShort(this, "传入参数错误!")
+                finish()
+            }
+            setupToolBar(locationData?.address ?: "位置")
+        }
+
+
+        //地图
+        mBaiduMap = map_baidu_o2_location.map
+        val builder = MapStatus.Builder()
+        builder.zoom(19.0f)
+        mBaiduMap?.setMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()))
+        mBaiduMap?.mapType = BaiduMap.MAP_TYPE_NORMAL
+        if (mode == 0) { //选择位置模式 需要加入点击功能
+            //点击地图 设置位置数据 画图钉
+            mBaiduMap?.setOnMapClickListener(object : BaiduMap.OnMapClickListener {
+                override fun onMapClick(latLng: LatLng?) {
+                    XLog.debug("onMapClick latitude:${latLng?.latitude}, longitude:${latLng?.longitude}")
+                    markerPoint(latLng, null)
+                    searchAddress(latLng)
+                }
+
+                override fun onMapPoiClick(poi: MapPoi?): Boolean {
+                    val latLng = poi?.position
+                    XLog.debug("onMapPoiClick latitude:${latLng?.latitude}, longitude:${latLng?.longitude}")
+                    markerPoint(latLng, null)
+                    searchAddress(latLng)
+                    return false
+                }
+            })
+            // 开启定位图层
+            mBaiduMap?.isMyLocationEnabled = true
+            mLocationClient.registerLocationListener(this)
+            initBaiduLocation()
+            mLocationClient.start()
+        }else { //查看模式 把位置图钉画上去
+            val lat = LatLng(locationData?.latitude!!, locationData?.longitude!!)
+            markerPoint(lat, locationData?.addressDetail)
+            val mapStatus: MapStatusUpdate = MapStatusUpdateFactory.newLatLng(lat)
+            mBaiduMap?.setMapStatus(mapStatus)
+        }
+
+    }
+
+    override fun onDestroy() {
+        geoCoder.destroy()
+        super.onDestroy()
+    }
+    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+        if (mode == 0) {
+            menuInflater.inflate(R.menu.menu_location_send, menu)
+        }
+        return super.onCreateOptionsMenu(menu)
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+        when(item?.itemId) {
+            R.id.location_send -> {
+                if (locationData == null){
+                    XToast.toastShort(this, "请先选择一个位置!")
+                }else {
+                    intent.putExtra(RESULT_LOCATION_KEY, locationData)
+                    setResult(RESULT_OK, intent)
+                    finish()
+                }
+                return true
+            }
+        }
+        return super.onOptionsItemSelected(item)
+    }
+
+
+    override fun onReceiveLocation(location: BDLocation?) {
+        XLog.debug("onReceive locType:${location?.locType}, latitude:${location?.latitude}, longitude:${location?.longitude}")
+        if (location != null) {
+            doAsync {
+                // 构造定位数据
+                val locData = MyLocationData.Builder()
+                        .accuracy(location.radius)
+                        // 此处设置开发者获取到的方向信息,顺时针0-360
+                        .direction(location.direction)
+                        .latitude(location.latitude)
+                        .longitude(location.longitude).build()
+                // 设置定位数据
+                mBaiduMap?.setMyLocationData(locData)
+                // 设置定位图层的配置(定位模式,是否允许方向信息,用户自定义定位图标)
+                val bit: BitmapDescriptor = BitmapDescriptorFactory
+                        .fromResource(R.mipmap.task_red_point)
+                val config = MyLocationConfiguration(MyLocationConfiguration.LocationMode.FOLLOWING, true, bit)
+                mBaiduMap?.setMyLocationConfiguration(config)
+                //定位成功后关闭
+                mLocationClient.stop()
+            }
+
+
+        }
+    }
+
+    override fun onConnectHotSpotMessage(p0: String?, p1: Int) {
+        XLog.debug("onConnectHotSpotMessage, p0:$p0, p1:$p1")
+    }
+
+    private fun setupToolBar(title:String = "") {
+        toolbar_snippet_top_bar.title = ""
+        setSupportActionBar(toolbar_snippet_top_bar)
+        toolbar_snippet_top_bar.setNavigationIcon(R.mipmap.ic_back_mtrl_white_alpha)
+        toolbar_snippet_top_bar.setNavigationOnClickListener {
+            XLog.debug("点了 关闭了。。。。。。。")
+            finish()
+        }
+
+        tv_snippet_top_title.text = title
+    }
+
+
+    /**
+     * 标记位置到地图上
+     */
+    private fun markerPoint(latLng: LatLng?, address: String?) {
+        if (latLng==null) {
+            XLog.error("坐标为空")
+            return
+        }
+        if (marker == null) {
+            //构建Marker图标
+            val bitmap = BitmapDescriptorFactory
+                    .fromResource(R.mipmap.icon_map_location)
+            val options = MarkerOptions()
+                    .position(latLng)  //设置marker的位置
+                    .title(address ?: "")
+                    .icon(bitmap)  //设置marker图标
+                    .zIndex(9)
+            //将marker添加到地图上
+            marker = mBaiduMap?.addOverlay(options) as Marker
+        }else {
+            marker?.position = latLng
+        }
+    }
+
+    /**
+     * 根据经纬度查询地址信息
+     */
+    private fun searchAddress(latLng: LatLng?) {
+        //搜索地址信息
+        geoCoder.setOnGetGeoCodeResultListener(object : OnGetGeoCoderResultListener {
+            override fun onGetGeoCodeResult(p0: GeoCodeResult?) {
+            }
+
+            override fun onGetReverseGeoCodeResult(p0: ReverseGeoCodeResult?) {
+                if(locationData == null) {
+                    locationData = LocationData()
+                }
+                locationData?.address = p0?.address
+                locationData?.addressDetail = p0?.sematicDescription
+                locationData?.latitude = p0?.location?.latitude
+                locationData?.longitude = p0?.location?.longitude
+                runOnUiThread {
+                    tv_o2_location_address.text = p0?.address
+                    tv_o2_location_address.visible()
+                }
+            }
+        })
+        geoCoder.reverseGeoCode(ReverseGeoCodeOption().location(latLng))
+    }
+
+    private fun initBaiduLocation() {
+        val option = LocationClientOption()
+        option.locationMode = LocationClientOption.LocationMode.Hight_Accuracy//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
+        option.setCoorType("bd09ll")//百度坐标系 可选,默认gcj02,设置返回的定位结果坐标系
+        option.setScanSpan(5000)//5秒一次定位 可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
+        option.setIsNeedAddress(true)//可选,设置是否需要地址信息,默认不需要
+        option.isOpenGps = true//可选,默认false,设置是否使用gps
+        option.isLocationNotify = true//可选,默认false,设置是否当GPS有效时按照1S/1次频率输出GPS结果
+        option.setIsNeedLocationDescribe(true)//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
+        option.setIsNeedLocationPoiList(true)//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
+        option.setIgnoreKillProcess(false)//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
+        option.SetIgnoreCacheException(false)//可选,默认false,设置是否收集CRASH信息,默认收集
+        option.setEnableSimulateGps(false)//可选,默认false,设置是否需要过滤GPS仿真结果,默认需要
+        mLocationClient.locOption = option
+    }
+
+
+    /**
+     * 地址数据对象
+     */
+    class LocationData(
+            var address: String? = null, //type=location的时候位置信息
+            var addressDetail: String? = null,
+            var latitude: Double? = null,//type=location的时候位置信息
+            var longitude: Double? = null//type=location的时候位置信息
+    ) : Parcelable {
+        constructor(source: Parcel) : this(
+                source.readString(),
+                source.readString(),
+                source.readValue(Double::class.java.classLoader) as Double?,
+                source.readValue(Double::class.java.classLoader) as Double?
+        )
+
+        override fun describeContents() = 0
+
+        override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
+            writeString(address)
+            writeString(addressDetail)
+            writeValue(latitude)
+            writeValue(longitude)
+        }
+
+        companion object {
+            @JvmField
+            val CREATOR: Parcelable.Creator<LocationData> = object : Parcelable.Creator<LocationData> {
+                override fun createFromParcel(source: Parcel): LocationData = LocationData(source)
+                override fun newArray(size: Int): Array<LocationData?> = arrayOfNulls(size)
+            }
+        }
+    }
+}
+

+ 46 - 5
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/fm/O2IMConversationFragment.kt

@@ -14,6 +14,7 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPViewPagerFragment
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.im.O2ChatActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.im.O2IM
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.im.O2InstantMessageActivity
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.main.MainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.organization.ContactPickerActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecycleViewAdapter
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecyclerViewHolder
@@ -22,6 +23,7 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.InstantMessage
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMConversationInfo
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessage
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageBody
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.MessageType
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.vo.ContactPickerResult
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.DateHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
@@ -54,6 +56,9 @@ class O2IMConversationFragment : BaseMVPViewPagerFragment<O2IMConversationContra
                             val name = person.substring(0, person.indexOf("@"))
                             holder.setText(R.id.tv_o2_im_con_title, name)
                         }
+                    }else if(O2IM.conversation_type_group == t.type) {
+                        holder.setText(R.id.tv_o2_im_con_title, t.title )
+                                .setImageViewResource(R.id.image_o2_im_con_avatar, R.mipmap.group_default)
                     }
                     val unread = holder.getView<TextView>(R.id.tv_o2_im_con_unread_number)
                     if (t.unreadNumber > 0) {
@@ -66,15 +71,15 @@ class O2IMConversationFragment : BaseMVPViewPagerFragment<O2IMConversationContra
                     if (lastMessage != null) {
                         val lastTime = DateHelper.convertStringToDate(lastMessage.createTime)
                         val lastMessageBody = lastMessage.messageBody()
-                        when(lastMessageBody) {
-                            is IMMessageBody.Emoji -> {
+                        when(lastMessageBody?.type) {
+                            MessageType.emoji.key -> {
                                 val image = holder.getView<ImageView>(R.id.tv_o2_im_con_last_message_emoji)
-                                image.setImageResource(O2IM.emojiResId(lastMessageBody.body))
+                                image.setImageResource(O2IM.emojiResId(lastMessageBody.body!!))
                                 image.visible()
                                 val text = holder.getView<TextView>(R.id.tv_o2_im_con_last_message)
                                 text.gone()
                             }
-                            is IMMessageBody.Text -> {
+                            MessageType.text.key -> {
                                 val image = holder.getView<ImageView>(R.id.tv_o2_im_con_last_message_emoji)
                                 image.gone()
                                 val text = holder.getView<TextView>(R.id.tv_o2_im_con_last_message)
@@ -85,10 +90,11 @@ class O2IMConversationFragment : BaseMVPViewPagerFragment<O2IMConversationContra
                                 val image = holder.getView<ImageView>(R.id.tv_o2_im_con_last_message_emoji)
                                 image.gone()
                                 val text = holder.getView<TextView>(R.id.tv_o2_im_con_last_message)
-                                text.text = ""
+                                text.text = lastMessageBody?.body
                                 text.visible()
                             }
                         }
+
                         holder.setText(R.id.tv_o2_im_con_last_message_time, DateHelper.friendlyTime(lastTime))
 
                     }
@@ -127,6 +133,10 @@ class O2IMConversationFragment : BaseMVPViewPagerFragment<O2IMConversationContra
                 openCreateSingleConversation()
                 return true
             }
+            R.id.menu_tribe_create -> {
+                openCreateTribeConversation()
+                return true
+            }
         }
         return super.onOptionsItemSelected(item)
     }
@@ -135,16 +145,24 @@ class O2IMConversationFragment : BaseMVPViewPagerFragment<O2IMConversationContra
         if (list.isEmpty()) {
             tv_null_conversation.visible()
             ll_o2_im_message_list.gone()
+            setUnreadNumber(0)
         } else {
             tv_null_conversation.gone()
             ll_o2_im_message_list.visible()
             cList.clear()
             cList.addAll(list)
             adapter.notifyDataSetChanged()
+            var allnumbers = 0
+            list.forEach { con ->
+                val number = con.unreadNumber ?: 0
+                allnumbers += number
+            }
+            setUnreadNumber(allnumbers)
         }
         mPresenter.getMyInstantMessageList()
     }
 
+
     override fun myInstantMessageList(instantList: List<InstantMessage>) {
          if (instantList.isNotEmpty()) {
              this.instantList.clear()
@@ -183,6 +201,13 @@ class O2IMConversationFragment : BaseMVPViewPagerFragment<O2IMConversationContra
         }
     }
 
+
+    private fun setUnreadNumber(number: Int) {
+        if (activity is MainActivity) {
+            (activity as MainActivity).refreshUnreadNumber(number)
+        }
+    }
+
     private fun openCreateSingleConversation() {
         ActivityResult.of(activity)
                 .className(ContactPickerActivity::class.java)
@@ -200,4 +225,20 @@ class O2IMConversationFragment : BaseMVPViewPagerFragment<O2IMConversationContra
     private fun createSingleConversation(user: String) {
         mPresenter.createConversation("single", arrayListOf(user))
     }
+
+    private fun openCreateTribeConversation() {
+        ActivityResult.of(activity)
+                .className(ContactPickerActivity::class.java)
+                .params(ContactPickerActivity.startPickerBundle(pickerModes = arrayListOf(ContactPickerActivity.personPicker), multiple = true))
+                .greenChannel().forResult { _, data ->
+                    val result = data?.getParcelableExtra<ContactPickerResult>(ContactPickerActivity.CONTACT_PICKED_RESULT)
+                    if (result != null && result.users.isNotEmpty()) {
+                        val a = arrayListOf<String>()
+                        a.addAll(result.users.map { it.distinguishedName })
+                        mPresenter.createConversation("group",  a)
+                    }else {
+                        XLog.debug("没有选择人员!!!!")
+                    }
+                }
+    }
 }

+ 0 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/meeting/invited/MeetingDetailInfoActivity.kt

@@ -79,7 +79,6 @@ class MeetingDetailInfoActivity : BaseMVPActivity<MeetingDetailInfoContract.View
     override fun downloadAttachmentSuccess(file: File?) {
         hideLoadingDialog()
         XLog.debug(file?.name)
-        XToast.toastShort(this,"下载成功")
         if (file != null && file.exists()) AndroidUtils.openFileWithDefaultApp(this, file)
     }
 

+ 16 - 73
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/meeting/invited/MeetingDetailInfoPresenter.kt

@@ -3,12 +3,16 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.meeting.invited
 import android.widget.TextView
 import net.muliba.accounting.app.ExceptionHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.APIDistributeTypeEnum
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.meeting.MeetingFileInfoJson
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.O2FileDownloadHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.SDCardHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import org.jetbrains.anko.doAsync
 import org.jetbrains.anko.uiThread
 import rx.android.schedulers.AndroidSchedulers
@@ -26,81 +30,20 @@ class MeetingDetailInfoPresenter : BasePresenterImpl<MeetingDetailInfoContract.V
 
     override fun downloadMeetingFile(meetingFileInfoJson: MeetingFileInfoJson) {
         val path = FileExtensionHelper.getXBPMMEETINGAttachmentFileByName(meetingFileInfoJson.name)
-        doAsync {
-            try {
-                val file = File(path)
-                if (!file.exists()) {
-                    val call = RetrofitClient.instance().meetingAssembleControlApi()
-                            .downloadMeetingFile(meetingFileInfoJson.id)
-                    SDCardHelper.generateNewFile(path)
-                    val responseBody = call.execute()
-                    val headerDisposition = responseBody.headers().get("Content-Disposition")
-                    XLog.debug("header disposition: $headerDisposition")
-                    val dataInput = DataInputStream(responseBody.body()?.byteStream())
-                    val fileOut = DataOutputStream(FileOutputStream(file))
-                    val buffer = ByteArray(4096)
-                    var count = 0
-                    do {
-                        count = dataInput.read(buffer)
-                        if (count > 0) {
-                            fileOut.write(buffer, 0, count)
-                        }
-                    } while (count > 0)
-                    fileOut.close()
-                    dataInput.close()
-                }
-                uiThread {
-                    mView?.downloadAttachmentSuccess(file)
-                }
-            } catch (e: Exception) {
-                XLog.error("下载附件失败!", e)
-                if (File(path).exists()) {
-                    File(path).delete()
-                }
-            }
-
-            /*val call = RetrofitClient.instance(it.getContext()).meetingAssembleControlApi()
-                    .downloadMeetingFile(meetingFileInfoJson.id)
-                try {
-                    SDCardHelper.generateNewFile(path)
-                    val responseBody = call.execute()
-                    val headerDisposition = responseBody.headers().get("Content-Disposition")
-                    XLog.debug("header disposition: $headerDisposition")
-                    val dataInput = DataInputStream(responseBody.body().byteStream())
-                    val fileOut = DataOutputStream(FileOutputStream(file))
-                    val buffer = ByteArray(4096)
-                    var count = 0
-                    do {
-                        count = dataInput.read(buffer)
-                        if (count > 0) {
-                            fileOut.write(buffer, 0, count)
-                        }
-                    } while (count > 0)
-                    fileOut.close()
-                    dataInput.close()
-                } catch (e: Exception) {
-                    XLog.error("下载附件失败!", e)
-                    if (file.exists()) {
-                        file.delete()
+        val downloadUrl = APIAddressHelper.instance()
+                .getCommonDownloadUrl(APIDistributeTypeEnum.x_meeting_assemble_control, "jaxrs/attachment/${meetingFileInfoJson.id}/download/true")
+        O2FileDownloadHelper.download(downloadUrl, path)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .o2Subscribe {
+                    onNext {
+                        mView?.downloadAttachmentSuccess(File(path))
+                    }
+                    onError { e, _ ->
+                        XLog.error("", e)
                     }
                 }
-            Observable.create(Observable.OnSubscribe<File> { t ->
-                val thisFile = File(path)
-                if (file.exists()) {
-                    t?.onNext(thisFile)
-                } else {
-                    t?.onError(Exception("附件下载异常,找不到文件!"))
-                }
-                t?.onCompleted()
-            })
-                    .subscribeOn(Schedulers.io())
-                    .observeOn(AndroidSchedulers.mainThread())
-                    .subscribe({ file -> it.downloadAttachmentSuccess(file) }, { e ->
-                        XToast.toastShort(it.getContext(), "下载附件失败,${e.message}")
-                        XLog.error("",e)
-                        it.downloadAttachmentSuccess(null)
-                    })*/
-        }
+
     }
 
     override fun asyncLoadPersonName(nameTv: TextView, id: String) {

+ 41 - 8
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainActivity.kt

@@ -415,17 +415,18 @@ class MainActivity : BaseMVPActivity<MainContract.View, MainContract.Presenter>(
                 .setRequiresCharging(true)//充电的时候才执行
                 .setPeriodic(24 * 60 * 60 * 1000)
                 .build()
-        val collectLogComponent = ComponentName(this, CollectLogJobService::class.java)
-        val jobCollectLog = JobInfo.Builder(O2.O2_COLLECT_LOG_JOB_ID, collectLogComponent)
-                .setPersisted(true)
-                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
-                .setPeriodic(1000 * 60 * 60 * 12)
-                .build()
+//        val collectLogComponent = ComponentName(this, CollectLogJobService::class.java)
+//        val jobCollectLog = JobInfo.Builder(O2.O2_COLLECT_LOG_JOB_ID, collectLogComponent)
+//                .setPersisted(true)
+//                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+//                .setPeriodic(1000 * 60 * 60 * 12)
+//                .build()
 
         val jobScheduler = applicationContext.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
         val result = jobScheduler.schedule(jobInfo)
-        val result2 = jobScheduler.schedule(jobCollectLog)
-        XLog.info("jobScheduler result:$result, result2:$result2")
+//        val result2 = jobScheduler.schedule(jobCollectLog)
+//        XLog.info("jobScheduler result:$result, result2:$result2")
+        XLog.info("jobScheduler result:$result")
     }
 
 
@@ -495,6 +496,37 @@ class MainActivity : BaseMVPActivity<MainContract.View, MainContract.Presenter>(
     /**************im 消息接收器***************/
 
     var mReceiver: IMMessageReceiver? = null
+    private var unreadMsgNumber = 0
+
+    fun refreshUnreadNumber(number: Int) {
+        unreadMsgNumber = number
+        when {
+            unreadMsgNumber in 1..99 -> {
+                circle_tv_icon_main_bottom_news.visible()
+                circle_tv_icon_main_bottom_news.setText("$unreadMsgNumber")
+            }
+            unreadMsgNumber >= 100 -> {
+                circle_tv_icon_main_bottom_news.visible()
+                circle_tv_icon_main_bottom_news.setText("99..")
+            }
+            else -> circle_tv_icon_main_bottom_news.gone()
+        }
+    }
+
+    fun addUnreadMsg() {
+        unreadMsgNumber += 1
+        when {
+            unreadMsgNumber in 1..99 -> {
+                circle_tv_icon_main_bottom_news.visible()
+                circle_tv_icon_main_bottom_news.setText("$unreadMsgNumber")
+            }
+            unreadMsgNumber >= 100 -> {
+                circle_tv_icon_main_bottom_news.visible()
+                circle_tv_icon_main_bottom_news.setText("99..")
+            }
+            else -> circle_tv_icon_main_bottom_news.gone()
+        }
+    }
 
     private fun registerBroadcast() {
         mReceiver = IMMessageReceiver()
@@ -507,6 +539,7 @@ class MainActivity : BaseMVPActivity<MainContract.View, MainContract.Presenter>(
         if (newsFragment is O2IMConversationFragment) {
             newsFragment.receiveMessageFromWebsocket(message)
         }
+        addUnreadMsg()
     }
 
     inner class IMMessageReceiver : BroadcastReceiver() {

+ 107 - 54
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/webview/DownloadDocument.kt

@@ -5,6 +5,7 @@ import android.os.Looper
 import android.text.TextUtils
 import com.tencent.smtt.sdk.QbSdk
 import com.tencent.smtt.sdk.ValueCallback
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.tbs.FileReaderActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.RetrofitClient
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.download.DownloadProgressHandler
@@ -18,6 +19,8 @@ import java.io.DataInputStream
 import java.io.DataOutputStream
 import java.io.File
 import java.io.FileOutputStream
+import java.net.HttpURLConnection
+import java.net.URL
 
 /**
  * Created by fancyLou on 2018/8/22.
@@ -28,63 +31,67 @@ class DownloadDocument(val context: Activity) {
     /**
      * 下线公文 并打开预览
      */
-    fun downloadDocumentAndOpenIt(url: String, finishCallback: (()->Unit)) {
-        val urlBase = url.substringBeforeLast("/")
-        val id = url.substringAfterLast("/")
-        XLog.info("文档名称: $id , baseUrl: $urlBase")
-        var path = ""
-
-        RetrofitClient.instance().skinDownloadService("$urlBase/", object : DownloadProgressHandler() {
-            override fun onProgress(progress: Long, total: Long, done: Boolean) {
-                XLog.debug("$progress $total, $done")
-                XLog.debug("是否在主线程中运行" + (Looper.getMainLooper() == Looper.myLooper()).toString())
-                val myP = 100 * progress / total
-                XLog.debug(String.format("%d%% done\n", myP))
-                XLog.debug("done --->$done")
-
-            }
-        }).skinDownload(id)
-                .subscribeOn(Schedulers.io())
-                .flatMap { response ->
-                    var isDownFileSuccess = false
-                    try {
-                        val headers = response.headers()
-                        var fileName = headers.get("Content-Disposition")
-                        if (fileName!=null) {
-                            fileName = fileName.substringAfterLast("''")
-                        }
-                        XLog.debug("filename: $fileName")
-                        path = FileExtensionHelper.getXBPMWORKAttachmentFileByName(fileName)
-                        XLog.debug("path: $path")
-                        val file = File(path)
-                        if (!file.exists()) {
-                            SDCardHelper.generateNewFile(path)
-                        }
-                        val input = DataInputStream(response.body()?.byteStream())
-                        val output = DataOutputStream(FileOutputStream(file))
-                        val buffer = ByteArray(4096)
-                        var count = 0
-                        do {
-                            count = input.read(buffer)
-                            if (count > 0) {
-                                output.write(buffer, 0, count)
-                            }
-                        } while (count > 0)
-                        output.close()
-                        input.close()
-                        isDownFileSuccess = true
-                    } catch (e: Exception) {
-                        XLog.error("download file fail", e)
-                        isDownFileSuccess = false
+    fun downloadDocumentAndOpenIt(url: String, finishCallback: (() -> Unit)) {
+//        val urlBase = url.substringBeforeLast("/")
+//        val id = url.substringAfterLast("/")
+//        XLog.info("文档名称: $id , baseUrl: $urlBase")
+        XLog.info("开始下载文档: $url")
+        Observable.create<String> { subscriber ->
+            var file: File? = null
+            try {
+                val downloadUrl = URL(url)
+                val conn = downloadUrl.openConnection() as HttpURLConnection
+                conn.setRequestProperty("Accept-Encoding", "identity")
+                val newCookie = "x-token:" + O2SDKManager.instance().zToken
+                conn.setRequestProperty("Cookie", newCookie)
+                conn.setRequestProperty("x-token", O2SDKManager.instance().zToken)
+                conn.connect()
+                val inputStream = conn.inputStream
+                var fileName = conn.getHeaderField("Content-Disposition")
+                if (fileName != null) {
+                    fileName = fileName.substringAfterLast("''")
+                }
+                XLog.debug("下载文件名称: $fileName")
+                val path = FileExtensionHelper.getXBPMWORKAttachmentFileByName(fileName)
+                XLog.debug("本地文件存储地址: $path")
+                file = File(path)
+                val fos = FileOutputStream(file)
+                val buf = ByteArray(1024 * 8)
+                var currentLength = 0
+                while (true) {
+                    val num = inputStream.read(buf)
+                    currentLength += num
+                    // 计算进度条位置
+                    if (num <= 0) {
+                        break
                     }
-                    Observable.just(isDownFileSuccess)
-                }.observeOn(AndroidSchedulers.mainThread())
+                    fos.write(buf, 0, num)
+                    fos.flush()
+                }
+                XLog.debug("file length :$currentLength")
+                fos.flush()
+                fos.close()
+                inputStream.close()
+                subscriber.onNext(path)
+                subscriber.onCompleted()
+            } catch (e: Exception) {
+                try {
+                    if (file?.exists() == true) {
+                        file.delete()
+                    }
+                } catch (e: Exception) {
+                }
+                subscriber.onError(e)
+                subscriber.onCompleted()
+            }
+        }.subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
                 .o2Subscribe {
                     onNext { result ->
                         XLog.info("下载文档:$result")
-                        if (result) {
-                            openFileWithTBS(path, "")
-                        }else {
+                        if (TextUtils.isEmpty(result)) {
+                            openFileWithTBS(result, "")
+                        } else {
                             XToast.toastShort(context, "下载文档失败!")
                         }
                         finishCallback()
@@ -95,13 +102,59 @@ class DownloadDocument(val context: Activity) {
                         finishCallback()
                     }
                 }
+
+//        RetrofitClient.instance().skinDownloadService("$urlBase/", object : DownloadProgressHandler() {
+//            override fun onProgress(progress: Long, total: Long, done: Boolean) {
+//                XLog.debug("$progress $total, $done")
+//                XLog.debug("是否在主线程中运行" + (Looper.getMainLooper() == Looper.myLooper()).toString())
+//                val myP = 100 * progress / total
+//                XLog.debug(String.format("%d%% done\n", myP))
+//                XLog.debug("done --->$done")
+//
+//            }
+//        }).skinDownload(id)
+//                .subscribeOn(Schedulers.io())
+//                .flatMap { response ->
+//                    var isDownFileSuccess = false
+//                    try {
+//                        val headers = response.headers()
+//                        var fileName = headers.get("Content-Disposition")
+//                        if (fileName!=null) {
+//                            fileName = fileName.substringAfterLast("''")
+//                        }
+//                        XLog.debug("filename: $fileName")
+//                        path = FileExtensionHelper.getXBPMWORKAttachmentFileByName(fileName)
+//                        XLog.debug("path: $path")
+//                        val file = File(path)
+//                        if (!file.exists()) {
+//                            SDCardHelper.generateNewFile(path)
+//                        }
+//                        val input = DataInputStream(response.body()?.byteStream())
+//                        val output = DataOutputStream(FileOutputStream(file))
+//                        val buffer = ByteArray(4096)
+//                        var count = 0
+//                        do {
+//                            count = input.read(buffer)
+//                            if (count > 0) {
+//                                output.write(buffer, 0, count)
+//                            }
+//                        } while (count > 0)
+//                        output.close()
+//                        input.close()
+//                        isDownFileSuccess = true
+//                    } catch (e: Exception) {
+//                        XLog.error("download file fail", e)
+//                        isDownFileSuccess = false
+//                    }
+//                    Observable.just(isDownFileSuccess)
+//                }
     }
 
     //......没有集成
     private fun openFileWithTBS(path: String?, fileName: String) = if (!TextUtils.isEmpty(path)) {
         context.go<FileReaderActivity>(FileReaderActivity.startBundle(path!!))
 //        AndroidUtils.openFileWithDefaultApp(context, File(path))
-    }else {
+    } else {
         XLog.error("文档本地地址没有。。。。。。。。。。。")
     }
 }

+ 93 - 74
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/webview/TaskWebViewPresenter.kt

@@ -5,16 +5,15 @@ import net.muliba.accounting.app.ExceptionHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2App
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.APIAddressHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.APIDistributeTypeEnum
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.IdData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AttachmentInfo
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.o2.ReadData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.o2.TaskData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.o2.WorkLog
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileExtensionHelper
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.FileUtil
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.SDCardHelper
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import okhttp3.MediaType
 import okhttp3.MultipartBody
@@ -208,42 +207,51 @@ class TaskWebViewPresenter : BasePresenterImpl<TaskWebViewContract.View>(), Task
                         val info: AttachmentInfo? = response.data
                         if (info != null) {
                             val path = FileExtensionHelper.getXBPMWORKAttachmentFileByName(info.name)
-                            val file = File(path)
-                            if (!file.exists()) { //下载
-                                try {
-                                    SDCardHelper.generateNewFile(path)
-                                    val call = service.downloadWorkAttachment(attachmentId, workId)
-                                    val downloadRes = call.execute()
-                                    val headerDisposition = downloadRes.headers().get("Content-Disposition")
-                                    XLog.debug("header disposition: $headerDisposition")
-                                    val dataInput = DataInputStream(downloadRes.body()?.byteStream())
-                                    val fileOut = DataOutputStream(FileOutputStream(file))
-                                    val buffer = ByteArray(4096)
-                                    var count = 0
-                                    do {
-                                        count = dataInput.read(buffer)
-                                        if (count > 0) {
-                                            fileOut.write(buffer, 0, count)
-                                        }
-                                    } while (count > 0)
-                                    fileOut.close()
-                                    dataInput.close()
-                                } catch (e: Exception) {
-                                    XLog.error("下载附件失败!", e)
-                                    if (file.exists()) {
-                                        file.delete()
+                            SDCardHelper.generateNewFile(path)
+                            val downloadUrl = APIAddressHelper.instance()
+                                    .getCommonDownloadUrl(APIDistributeTypeEnum.x_processplatform_assemble_surface, "jaxrs/attachment/download/$attachmentId/work/$workId/stream")
+                            O2FileDownloadHelper.download(downloadUrl, path)
+                                    .flatMap {
+                                        Observable.just(File(path))
                                     }
-                                }
-                            }
-                            Observable.create { t ->
-                                val thisfile = File(path)
-                                if (file.exists()) {
-                                    t?.onNext(thisfile)
-                                } else {
-                                    t?.onError(Exception("附件下载异常,找不到文件!"))
-                                }
-                                t?.onCompleted()
-                            }
+
+
+//                            val file = File(path)
+//                            if (!file.exists()) { //下载
+//                                try {
+//                                    SDCardHelper.generateNewFile(path)
+//                                    val call = service.downloadWorkAttachment(attachmentId, workId)
+//                                    val downloadRes = call.execute()
+//                                    val headerDisposition = downloadRes.headers().get("Content-Disposition")
+//                                    XLog.debug("header disposition: $headerDisposition")
+//                                    val dataInput = DataInputStream(downloadRes.body()?.byteStream())
+//                                    val fileOut = DataOutputStream(FileOutputStream(file))
+//                                    val buffer = ByteArray(4096)
+//                                    var count = 0
+//                                    do {
+//                                        count = dataInput.read(buffer)
+//                                        if (count > 0) {
+//                                            fileOut.write(buffer, 0, count)
+//                                        }
+//                                    } while (count > 0)
+//                                    fileOut.close()
+//                                    dataInput.close()
+//                                } catch (e: Exception) {
+//                                    XLog.error("下载附件失败!", e)
+//                                    if (file.exists()) {
+//                                        file.delete()
+//                                    }
+//                                }
+//                            }
+//                            Observable.create { t ->
+//                                val thisfile = File(path)
+//                                if (file.exists()) {
+//                                    t?.onNext(thisfile)
+//                                } else {
+//                                    t?.onError(Exception("附件下载异常,找不到文件!"))
+//                                }
+//                                t?.onCompleted()
+//                            }
                         } else {
                             Observable.create(object : Observable.OnSubscribe<File> {
                                 override fun call(t: Subscriber<in File>?) {
@@ -276,42 +284,53 @@ class TaskWebViewPresenter : BasePresenterImpl<TaskWebViewContract.View>(), Task
                         val info: AttachmentInfo? = response.data
                         if (info != null) {
                             val path = FileExtensionHelper.getXBPMWORKAttachmentFileByName(info.name)
-                            val file = File(path)
-                            if (!file.exists()) { //下载
-                                try {
-                                    SDCardHelper.generateNewFile(path)
-                                    val call = service.downloadWorkCompletedAttachment(attachmentId, workCompleted)
-                                    val downloadRes = call.execute()
-                                    val headerDisposition = downloadRes.headers().get("Content-Disposition")
-                                    XLog.debug("header disposition: $headerDisposition")
-                                    val dataInput = DataInputStream(downloadRes.body()?.byteStream())
-                                    val fileOut = DataOutputStream(FileOutputStream(file))
-                                    val buffer = ByteArray(4096)
-                                    var count = 0
-                                    do {
-                                        count = dataInput.read(buffer)
-                                        if (count > 0) {
-                                            fileOut.write(buffer, 0, count)
-                                        }
-                                    } while (count > 0)
-                                    fileOut.close()
-                                    dataInput.close()
-                                } catch (e: Exception) {
-                                    XLog.error("下载附件失败!", e)
-                                    if (file.exists()) {
-                                        file.delete()
+                            SDCardHelper.generateNewFile(path)
+                            val downloadUrl = APIAddressHelper.instance()
+                                    .getCommonDownloadUrl(APIDistributeTypeEnum.x_processplatform_assemble_surface, "jaxrs/attachment/download/$attachmentId/workcompleted/$workCompleted/stream")
+                            O2FileDownloadHelper.download(downloadUrl, path)
+                                    .flatMap {
+                                        Observable.just(File(path))
                                     }
-                                }
-                            }
-                            Observable.create { t ->
-                                val thisfile = File(path)
-                                if (file.exists()) {
-                                    t?.onNext(thisfile)
-                                } else {
-                                    t?.onError(Exception("附件下载异常,找不到文件!"))
-                                }
-                                t?.onCompleted()
-                            }
+
+
+//                            val file = File(path)
+//                            if (!file.exists()) { //下载
+//                                try {
+//                                    SDCardHelper.generateNewFile(path)
+//                                    val call = service.downloadWorkCompletedAttachment(attachmentId, workCompleted)
+//                                    val downloadRes = call.execute()
+//                                    val headerDisposition = downloadRes.headers().get("Content-Disposition")
+//                                    XLog.debug("header disposition: $headerDisposition")
+//                                    val dataInput = DataInputStream(downloadRes.body()?.byteStream())
+//                                    val fileOut = DataOutputStream(FileOutputStream(file))
+//                                    val buffer = ByteArray(4096)
+//                                    var count = 0
+//                                    do {
+//                                        count = dataInput.read(buffer)
+//                                        if (count > 0) {
+//                                            fileOut.write(buffer, 0, count)
+//                                        }
+//                                    } while (count > 0)
+//                                    fileOut.close()
+//                                    dataInput.close()
+//                                } catch (e: Exception) {
+//                                    XLog.error("下载附件失败!", e)
+//                                    if (file.exists()) {
+//                                        file.delete()
+//                                    }
+//                                }
+//                            }
+//                            Observable.create { t ->
+//                                val thisfile = File(path)
+//                                if (file.exists()) {
+//                                    t?.onNext(thisfile)
+//                                } else {
+//                                    t?.onError(Exception("附件下载异常,找不到文件!"))
+//                                }
+//                                t?.onCompleted()
+//                            }
+
+
                         } else {
                             Observable.create(object : Observable.OnSubscribe<File> {
                                 override fun call(t: Subscriber<in File>?) {

+ 12 - 2
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/service/PictureLoaderService.kt

@@ -23,6 +23,7 @@ import org.jetbrains.anko.dip
 import org.jetbrains.anko.doAsync
 import org.jetbrains.anko.uiThread
 import java.io.BufferedReader
+import java.io.FileOutputStream
 import java.io.InputStream
 import java.io.InputStreamReader
 import java.net.HttpURLConnection
@@ -297,8 +298,17 @@ class PictureLoaderService(val context: Context) {
         var inputstream:InputStream? = null
         try {
             XLog.debug("load avatar : $name")
-            val response = RetrofitClient.instance().assembleExpressApi().loadPersonAvatar(name).execute()
-            inputstream = response.body()?.byteStream()
+//            val response = RetrofitClient.instance().assembleExpressApi().loadPersonAvatar(name).execute()
+//            inputstream = response.body()?.byteStream()
+            val downloadUrl = APIAddressHelper.instance().getCommonDownloadUrl(APIDistributeTypeEnum.x_organization_assemble_express, "servlet/icon/$name")
+                val url = URL(downloadUrl)
+                val conn = url.openConnection() as HttpURLConnection
+                conn.setRequestProperty("Accept-Encoding", "identity")
+                val newCookie = "x-token:" + O2SDKManager.instance().zToken
+                conn.setRequestProperty("Cookie", newCookie)
+                conn.setRequestProperty("x-token", O2SDKManager.instance().zToken)
+                conn.connect()
+                inputstream = conn.inputStream
         }catch (e: Exception){XLog.error("获取头像失败", e)}
         return inputstream
     }

+ 73 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/O2FileDownloadHelper.kt

@@ -0,0 +1,73 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils
+
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
+import rx.Observable
+import java.io.File
+import java.io.FileOutputStream
+import java.net.HttpURLConnection
+import java.net.URL
+
+
+/**
+ * Created by fancyLou on 2020-06-22.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+object O2FileDownloadHelper {
+
+    fun download(downloadUrl: String, outputFilePath: String): Observable<Boolean> {
+        XLog.debug("准备下载文件 网络下载url: $downloadUrl 本地路径: $outputFilePath")
+        return Observable.create { subscriber ->
+            val file = File(outputFilePath)
+            if (file.exists()) {
+                subscriber.onNext(true)
+                subscriber.onCompleted()
+            }else {
+                try {
+                    val url = URL(downloadUrl)
+                    val conn = url.openConnection() as HttpURLConnection
+                    conn.setRequestProperty("Accept-Encoding", "identity")
+                    val newCookie = "x-token:" + O2SDKManager.instance().zToken
+                    conn.setRequestProperty("Cookie", newCookie)
+                    conn.setRequestProperty("x-token", O2SDKManager.instance().zToken)
+                    conn.connect()
+                    val inputStream = conn.inputStream
+                    var fileName = conn.getHeaderField("Content-Disposition")
+                    if (fileName!=null) {
+                        fileName = fileName.substringAfterLast("''")
+                    }
+                    XLog.debug("下载文件名称: $fileName")
+                    val fos = FileOutputStream(file, true)
+                    val buf = ByteArray(1024 * 8)
+                    var currentLength = 0
+                    while (true) {
+                        val num = inputStream.read(buf)
+                        currentLength += num
+                        // 计算进度条位置
+                        if (num <= 0) {
+                            break
+                        }
+                        fos.write(buf, 0, num)
+                        fos.flush()
+                    }
+                    XLog.debug("file length :$currentLength")
+                    fos.flush()
+                    fos.close()
+                    inputStream.close()
+                    subscriber.onNext(true)
+                    subscriber.onCompleted()
+                }catch (e: Exception){
+                    try {
+                        if (file.exists()) {
+                            file.delete()
+                        }
+                    } catch (e: Exception) {}
+                    subscriber.onError(e)
+                    subscriber.onCompleted()
+                }
+            }
+        }
+    }
+
+
+}

+ 13 - 0
o2android/app/src/main/res/drawable/f5_circle.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+	<item>
+		<shape android:shape="oval">
+			<solid android:color="#ffffff"/>
+		</shape>
+	</item>
+	<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
+		<shape android:shape="oval">
+			<solid android:color="#F5F5F5"/>
+		</shape>
+	</item>
+</layer-list>

+ 5 - 4
o2android/app/src/main/res/layout/activity_local_image_view.xml

@@ -10,12 +10,13 @@
     tools:context=".app.o2.webview.LocalImageViewActivity">
     <RelativeLayout
         android:layout_width="match_parent"
-        android:layout_height="48dp"
-        android:padding="@dimen/spacing_small">
+        android:layout_height="48dp">
         <ImageView
             android:id="@+id/image_local_view_back_btn"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="42dp"
+            android:layout_height="42dp"
+            android:padding="@dimen/spacing_small"
+            android:scaleType="fitCenter"
             android:layout_alignParentStart="true"
             android:layout_centerVertical="true"
             android:src="@mipmap/ic_back_mtrl_white_alpha"/>

+ 38 - 2
o2android/app/src/main/res/layout/activity_o2_chat.xml

@@ -92,9 +92,9 @@
             android:paddingStart="@dimen/activity_horizontal_margin"
             android:paddingEnd="@dimen/activity_horizontal_margin"
             android:orientation="horizontal"
-            android:visibility="gone"
             android:baselineAligned="false">
              <LinearLayout
+                 android:id="@+id/ll_o2_chat_audio_btn"
                  android:layout_width="0dp"
                  android:layout_height="wrap_content"
                  android:layout_weight="1"
@@ -107,6 +107,7 @@
                      android:src="@mipmap/chat_mic" />
              </LinearLayout>
             <LinearLayout
+                android:id="@+id/ll_o2_chat_album_btn"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
@@ -119,6 +120,7 @@
                     android:src="@mipmap/chat_img" />
             </LinearLayout>
             <LinearLayout
+                android:id="@+id/ll_o2_chat_camera_btn"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
@@ -131,6 +133,7 @@
                     android:src="@mipmap/chat_camera" />
             </LinearLayout>
             <LinearLayout
+                android:id="@+id/ll_o2_chat_location_btn"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
@@ -147,13 +150,46 @@
         <android.support.v7.widget.RecyclerView
             android:id="@+id/rv_o2_chat_emoji_box"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
+            android:layout_height="250dp"
             android:layout_marginBottom="@dimen/spacing_small"
             android:visibility="gone"
             android:paddingStart="@dimen/activity_horizontal_margin"
             android:paddingEnd="@dimen/activity_horizontal_margin"
             />
 
+        <RelativeLayout
+            android:id="@+id/tv_o2_chat_audio_send_box"
+            android:layout_width="match_parent"
+            android:layout_height="180dp"
+            android:layout_marginBottom="@dimen/spacing_small"
+            android:visibility="gone">
+            <TextView
+                android:id="@+id/tv_o2_chat_audio_speak_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerHorizontal="true"
+                android:textSize="@dimen/font_small"
+                android:textColor="@color/z_color_subtitle_font"
+                android:text="@string/activity_im_audio_speak" />
+            <TextView
+                android:id="@+id/tv_o2_chat_audio_speak_duration"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerHorizontal="true"
+                android:layout_marginTop="@dimen/spacing_tiny"
+                android:layout_below="@+id/tv_o2_chat_audio_speak_title"
+                android:textSize="@dimen/font_mini"
+                android:textColor="@color/z_color_primary_blur_blue"
+                tools:text="00:01" />
+            <ImageButton
+                android:id="@+id/image_o2_chat_audio_speak_btn"
+                android:layout_width="96dp"
+                android:layout_height="96dp"
+                android:src="@mipmap/chat_mic"
+                android:layout_centerInParent="true"
+                android:background="@drawable/f5_circle"
+                />
+        </RelativeLayout>
 
     </LinearLayout>
 

+ 38 - 0
o2android/app/src/main/res/layout/activity_o2_location.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".app.im.O2LocationActivity">
+    <include layout="@layout/snippet_appbarlayout_toolbar" />
+
+    <com.baidu.mapapi.map.MapView
+        android:id="@+id/map_baidu_o2_location"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/app_bar_layout_snippet"
+        android:clickable="true" />
+
+
+    <TextView
+        android:id="@+id/tv_o2_location_address"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toBottomOf="@+id/app_bar_layout_snippet"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        android:padding="@dimen/spacing_tiny"
+        android:background="@color/z_color_white_translucent_af"
+        android:maxLines="1"
+        android:textSize="@dimen/font_small"
+        android:textAlignment="center"
+        android:ellipsize="end"
+        android:visibility="gone"
+        tools:text="浙江省杭州市萧山区高桥路111号" />
+
+
+</android.support.constraint.ConstraintLayout>

+ 15 - 0
o2android/app/src/main/res/layout/fragment_main_bottom_bar_image.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="56dp"
     android:orientation="vertical"
@@ -39,6 +40,20 @@
                 android:textSize="12sp"
                 android:textColor="@color/z_color_text_primary"
                 android:text="@string/tab_message"/>
+            <net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.CircleTextView
+                android:id="@+id/circle_tv_icon_main_bottom_news"
+                android:layout_width="16dp"
+                android:layout_height="16dp"
+                android:layout_marginStart="25dp"
+                app:c_height="16dp"
+                app:c_inColor="@color/z_color_primary"
+                app:c_text="5"
+                android:textAlignment="center"
+                app:c_textColor="@android:color/white"
+                app:c_textSize="@dimen/font_mini"
+                app:c_width="16dp"
+                android:visibility="gone"
+                />
         </RelativeLayout>
         <RelativeLayout
             android:id="@+id/icon_main_bottom_contact"

+ 46 - 0
o2android/app/src/main/res/layout/item_o2_chat_message_text_left.xml

@@ -46,6 +46,52 @@
                 android:layout_height="32dp"
                 android:visibility="gone"
                 tools:src="@mipmap/im_emotion_01"/>
+            <ImageView
+                android:id="@+id/image_o2_chat_message_image_body"
+                android:layout_width="144dp"
+                android:layout_height="192dp"
+                android:visibility="gone"
+                android:scaleType="fitCenter"
+                tools:src="@mipmap/default_image"/>
+            <LinearLayout
+                android:id="@+id/ll_o2_chat_message_audio_body"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:visibility="gone"
+                android:orientation="horizontal">
+                <ImageView
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
+                    android:src="@mipmap/chat_icon_audio_play"/>
+                <TextView
+                    android:id="@+id/tv_o2_chat_message_audio_duration"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/spacing_small"
+                    tools:text="60&#34;" />
+            </LinearLayout>
+            <RelativeLayout
+                android:id="@+id/rl_o2_chat_message_location_body"
+                android:layout_width="175dp"
+                android:layout_height="109dp"
+                android:visibility="gone"
+                android:orientation="horizontal">
+                <ImageView
+                    android:layout_width="175dp"
+                    android:layout_height="109dp"
+                    android:src="@mipmap/chat_location_background"/>
+                <TextView
+                    android:id="@+id/tv_o2_chat_message_location_address"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:padding="@dimen/spacing_tiny"
+                    android:background="@color/z_color_white_translucent_af"
+                    android:maxLines="1"
+                    android:textSize="@dimen/font_small"
+                    android:ellipsize="end"
+                    tools:text="浙江省杭州市萧山区高桥路111号" />
+            </RelativeLayout>
         </LinearLayout>
 
         <ImageButton

+ 46 - 0
o2android/app/src/main/res/layout/item_o2_chat_message_text_right.xml

@@ -45,6 +45,52 @@
                 android:layout_height="32dp"
                 android:visibility="gone"
                 tools:src="@mipmap/im_emotion_01"/>
+            <ImageView
+                android:id="@+id/image_o2_chat_message_image_body"
+                android:layout_width="144dp"
+                android:layout_height="192dp"
+                android:visibility="gone"
+                android:scaleType="fitCenter"
+                tools:src="@mipmap/default_image"/>
+            <LinearLayout
+                android:id="@+id/ll_o2_chat_message_audio_body"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:visibility="gone"
+                android:orientation="horizontal">
+                <ImageView
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
+                    android:src="@mipmap/chat_icon_audio_play"/>
+                <TextView
+                    android:id="@+id/tv_o2_chat_message_audio_duration"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/spacing_small"
+                    tools:text="60&#34;" />
+            </LinearLayout>
+            <RelativeLayout
+                android:id="@+id/rl_o2_chat_message_location_body"
+                android:layout_width="175dp"
+                android:layout_height="109dp"
+                android:visibility="gone"
+                android:orientation="horizontal">
+                <ImageView
+                    android:layout_width="175dp"
+                    android:layout_height="109dp"
+                    android:src="@mipmap/chat_location_background"/>
+                <TextView
+                    android:id="@+id/tv_o2_chat_message_location_address"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:padding="@dimen/spacing_tiny"
+                    android:background="@color/z_color_white_translucent_af"
+                    android:maxLines="1"
+                    android:textSize="@dimen/font_small"
+                    android:ellipsize="end"
+                    tools:text="浙江省杭州市萧山区高桥路111号" />
+            </RelativeLayout>
         </LinearLayout>
 
         <ImageButton

+ 11 - 0
o2android/app/src/main/res/menu/menu_location_send.xml

@@ -0,0 +1,11 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    tools:context=".app.im.O2LocationActivity">
+
+    <item android:id="@+id/location_send"
+        app:showAsAction="ifRoom"
+        android:title="@string/activity_location_send"
+        android:orderInCategory="900" />
+
+</menu>

BIN
o2android/app/src/main/res/mipmap-xhdpi/chat_icon_audio_play.png


BIN
o2android/app/src/main/res/mipmap-xhdpi/chat_location_background.png


BIN
o2android/app/src/main/res/mipmap-xhdpi/group_default.png


+ 3 - 0
o2android/app/src/main/res/values/strings.xml

@@ -215,6 +215,9 @@
     <string name="activity_im_tribe_save">保      存</string>
     <string name="activity_im_tribe_delete">删除并退出</string>
     <string name="activity_im_tribe_update">更      新</string>
+    <string name="activity_im_audio_speak">按住说话</string>
+    <string name="activity_im_audio_speak_cancel">上滑取消发送</string>
+    <string name="activity_location_send">发送</string>
 
     <!-- myinfo activity -->
     <string name="title_activity_my_info">我的资料</string>

+ 2 - 2
o2android/gradle.properties

@@ -20,6 +20,6 @@ org.gradle.parallel=true
 
 
 # o2
-o2.versionName=5.0.0
-o2.versionCode=500
+o2.versionName=5.1.0
+o2.versionCode=110
 

+ 24 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/APIAddressHelper.kt

@@ -148,6 +148,30 @@ class APIAddressHelper private constructor() {
         return getAPIDistribute(APIDistributeTypeEnum.x_file_assemble_control) + "jaxrs/file/$pid/download/stream"
     }
 
+    /**
+     * 聊天消息 文件下载地址
+     */
+    fun getImFileDownloadUrl(fileId: String): String {
+        return getAPIDistribute(APIDistributeTypeEnum.x_message_assemble_communicate) + "jaxrs/im/msg/download/$fileId"
+    }
+
+    /**
+     * 通用的
+     * 下载文件的地址
+     * @param context: APIDistributeTypeEnum
+     * @param urlPath : 例如:jaxrs/im/msg/download/12222233333
+     */
+    fun getCommonDownloadUrl(context: APIDistributeTypeEnum, urlPath: String): String {
+        return getAPIDistribute(context) + urlPath
+    }
+
+    /**
+     * 聊天消息
+     */
+    fun getImImageDownloadUrlWithWH(fileId: String, width: Int, height: Int): String {
+        return getAPIDistribute(APIDistributeTypeEnum.x_message_assemble_communicate) + "jaxrs/im/msg/download/$fileId/image/width/$width/height/$height"
+    }
+
     /**
      * 云盘图片地址
      * @param fileId 图片文件id

+ 1 - 8
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/BBSAssembleControlService.kt

@@ -138,12 +138,5 @@ interface BBSAssembleControlService {
     fun getSubjectAttachList(@Path("id") id: String): Observable<ApiResponse<List<BBSSubjectAttachmentJson>>>
 
 
-    /**
-     * 附件下载
-     * @param attachId
-     * *
-     * @return
-     */
-    @GET("jaxrs/attachment/download/{id}/stream/{stream}")
-    fun downloadAttach(@Path("id") id: String,@Path("stream") stream: Boolean = true): Call<ResponseBody>
+
 }

+ 0 - 9
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/CMSAssembleControlService.kt

@@ -100,15 +100,6 @@ interface CMSAssembleControlService {
     fun getDocumentAttachList(@Path("docId") docId: String): Observable<ApiResponse<List<CMSDocumentAttachmentJson>>>
 
 
-    /**
-     * 附件下载
-     * @param id 附件id
-     * *
-     * @return
-     */
-    @GET("jaxrs/fileinfo/download/document/{id}/stream")
-    fun downloadAttach(@Path("id") id: String): Call<ResponseBody>
-
     /**
      * 附件上传
      * @param body

+ 0 - 10
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/CloudFileControlService.kt

@@ -127,16 +127,6 @@ interface CloudFileControlService {
     fun deleteFolder(@Path("folderId") folderId: String): Observable<ApiResponse<IdData>>
 
 
-    /**
-     * 下载文件
-     * @param id
-     * *
-     * @return
-     */
-    @GET("jaxrs/attachment2/{id}/download/stream")
-    fun downloadFile(@Path("id") id: String): Call<ResponseBody>
-
-
     /**
      * 分享
      */

+ 1 - 8
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/FileAssembleControlService.kt

@@ -17,14 +17,7 @@ import rx.Observable
 
 interface FileAssembleControlService {
 
-    /**
-     * 下载文件
-     * @param fileId
-     * *
-     * @return
-     */
-    @GET("jaxrs/attachment/{id}/download/stream")
-    fun downloadFile(@Path("id") id: String): Call<ResponseBody>
+
 
     /**
      * 上传文件

+ 0 - 8
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/MeetingAssembleControlService.kt

@@ -149,14 +149,6 @@ interface MeetingAssembleControlService {
     @DELETE("jaxrs/attachment/{id}")
     fun deleteMeetingFile(@Path("id") id: String): Observable<ApiResponse<IdData>>
 
-    /**
-     * 下载会议材料
-     * @param fileId
-     *
-     * @return
-     */
-    @GET("jaxrs/attachment/{id}/download/{stream}")
-    fun downloadMeetingFile(@Path("id") fileId: String,@Path("stream") stream: Boolean = true): Call<ResponseBody>
 
     /**
      * 更新会议

+ 16 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/MessageCommunicateService.kt

@@ -6,7 +6,11 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.InstantMessage
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.InstantMessageData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMConversationInfo
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessage
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageFileData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.IMMessageForm
+import okhttp3.MultipartBody
+import okhttp3.ResponseBody
+import retrofit2.Call
 import retrofit2.http.*
 import rx.Observable
 
@@ -69,4 +73,16 @@ interface MessageCommunicateService {
     @GET("jaxrs/instant/list/currentperson/noim/count/{count}/desc")
     fun instantMessageList(@Path("count") count: Int) : Observable<ApiResponse<List<InstantMessage>>>
 
+    /**
+     * 上传文件
+     * im消息文件 图片 音频 视频等
+     * @param conversationId 会话id
+     * @param type 消息类型 image audio 等
+     */
+    @Multipart
+    @POST("jaxrs/im/msg/upload/{conversationId}/type/{type}")
+    fun uploadFile(@Path("conversationId") conversationId: String, @Path("type") type: String, @Part body: MultipartBody.Part): Observable<ApiResponse<IMMessageFileData>>
+
+
+
 }

+ 1 - 9
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssembleExpressService.kt

@@ -155,15 +155,7 @@ interface OrgAssembleExpressService {
     @POST("jaxrs/unitduty/list/identity/unit/name/object")
     fun identityListByUnitAndDuty(@Body body: UnitDutyIdentityForm): Observable<ApiResponse<List<IdentityJson>>>
 
-    /**
-     * 获取用户头像
-     * @param person
-     * *
-     * @return
-     */
-    @GET("servlet/icon/{person}")
-    @Headers("Content-Type: application/octet-stream")
-    fun loadPersonAvatar(@Path("person") person: String): Call<ResponseBody>
+
 
     /**
      * 根据身份查询和层级查询组织

+ 19 - 19
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/ProcessAssembleSurfaceService.kt

@@ -339,25 +339,25 @@ interface ProcessAssembleSurfaceService {
     @PUT("jaxrs/attachment/update/{attachmentId}/work/{workId}")
     fun replaceAttachment(@Part body: MultipartBody.Part, @Path("attachmentId") attachmentId: String, @Path("workId") workId: String): Observable<ApiResponse<IdData>>
 
-    /**
-     * 附件下载
-     * @param attachId
-     * *
-     * @return
-     */
-    @GET("jaxrs/attachment/download/{attachId}/work/{workId}/stream")
-    @Headers("Content-Type: application/json; charset=utf-8")
-    fun downloadWorkAttachment(@Path("attachId") attachId: String, @Path("workId") workId: String): Call<ResponseBody>
-
-    /**
-     * 附件下载
-     * @param attachId
-     * *
-     * @return
-     */
-    @GET("jaxrs/attachment/download/{attachId}/workcompleted/{workCompletedId}/stream")
-    @Headers("Content-Type: application/json; charset=utf-8")
-    fun downloadWorkCompletedAttachment(@Path("attachId") attachId: String, @Path("workCompletedId") workCompletedId: String): Call<ResponseBody>
+//    /**
+//     * 附件下载
+//     * @param attachId
+//     * *
+//     * @return
+//     */
+//    @GET("jaxrs/attachment/download/{attachId}/work/{workId}/stream")
+//    @Headers("Content-Type: application/json; charset=utf-8")
+//    fun downloadWorkAttachment(@Path("attachId") attachId: String, @Path("workId") workId: String): Call<ResponseBody>
+//
+//    /**
+//     * 附件下载
+//     * @param attachId
+//     * *
+//     * @return
+//     */
+//    @GET("jaxrs/attachment/download/{attachId}/workcompleted/{workCompletedId}/stream")
+//    @Headers("Content-Type: application/json; charset=utf-8")
+//    fun downloadWorkCompletedAttachment(@Path("attachId") attachId: String, @Path("workCompletedId") workCompletedId: String): Call<ResponseBody>
 
     /**
      * 测试附件是否可用

+ 13 - 26
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/im/IMMessage.kt

@@ -1,8 +1,8 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im
 
 import android.text.TextUtils
-import org.json.JSONObject
-import org.json.JSONTokener
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
+
 
 data class IMMessage(
         var id: String = "",
@@ -18,33 +18,20 @@ data class IMMessage(
         if (TextUtils.isEmpty(body)) {
             return null
         }
-        val json = JSONTokener(body).nextValue()
-        if (json is JSONObject) {
-            try {
-                if (json.has("type")) {
-                    val type = json.getString("type")
-                    if (MessageType.text.key == type) {
-                        val textBody = json.getString("body")
-                        return IMMessageBody.Text(textBody)
-                    }else if(MessageType.emoji.key == type) {
-                        val textBody = json.getString("body")
-                        return IMMessageBody.Emoji(textBody)
-                    }
-                }else {
-                    val textBody = json.getString("body")
-                    return IMMessageBody.Text(textBody)
-                }
-            } catch (e: Exception) {
-            }
-
-        }
-        return null
+        return O2SDKManager.instance().gson.fromJson(body, IMMessageBody::class.java)
     }
-
-
 }
 
 enum class MessageType(val key:String) {
     text("text"),
-    emoji("emoji")
+    emoji("emoji"),
+    image("image"),
+    audio("audio"),
+    location("location")
+}
+
+enum class MessageBody(val body:String) {
+    image("[图片]"),
+    audio("[语音]"),
+    location("[位置]")
 }

+ 12 - 7
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/im/IMMessageBody.kt

@@ -1,11 +1,16 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im
 
 
+class IMMessageBody(
+        var type: String?,
+        var body: String?,
+        var fileId: String? = null, //文件id
+        var fileExtension: String? = null, //文件扩展
+        var fileTempPath: String? = null, //本地临时文件地址
+        var audioDuration: String? = null, // 音频文件时长
+        var address: String? = null, //type=location的时候位置信息
+        var addressDetail: String? = null,
+        var latitude: Double? = null,//type=location的时候位置信息
+        var longitude: Double? = null//type=location的时候位置信息
+)
 
-sealed class IMMessageBody(open var  type: String) {
-
-    class Text(var  body: String): IMMessageBody(MessageType.text.key)
-    class Emoji(var  body: String): IMMessageBody(MessageType.emoji.key)
-
-
-}

+ 12 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/im/IMMessageFileData.kt

@@ -0,0 +1,12 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im
+
+
+/**
+ * Created by fancyLou on 2020-06-21.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+data class IMMessageFileData(
+        var id: String = "",
+        var fileExtension: String = ""
+)

+ 1 - 0
o2ios/.gitignore

@@ -5,6 +5,7 @@
 ## Build generated
 build/
 DerivedData/
+BuildShell/
 
 ## Various settings
 *.pbxuser

+ 303 - 57
o2ios/O2Platform.xcodeproj/project.pbxproj

@@ -37,6 +37,7 @@
 		09E02E981F16319600579887 /* UIView+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E02E821F16319600579887 /* UIView+Haneke.swift */; };
 		09E02E9A1F1745E700579887 /* ZLTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E02E991F1745E700579887 /* ZLTextView.swift */; };
 		37D63E73FDC49F690C780FD1 /* Pods_O2Platform.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 10069E72107080DCAD68970B /* Pods_O2Platform.framework */; };
+		8840A992248CDC9D005970A5 /* OOCalendarEditRemarkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8840A991248CDC9D005970A5 /* OOCalendarEditRemarkViewController.swift */; };
 		A043051B1F99CFD500740423 /* MailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A043051A1F99CFD500740423 /* MailViewController.swift */; };
 		B1015DDB2272B5DB00C1A7E6 /* O2BaseJsMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1015DDA2272B5DB00C1A7E6 /* O2BaseJsMessageHandler.swift */; };
 		B104303721464C690011B08E /* ai.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B104303621464C690011B08E /* ai.storyboard */; };
@@ -56,6 +57,14 @@
 		B108F402229E34D400778050 /* LBXScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108F3FB229E34D300778050 /* LBXScanViewController.swift */; };
 		B10A2F56233DDA990011CE3D /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B10A2F55233DDA990011CE3D /* AdSupport.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 */; };
 		B1298E7C23669BA2006E9236 /* CloudFileTypeListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E7B23669BA2006E9236 /* CloudFileTypeListController.swift */; };
 		B1298E7E2366AE4C006E9236 /* CloudFileImageCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1298E7D2366AE4C006E9236 /* CloudFileImageCollectionController.swift */; };
@@ -111,6 +120,18 @@
 		B13A0120236935BC00025F3B /* O2CloudFileInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B13A011F236935BC00025F3B /* O2CloudFileInfo.swift */; };
 		B142B081230FB56400E7D127 /* MimeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B142B080230FB56400E7D127 /* MimeType.swift */; };
 		B142B083230FB58B00E7D127 /* Swime.swift in Sources */ = {isa = PBXBuildFile; fileRef = B142B082230FB58B00E7D127 /* Swime.swift */; };
+		B1489B1C248E0F4D009EE9FD /* IMChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1489B1A248E0F4D009EE9FD /* IMChatViewController.swift */; };
+		B1489B1D248E0F4D009EE9FD /* IMChatViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1489B1B248E0F4D009EE9FD /* IMChatViewController.xib */; };
+		B1489B51248E192D009EE9FD /* IMChatMessageViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1489B4F248E192D009EE9FD /* IMChatMessageViewCell.swift */; };
+		B1489B52248E192D009EE9FD /* IMChatMessageViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1489B50248E192D009EE9FD /* IMChatMessageViewCell.xib */; };
+		B1489BFE2490BE51009EE9FD /* IMChatMessageSendViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1489BFC2490BE51009EE9FD /* IMChatMessageSendViewCell.swift */; };
+		B1489BFF2490BE51009EE9FD /* IMChatMessageSendViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1489BFD2490BE51009EE9FD /* IMChatMessageSendViewCell.xib */; };
+		B1489C7B2491FEFE009EE9FD /* IMChatEmojiBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1489C7A2491FEFE009EE9FD /* IMChatEmojiBarView.swift */; };
+		B1489CAE2491FF13009EE9FD /* IMChatEmojiBarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1489CAD2491FF13009EE9FD /* IMChatEmojiBarView.xib */; };
+		B1489CB12492045D009EE9FD /* IMChatEmojiItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1489CAF2492045D009EE9FD /* IMChatEmojiItemCell.swift */; };
+		B1489CB22492045D009EE9FD /* IMChatEmojiItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1489CB02492045D009EE9FD /* IMChatEmojiItemCell.xib */; };
+		B1489CB624935104009EE9FD /* IMInstantMessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1489CB424935104009EE9FD /* IMInstantMessageViewController.swift */; };
+		B1489CB724935104009EE9FD /* IMInstantMessageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1489CB524935104009EE9FD /* IMInstantMessageViewController.xib */; };
 		B14B339F2356EB1500442968 /* CloudFileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B339E2356EB1500442968 /* CloudFileViewModel.swift */; };
 		B14E07532301137F00AE85A0 /* ContactPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E07522301137F00AE85A0 /* ContactPickerViewController.swift */; };
 		B14E07862301418400AE85A0 /* ContactUnitPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E07852301418400AE85A0 /* ContactUnitPickerViewController.swift */; };
@@ -118,8 +139,20 @@
 		B14E078A230141AC00AE85A0 /* ContactGroupPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E0789230141AC00AE85A0 /* ContactGroupPickerViewController.swift */; };
 		B14E078C230141BE00AE85A0 /* ContactPersonPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E078B230141BE00AE85A0 /* ContactPersonPickerViewController.swift */; };
 		B14E07C523025C6A00AE85A0 /* OOContactExpressAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E07C423025C6A00AE85A0 /* OOContactExpressAPI.swift */; };
+		B14E0C0C2484F1F0008AF6AE /* O2WebsocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E0C0B2484F1F0008AF6AE /* O2WebsocketManager.swift */; };
 		B1534E3F21F712EA00CC8C35 /* O2DemoAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1534E3E21F712EA00CC8C35 /* O2DemoAlertView.swift */; };
 		B158E95E215DD3F500AB2727 /* AIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B158E95D215DD3F500AB2727 /* AIConstants.swift */; };
+		B15BE0BE2499BCEF008CD1DB /* O2RecordVoiceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15BE0BD2499BCEF008CD1DB /* O2RecordVoiceManager.swift */; };
+		B15BE0EE2499DD7E008CD1DB /* IMChatAudioView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15BE0ED2499DD7E008CD1DB /* IMChatAudioView.swift */; };
+		B15BE0F02499DD90008CD1DB /* IMChatAudioView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B15BE0EF2499DD90008CD1DB /* IMChatAudioView.xib */; };
+		B15BE106249A06BF008CD1DB /* libvo-amrwbenc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B15BE0F7249A06BE008CD1DB /* libvo-amrwbenc.a */; };
+		B15BE107249A06BF008CD1DB /* ConvertMp3.m in Sources */ = {isa = PBXBuildFile; fileRef = B15BE0F8249A06BE008CD1DB /* ConvertMp3.m */; };
+		B15BE108249A06BF008CD1DB /* libmp3lame.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B15BE0F9249A06BE008CD1DB /* libmp3lame.a */; };
+		B15BE109249A06BF008CD1DB /* libopencore-amrwb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B15BE100249A06BE008CD1DB /* libopencore-amrwb.a */; };
+		B15BE10A249A06BF008CD1DB /* libopencore-amrnb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B15BE101249A06BE008CD1DB /* libopencore-amrnb.a */; };
+		B15BE10C249A0EFE008CD1DB /* IMAudioView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B15BE10B249A0EFE008CD1DB /* IMAudioView.xib */; };
+		B15BE10E249A107C008CD1DB /* IMAudioView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15BE10D249A107C008CD1DB /* IMAudioView.swift */; };
+		B15BE111249A6002008CD1DB /* AudioPlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15BE110249A6002008CD1DB /* AudioPlayerManager.swift */; };
 		B15D26EC235EF7480092F8B8 /* genstrings.sh in Resources */ = {isa = PBXBuildFile; fileRef = B15D26EB235EF7480092F8B8 /* genstrings.sh */; };
 		B15F80F3210EB93000B81F35 /* OOCalendarMainMonthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F80F2210EB93000B81F35 /* OOCalendarMainMonthViewController.swift */; };
 		B15F8129210EF15E00B81F35 /* OOCalendarEventViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F8128210EF15E00B81F35 /* OOCalendarEventViewController.swift */; };
@@ -166,6 +199,11 @@
 		B1750087233C937E003DA7B9 /* IntExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1750086233C937E003DA7B9 /* IntExtensions.swift */; };
 		B1750089233C9B2C003DA7B9 /* Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1750088233C9B2C003DA7B9 /* Stack.swift */; };
 		B17BF43022B23758009E36E0 /* SkinViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B17BF42F22B23758009E36E0 /* SkinViewController.swift */; };
+		B183987D249AFF64001C6FAA /* IMLocationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B183987C249AFF64001C6FAA /* IMLocationView.xib */; };
+		B18398AD249B00AA001C6FAA /* IMLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18398AC249B00AA001C6FAA /* IMLocationView.swift */; };
+		B18398B0249B079B001C6FAA /* IMLocationChooseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18398AE249B079B001C6FAA /* IMLocationChooseController.swift */; };
+		B18398B1249B079B001C6FAA /* IMLocationChooseController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B18398AF249B079B001C6FAA /* IMLocationChooseController.xib */; };
+		B18398B3249B4154001C6FAA /* IMShowLocationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18398B2249B4154001C6FAA /* IMShowLocationViewController.swift */; };
 		B18FFF5F23756B6C001B2887 /* JPushAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18FFF5E23756B6C001B2887 /* JPushAPI.swift */; };
 		B1908E1422685E8F00D75632 /* O2WebViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1908E1322685E8F00D75632 /* O2WebViewModels.swift */; };
 		B1908E4C22687B1A00D75632 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1908E4E22687B1A00D75632 /* Localizable.strings */; };
@@ -220,6 +258,9 @@
 		B1E95FA72375155F004876B7 /* CloudFileBaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E95FA62375155F004876B7 /* CloudFileBaseVC.swift */; };
 		B1EE2CCE2281729400842F48 /* QDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1EE2CCD2281729400842F48 /* QDatePicker.swift */; };
 		B1EE2CD02281771600842F48 /* O2JsApiUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1EE2CCF2281771600842F48 /* O2JsApiUtil.swift */; };
+		B1F6CDBE24A88D26005CB1E0 /* BBSViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F6CDBD24A88D26005CB1E0 /* BBSViewModel.swift */; };
+		B1F6CDEE24A893B6005CB1E0 /* BBSSubjectAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F6CDED24A893B6005CB1E0 /* BBSSubjectAttachmentViewController.swift */; };
+		B1F6CDF024A89836005CB1E0 /* BBSSubjectAttachmentViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F6CDEF24A89836005CB1E0 /* BBSSubjectAttachmentViewCell.swift */; };
 		B1FAE9E12115F95800981A25 /* OOCalendarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FAE9E02115F95800981A25 /* OOCalendarViewController.swift */; };
 		B1FAFD442105C23B008A0CDF /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FAFD432105C23B008A0CDF /* Operators.swift */; };
 		B1FB9FAE2302891F00A90722 /* ContactPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FB9FAD2302891F00A90722 /* ContactPickerViewModel.swift */; };
@@ -1008,13 +1049,6 @@
 			remoteGlobalIDString = 5F72A30590D0D18EC2C2BBC2D902C6D1;
 			remoteInfo = BetterSegmentedControl;
 		};
-		B10AC59221058DAE00179587 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = E18B1C0DEBD04E12A5DC8B40B7BF5150;
-			remoteInfo = BSGridCollectionViewLayout;
-		};
 		B10AC59421058DAE00179587 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
@@ -1022,13 +1056,6 @@
 			remoteGlobalIDString = D13C7C5DC1991163C85D47D9B72B42DD;
 			remoteInfo = BSImagePicker;
 		};
-		B10AC59621058DAE00179587 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 797083F5F27AFF01045BE4809698B5C1;
-			remoteInfo = "BSImagePicker-BSImagePicker";
-		};
 		B10AC59A21058DAE00179587 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
@@ -1211,6 +1238,13 @@
 			remoteGlobalIDString = 183276F1FBCA05D9F840C64172C84A44;
 			remoteInfo = YHPopupView;
 		};
+		B1173A582488C3DD005075F0 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 891B2270823847ED23F2ECFC28F935EC;
+			remoteInfo = Starscream;
+		};
 		B14A2292224CBC2E00745E0A /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
@@ -1232,13 +1266,6 @@
 			remoteGlobalIDString = 85979644862830BD1DFFD1D60F0D64AE;
 			remoteInfo = RxAtomic;
 		};
-		B1BC8CD5216B1F0B00AF571F /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 8B824035EFF627D7343420A8E0BC044B;
-			remoteInfo = BSImageView;
-		};
 		B1F79C77233B5F9B004D0AEE /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = E4E7755421017DB4006ED7FC /* Pods.xcodeproj */;
@@ -1339,6 +1366,7 @@
 		10069E72107080DCAD68970B /* Pods_O2Platform.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_O2Platform.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		47A96D30743BECAB12B424CE /* Pods-O2Platform.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-O2Platform.release.xcconfig"; path = "Pods/Target Support Files/Pods-O2Platform/Pods-O2Platform.release.xcconfig"; sourceTree = "<group>"; };
 		4F1BA982094EC6172ACF8F99 /* Pods-O2Platform.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-O2Platform.debug.xcconfig"; path = "Pods/Target Support Files/Pods-O2Platform/Pods-O2Platform.debug.xcconfig"; sourceTree = "<group>"; };
+		8840A991248CDC9D005970A5 /* OOCalendarEditRemarkViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OOCalendarEditRemarkViewController.swift; sourceTree = "<group>"; };
 		A043051A1F99CFD500740423 /* MailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MailViewController.swift; sourceTree = "<group>"; };
 		B1015DDA2272B5DB00C1A7E6 /* O2BaseJsMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2BaseJsMessageHandler.swift; sourceTree = "<group>"; };
 		B104303621464C690011B08E /* ai.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ai.storyboard; sourceTree = "<group>"; };
@@ -1358,6 +1386,14 @@
 		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; };
 		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>"; };
 		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>"; };
@@ -1409,6 +1445,18 @@
 		B13A011F236935BC00025F3B /* O2CloudFileInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2CloudFileInfo.swift; sourceTree = "<group>"; };
 		B142B080230FB56400E7D127 /* MimeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MimeType.swift; sourceTree = "<group>"; };
 		B142B082230FB58B00E7D127 /* Swime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Swime.swift; sourceTree = "<group>"; };
+		B1489B1A248E0F4D009EE9FD /* IMChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMChatViewController.swift; sourceTree = "<group>"; };
+		B1489B1B248E0F4D009EE9FD /* IMChatViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMChatViewController.xib; sourceTree = "<group>"; };
+		B1489B4F248E192D009EE9FD /* IMChatMessageViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMChatMessageViewCell.swift; sourceTree = "<group>"; };
+		B1489B50248E192D009EE9FD /* IMChatMessageViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMChatMessageViewCell.xib; sourceTree = "<group>"; };
+		B1489BFC2490BE51009EE9FD /* IMChatMessageSendViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMChatMessageSendViewCell.swift; sourceTree = "<group>"; };
+		B1489BFD2490BE51009EE9FD /* IMChatMessageSendViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMChatMessageSendViewCell.xib; sourceTree = "<group>"; };
+		B1489C7A2491FEFE009EE9FD /* IMChatEmojiBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMChatEmojiBarView.swift; sourceTree = "<group>"; };
+		B1489CAD2491FF13009EE9FD /* IMChatEmojiBarView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMChatEmojiBarView.xib; sourceTree = "<group>"; };
+		B1489CAF2492045D009EE9FD /* IMChatEmojiItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMChatEmojiItemCell.swift; sourceTree = "<group>"; };
+		B1489CB02492045D009EE9FD /* IMChatEmojiItemCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMChatEmojiItemCell.xib; sourceTree = "<group>"; };
+		B1489CB424935104009EE9FD /* IMInstantMessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMInstantMessageViewController.swift; sourceTree = "<group>"; };
+		B1489CB524935104009EE9FD /* IMInstantMessageViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMInstantMessageViewController.xib; sourceTree = "<group>"; };
 		B14B339E2356EB1500442968 /* CloudFileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileViewModel.swift; sourceTree = "<group>"; };
 		B14E07522301137F00AE85A0 /* ContactPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactPickerViewController.swift; sourceTree = "<group>"; };
 		B14E07852301418400AE85A0 /* ContactUnitPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactUnitPickerViewController.swift; sourceTree = "<group>"; };
@@ -1416,8 +1464,28 @@
 		B14E0789230141AC00AE85A0 /* ContactGroupPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactGroupPickerViewController.swift; sourceTree = "<group>"; };
 		B14E078B230141BE00AE85A0 /* ContactPersonPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactPersonPickerViewController.swift; sourceTree = "<group>"; };
 		B14E07C423025C6A00AE85A0 /* OOContactExpressAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OOContactExpressAPI.swift; sourceTree = "<group>"; };
+		B14E0C0B2484F1F0008AF6AE /* O2WebsocketManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2WebsocketManager.swift; sourceTree = "<group>"; };
 		B1534E3E21F712EA00CC8C35 /* O2DemoAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2DemoAlertView.swift; sourceTree = "<group>"; };
 		B158E95D215DD3F500AB2727 /* AIConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIConstants.swift; sourceTree = "<group>"; };
+		B15BE0BD2499BCEF008CD1DB /* O2RecordVoiceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2RecordVoiceManager.swift; sourceTree = "<group>"; };
+		B15BE0ED2499DD7E008CD1DB /* IMChatAudioView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMChatAudioView.swift; sourceTree = "<group>"; };
+		B15BE0EF2499DD90008CD1DB /* IMChatAudioView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMChatAudioView.xib; sourceTree = "<group>"; };
+		B15BE0F2249A06BE008CD1DB /* AmrCodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AmrCodec.h; sourceTree = "<group>"; };
+		B15BE0F5249A06BE008CD1DB /* enc_if.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = enc_if.h; sourceTree = "<group>"; };
+		B15BE0F7249A06BE008CD1DB /* libvo-amrwbenc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libvo-amrwbenc.a"; sourceTree = "<group>"; };
+		B15BE0F8249A06BE008CD1DB /* ConvertMp3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConvertMp3.m; sourceTree = "<group>"; };
+		B15BE0F9249A06BE008CD1DB /* libmp3lame.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libmp3lame.a; sourceTree = "<group>"; };
+		B15BE0FA249A06BE008CD1DB /* ConvertMp3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertMp3.h; sourceTree = "<group>"; };
+		B15BE0FD249A06BE008CD1DB /* if_rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_rom.h; sourceTree = "<group>"; };
+		B15BE0FE249A06BE008CD1DB /* dec_if.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dec_if.h; sourceTree = "<group>"; };
+		B15BE100249A06BE008CD1DB /* libopencore-amrwb.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopencore-amrwb.a"; sourceTree = "<group>"; };
+		B15BE101249A06BE008CD1DB /* libopencore-amrnb.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopencore-amrnb.a"; sourceTree = "<group>"; };
+		B15BE103249A06BE008CD1DB /* interf_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interf_dec.h; sourceTree = "<group>"; };
+		B15BE104249A06BE008CD1DB /* interf_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interf_enc.h; sourceTree = "<group>"; };
+		B15BE105249A06BE008CD1DB /* lame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lame.h; sourceTree = "<group>"; };
+		B15BE10B249A0EFE008CD1DB /* IMAudioView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMAudioView.xib; sourceTree = "<group>"; };
+		B15BE10D249A107C008CD1DB /* IMAudioView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMAudioView.swift; sourceTree = "<group>"; };
+		B15BE110249A6002008CD1DB /* AudioPlayerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerManager.swift; sourceTree = "<group>"; };
 		B15D26BF235EF0850092F8B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/CloudFile.storyboard; sourceTree = "<group>"; };
 		B15D26EA235EF0940092F8B8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/CloudFile.strings; sourceTree = "<group>"; };
 		B15D26EB235EF7480092F8B8 /* genstrings.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = genstrings.sh; sourceTree = "<group>"; };
@@ -1467,6 +1535,11 @@
 		B1750086233C937E003DA7B9 /* IntExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntExtensions.swift; sourceTree = "<group>"; };
 		B1750088233C9B2C003DA7B9 /* Stack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stack.swift; sourceTree = "<group>"; };
 		B17BF42F22B23758009E36E0 /* SkinViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkinViewController.swift; sourceTree = "<group>"; };
+		B183987C249AFF64001C6FAA /* IMLocationView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMLocationView.xib; sourceTree = "<group>"; };
+		B18398AC249B00AA001C6FAA /* IMLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMLocationView.swift; sourceTree = "<group>"; };
+		B18398AE249B079B001C6FAA /* IMLocationChooseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMLocationChooseController.swift; sourceTree = "<group>"; };
+		B18398AF249B079B001C6FAA /* IMLocationChooseController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IMLocationChooseController.xib; sourceTree = "<group>"; };
+		B18398B2249B4154001C6FAA /* IMShowLocationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMShowLocationViewController.swift; sourceTree = "<group>"; };
 		B18FFF5E23756B6C001B2887 /* JPushAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JPushAPI.swift; sourceTree = "<group>"; };
 		B1908E1322685E8F00D75632 /* O2WebViewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2WebViewModels.swift; sourceTree = "<group>"; };
 		B1908E4D22687B1A00D75632 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -1524,6 +1597,9 @@
 		B1E95FA62375155F004876B7 /* CloudFileBaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileBaseVC.swift; sourceTree = "<group>"; };
 		B1EE2CCD2281729400842F48 /* QDatePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QDatePicker.swift; sourceTree = "<group>"; };
 		B1EE2CCF2281771600842F48 /* O2JsApiUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2JsApiUtil.swift; sourceTree = "<group>"; };
+		B1F6CDBD24A88D26005CB1E0 /* BBSViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BBSViewModel.swift; sourceTree = "<group>"; };
+		B1F6CDED24A893B6005CB1E0 /* BBSSubjectAttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BBSSubjectAttachmentViewController.swift; sourceTree = "<group>"; };
+		B1F6CDEF24A89836005CB1E0 /* BBSSubjectAttachmentViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BBSSubjectAttachmentViewCell.swift; sourceTree = "<group>"; };
 		B1FAE9E02115F95800981A25 /* OOCalendarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OOCalendarViewController.swift; sourceTree = "<group>"; };
 		B1FAFD432105C23B008A0CDF /* Operators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = "<group>"; };
 		B1FB9FAD2302891F00A90722 /* ContactPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactPickerViewModel.swift; sourceTree = "<group>"; };
@@ -2342,6 +2418,7 @@
 				B1BC8CDA216B3D5F00AF571F /* libc++.tbd in Frameworks */,
 				B130E648223B774D00B68354 /* image_picker.framework in Frameworks */,
 				E4D23119209EF74D00837868 /* libssl.a in Frameworks */,
+				B15BE106249A06BF008CD1DB /* libvo-amrwbenc.a in Frameworks */,
 				E4C24A222080A44300E426B0 /* CFNetwork.framework in Frameworks */,
 				B1AE4E2621A3DCC100183FCD /* O2OA_Auth_SDK.framework in Frameworks */,
 				B130E64A223B774D00B68354 /* shared_preferences.framework in Frameworks */,
@@ -2352,13 +2429,16 @@
 				E40958C7208051DE000FECC3 /* CoreTelephony.framework in Frameworks */,
 				E4418C5F1DDC1AC80066348D /* CoreGraphics.framework in Frameworks */,
 				E4375B12207CABAB0065A880 /* SystemConfiguration.framework in Frameworks */,
+				B15BE108249A06BF008CD1DB /* libmp3lame.a in Frameworks */,
 				B19BCE8A2228272500BD454C /* App.framework in Frameworks */,
 				B130E649223B774D00B68354 /* path_provider.framework in Frameworks */,
 				E4375B1A207CABE90065A880 /* AudioToolbox.framework in Frameworks */,
+				B15BE10A249A06BF008CD1DB /* libopencore-amrnb.a in Frameworks */,
 				E4375B14207CABB30065A880 /* AddressBook.framework in Frameworks */,
 				E4375B18207CABD20065A880 /* AssetsLibrary.framework in Frameworks */,
 				E4375B16207CABC90065A880 /* CoreMotion.framework in Frameworks */,
 				E4375B10207CABA30065A880 /* CoreLocation.framework in Frameworks */,
+				B15BE109249A06BF008CD1DB /* libopencore-amrwb.a in Frameworks */,
 				E4375B0E207CAB980065A880 /* CoreData.framework in Frameworks */,
 				E4375B0C207CAB860065A880 /* libz.tbd in Frameworks */,
 				E4375B08207CAB770065A880 /* libsqlite3.0.tbd in Frameworks */,
@@ -2483,10 +2563,7 @@
 				B10AC58D21058DAE00179587 /* AlamofireNetworkActivityIndicator.framework */,
 				B10AC58F21058DAE00179587 /* AlamofireObjectMapper.framework */,
 				B10AC59121058DAE00179587 /* BetterSegmentedControl.framework */,
-				B10AC59321058DAE00179587 /* BSGridCollectionViewLayout.framework */,
 				B10AC59521058DAE00179587 /* BSImagePicker.framework */,
-				B10AC59721058DAE00179587 /* BSImagePicker.bundle */,
-				B1BC8CD6216B1F0B00AF571F /* BSImageView.framework */,
 				B10AC59B21058DAE00179587 /* Charts.framework */,
 				B1F79C78233B5F9B004D0AEE /* Chrysan.framework */,
 				B1F79C7A233B5F9B004D0AEE /* Chrysan.bundle */,
@@ -2514,6 +2591,7 @@
 				B10AC5D721058DAE00179587 /* RxSwift.framework */,
 				B10AC5D921058DAE00179587 /* SDWebImage.framework */,
 				B10AC5DF21058DAE00179587 /* SnapKit.framework */,
+				B1173A592488C3DD005075F0 /* Starscream.framework */,
 				B10AC5E321058DAE00179587 /* SwiftValidator.framework */,
 				B10AC5E521058DAE00179587 /* SwiftyJSON.framework */,
 				B10AC5E721058DAE00179587 /* SwiftyTimer.framework */,
@@ -2524,6 +2602,64 @@
 			name = Products;
 			sourceTree = "<group>";
 		};
+		B1173A262488C3DD005075F0 /* IM-聊天 */ = {
+			isa = PBXGroup;
+			children = (
+				B1173A642488CD37005075F0 /* View */,
+				B1173A612488C8D3005075F0 /* Model */,
+				B1173A5A2488C546005075F0 /* IMConversationListViewController.swift */,
+				B1173A5F2488C82F005075F0 /* IMViewModel.swift */,
+				B1173A692488D4AD005075F0 /* O2IM.swift */,
+				B1489B1A248E0F4D009EE9FD /* IMChatViewController.swift */,
+				B1489B1B248E0F4D009EE9FD /* IMChatViewController.xib */,
+				B1489CB424935104009EE9FD /* IMInstantMessageViewController.swift */,
+				B1489CB524935104009EE9FD /* IMInstantMessageViewController.xib */,
+				B18398AE249B079B001C6FAA /* IMLocationChooseController.swift */,
+				B18398AF249B079B001C6FAA /* IMLocationChooseController.xib */,
+				B18398B2249B4154001C6FAA /* IMShowLocationViewController.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 */,
+				B1489B4F248E192D009EE9FD /* IMChatMessageViewCell.swift */,
+				B1489B50248E192D009EE9FD /* IMChatMessageViewCell.xib */,
+				B1489BFC2490BE51009EE9FD /* IMChatMessageSendViewCell.swift */,
+				B1489BFD2490BE51009EE9FD /* IMChatMessageSendViewCell.xib */,
+				B1489C7A2491FEFE009EE9FD /* IMChatEmojiBarView.swift */,
+				B1489CAD2491FF13009EE9FD /* IMChatEmojiBarView.xib */,
+				B1489CAF2492045D009EE9FD /* IMChatEmojiItemCell.swift */,
+				B1489CB02492045D009EE9FD /* IMChatEmojiItemCell.xib */,
+				B15BE0ED2499DD7E008CD1DB /* IMChatAudioView.swift */,
+				B15BE0EF2499DD90008CD1DB /* IMChatAudioView.xib */,
+				B15BE10B249A0EFE008CD1DB /* IMAudioView.xib */,
+				B15BE10D249A107C008CD1DB /* IMAudioView.swift */,
+				B183987C249AFF64001C6FAA /* IMLocationView.xib */,
+				B18398AC249B00AA001C6FAA /* IMLocationView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		B12FD1502283CDF400E636BA /* theme */ = {
 			isa = PBXGroup;
 			children = (
@@ -2591,6 +2727,82 @@
 			path = vm;
 			sourceTree = "<group>";
 		};
+		B15BE0F1249A06BE008CD1DB /* lame */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE0F2249A06BE008CD1DB /* AmrCodec.h */,
+				B15BE0F3249A06BE008CD1DB /* vo-amrwbenc */,
+				B15BE0F8249A06BE008CD1DB /* ConvertMp3.m */,
+				B15BE0F9249A06BE008CD1DB /* libmp3lame.a */,
+				B15BE0FA249A06BE008CD1DB /* ConvertMp3.h */,
+				B15BE0FB249A06BE008CD1DB /* opencore-amr */,
+				B15BE105249A06BE008CD1DB /* lame.h */,
+			);
+			path = lame;
+			sourceTree = "<group>";
+		};
+		B15BE0F3249A06BE008CD1DB /* vo-amrwbenc */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE0F4249A06BE008CD1DB /* vo-amrwbenc */,
+				B15BE0F6249A06BE008CD1DB /* lib */,
+			);
+			path = "vo-amrwbenc";
+			sourceTree = "<group>";
+		};
+		B15BE0F4249A06BE008CD1DB /* vo-amrwbenc */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE0F5249A06BE008CD1DB /* enc_if.h */,
+			);
+			path = "vo-amrwbenc";
+			sourceTree = "<group>";
+		};
+		B15BE0F6249A06BE008CD1DB /* lib */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE0F7249A06BE008CD1DB /* libvo-amrwbenc.a */,
+			);
+			path = lib;
+			sourceTree = "<group>";
+		};
+		B15BE0FB249A06BE008CD1DB /* opencore-amr */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE0FC249A06BE008CD1DB /* opencore-amrwb */,
+				B15BE0FF249A06BE008CD1DB /* lib */,
+				B15BE102249A06BE008CD1DB /* opencore-amrnb */,
+			);
+			path = "opencore-amr";
+			sourceTree = "<group>";
+		};
+		B15BE0FC249A06BE008CD1DB /* opencore-amrwb */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE0FD249A06BE008CD1DB /* if_rom.h */,
+				B15BE0FE249A06BE008CD1DB /* dec_if.h */,
+			);
+			path = "opencore-amrwb";
+			sourceTree = "<group>";
+		};
+		B15BE0FF249A06BE008CD1DB /* lib */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE100249A06BE008CD1DB /* libopencore-amrwb.a */,
+				B15BE101249A06BE008CD1DB /* libopencore-amrnb.a */,
+			);
+			path = lib;
+			sourceTree = "<group>";
+		};
+		B15BE102249A06BE008CD1DB /* opencore-amrnb */ = {
+			isa = PBXGroup;
+			children = (
+				B15BE103249A06BE008CD1DB /* interf_dec.h */,
+				B15BE104249A06BE008CD1DB /* interf_enc.h */,
+			);
+			path = "opencore-amrnb";
+			sourceTree = "<group>";
+		};
 		B165CC9D2241DB9F00373B66 /* DatePickerDialogSwift */ = {
 			isa = PBXGroup;
 			children = (
@@ -2683,6 +2895,7 @@
 				B15F8128210EF15E00B81F35 /* OOCalendarEventViewController.swift */,
 				B1C19024211437E200935829 /* OOCalendarLeftMenuController.swift */,
 				B1FAE9E02115F95800981A25 /* OOCalendarViewController.swift */,
+				8840A991248CDC9D005970A5 /* OOCalendarEditRemarkViewController.swift */,
 			);
 			path = Controller;
 			sourceTree = "<group>";
@@ -2785,6 +2998,7 @@
 		B1F79C44233B5F9B004D0AEE /* Resources */ = {
 			isa = PBXGroup;
 			children = (
+				B1173B2C2489F48C005075F0 /* O2Emoji.bundle */,
 				B19776E7217D9D810019F3A8 /* beep.wav */,
 				E4B888231D9D48F1002E1A46 /* images */,
 				E4B888291D9D48F1002E1A46 /* 隶变体.ttf */,
@@ -2838,6 +3052,9 @@
 				B13A011023692A8B00025F3B /* O2CloudFileManager.swift */,
 				B1E0BAA02378FC01001D741F /* O2JPushManager.swift */,
 				B1ABAA0B237E498C0027EC48 /* O2VersionManager.swift */,
+				B14E0C0B2484F1F0008AF6AE /* O2WebsocketManager.swift */,
+				B15BE0BD2499BCEF008CD1DB /* O2RecordVoiceManager.swift */,
+				B15BE110249A6002008CD1DB /* AudioPlayerManager.swift */,
 			);
 			path = Manager;
 			sourceTree = "<group>";
@@ -2869,6 +3086,7 @@
 				E45CD4211DFE503C008F99AD /* Scan-二维码扫码 */,
 				E4C24C22208D7EDE00E426B0 /* Contact-通讯录 */,
 				E4B8875E1D9D48F1002E1A46 /* contacts */,
+				B1173A262488C3DD005075F0 /* IM-聊天 */,
 				E428AF3720A95D3800D964B9 /* NewAttance-考勤打卡 */,
 				E40E246E20B7DA3C009F8BE7 /* meeting-会议 */,
 				B19091FD2107145F009A7906 /* Calendar-日程管理 */,
@@ -3076,6 +3294,7 @@
 				E41441D71DCAC5C600E3DDA3 /* c */,
 				E41441D81DCAC5C600E3DDA3 /* m */,
 				E41441D91DCAC5C600E3DDA3 /* v */,
+				B1F6CDBD24A88D26005CB1E0 /* BBSViewModel.swift */,
 			);
 			path = "BBS-论坛";
 			sourceTree = "<group>";
@@ -3089,6 +3308,7 @@
 				E46E6BF61DD2C8B500AB7561 /* BBSReplySubjectViewController.swift */,
 				E4418C6C1DDD5D6A0066348D /* BBSSubjectCreateTableViewController.swift */,
 				E47EF77C1DDDC78300B5B8C2 /* BBSSubjectContentViewController.swift */,
+				B1F6CDED24A893B6005CB1E0 /* BBSSubjectAttachmentViewController.swift */,
 			);
 			path = c;
 			sourceTree = "<group>";
@@ -3108,6 +3328,7 @@
 				E41441E01DCB248C00E3DDA3 /* BBSForumCell.swift */,
 				E4740ABE1DCC267100686780 /* BBSHeaderCollectionReusableView.swift */,
 				E4740AC01DCC45A300686780 /* SubjectTableViewCell.swift */,
+				B1F6CDEF24A89836005CB1E0 /* BBSSubjectAttachmentViewCell.swift */,
 			);
 			path = v;
 			sourceTree = "<group>";
@@ -3405,6 +3626,7 @@
 		E4B69721207602840062F6E8 /* O2API */ = {
 			isa = PBXGroup;
 			children = (
+				B1173A5C2488C568005075F0 /* Communicate */,
 				B18FFF3323756B24001B2887 /* JpushAPI */,
 				B107453721A52B9A0015F1B2 /* PersonalAPI */,
 				B1B6A8F7217710A400C10F3C /* FaceRecognizeAPI */,
@@ -3816,6 +4038,7 @@
 		E4B887821D9D48F1002E1A46 /* Framework */ = {
 			isa = PBXGroup;
 			children = (
+				B15BE0F1249A06BE008CD1DB /* lame */,
 				E4B69721207602840062F6E8 /* O2API */,
 				E4B8892E1D9D6308002E1A46 /* Utils */,
 				B142B04E230FB53E00E7D127 /* MagicBytesMimeType */,
@@ -5091,13 +5314,6 @@
 			remoteRef = B10AC59021058DAE00179587 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		B10AC59321058DAE00179587 /* BSGridCollectionViewLayout.framework */ = {
-			isa = PBXReferenceProxy;
-			fileType = wrapper.framework;
-			path = BSGridCollectionViewLayout.framework;
-			remoteRef = B10AC59221058DAE00179587 /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
 		B10AC59521058DAE00179587 /* BSImagePicker.framework */ = {
 			isa = PBXReferenceProxy;
 			fileType = wrapper.framework;
@@ -5105,13 +5321,6 @@
 			remoteRef = B10AC59421058DAE00179587 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		B10AC59721058DAE00179587 /* BSImagePicker.bundle */ = {
-			isa = PBXReferenceProxy;
-			fileType = wrapper.cfbundle;
-			path = BSImagePicker.bundle;
-			remoteRef = B10AC59621058DAE00179587 /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
 		B10AC59B21058DAE00179587 /* Charts.framework */ = {
 			isa = PBXReferenceProxy;
 			fileType = wrapper.framework;
@@ -5294,6 +5503,13 @@
 			remoteRef = B10AC5F021058DAE00179587 /* PBXContainerItemProxy */;
 			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 */ = {
 			isa = PBXReferenceProxy;
 			fileType = wrapper.framework;
@@ -5315,13 +5531,6 @@
 			remoteRef = B1AE4E6321A3F53A00183FCD /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		B1BC8CD6216B1F0B00AF571F /* BSImageView.framework */ = {
-			isa = PBXReferenceProxy;
-			fileType = wrapper.framework;
-			path = BSImageView.framework;
-			remoteRef = B1BC8CD5216B1F0B00AF571F /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
 		B1F79C78233B5F9B004D0AEE /* Chrysan.framework */ = {
 			isa = PBXReferenceProxy;
 			fileType = wrapper.framework;
@@ -5364,6 +5573,7 @@
 				E46E6CA01DD41F5D00AB7561 /* ZSSrightjustify@2x.png in Resources */,
 				E46E6CA91DD41F5D00AB7561 /* ZSStextcolor.png in Resources */,
 				E4C24C1F2085849500E426B0 /* o2Theme.bundle in Resources */,
+				B15BE0F02499DD90008CD1DB /* IMChatAudioView.xib in Resources */,
 				E4B781671DF8E556007B58A9 /* information.storyboard in Resources */,
 				E46E6CAA1DD41F5D00AB7561 /* ZSStextcolor@2x.png in Resources */,
 				E40E24C020B7DA3C009F8BE7 /* OOMeetingRoomTableHeaderView.xib in Resources */,
@@ -5384,6 +5594,7 @@
 				E4C24B4920844F3C00E426B0 /* JCMessageImageCollectionViewCell.xib in Resources */,
 				E4C24C1820844F5200E426B0 /* yh_image_picked@2x.png in Resources */,
 				E45755A61E0BA72E00EC44F4 /* qrcode_scan_part_net.png in Resources */,
+				B1489B52248E192D009EE9FD /* IMChatMessageViewCell.xib in Resources */,
 				E46E6C721DD41F5D00AB7561 /* ZSSfonts@2x.png in Resources */,
 				E46E6C6E1DD41F5D00AB7561 /* ZSScenterjustify@2x.png in Resources */,
 				B1298E822366B2E7006E9236 /* CFImageViewCell.xib in Resources */,
@@ -5398,12 +5609,14 @@
 				E4B8871E1D9D477A002E1A46 /* Assets.xcassets in Resources */,
 				E46E6CA51DD41F5D00AB7561 /* ZSSsuperscript.png in Resources */,
 				E4C24BC020844F3C00E426B0 /* 定位2.png in Resources */,
+				B1173A682488CD5B005075F0 /* IMConversationItemCell.xib in Resources */,
 				B197771D217D9D810019F3A8 /* beep.wav in Resources */,
 				E40E24C920B7DA3C009F8BE7 /* OOMeetingPersonTableViewCell.xib in Resources */,
 				E4B2321C20B3E94E0082F30A /* OOAttanceCheckinPromptView.xib in Resources */,
 				E4C24B6120844F3C00E426B0 /* addressCode in Resources */,
 				E4B697D920764A2D0062F6E8 /* myshareEditorByPerson.json in Resources */,
 				E457559D1E0BA72E00EC44F4 /* qrcode_scan_btn_flash_down@2x.png in Resources */,
+				B1489B1D248E0F4D009EE9FD /* IMChatViewController.xib in Resources */,
 				E4C24C1A20844F5200E426B0 /* emoticons.bundle in Resources */,
 				E4B888E11D9D48F1002E1A46 /* contacts.storyboard in Resources */,
 				E45755A51E0BA72E00EC44F4 /* qrcode_scan_light_green@2x.png in Resources */,
@@ -5476,6 +5689,7 @@
 				E46E6CB51DD41F5D00AB7561 /* jQuery.js in Resources */,
 				E46E6C801DD41F5D00AB7561 /* ZSSh6@2x.png in Resources */,
 				E46E6C971DD41F5D00AB7561 /* ZSSparagraph.png in Resources */,
+				B1489CAE2491FF13009EE9FD /* IMChatEmojiBarView.xib in Resources */,
 				E4B888E01D9D48F1002E1A46 /* apps.storyboard in Resources */,
 				E428AF6120AD4DCE00D964B9 /* OOAttanceCheckInController.xib in Resources */,
 				B165CD5D2242093500373B66 /* SourceSansPro-Regular.ttf in Resources */,
@@ -5488,6 +5702,7 @@
 				E46E6C6D1DD41F5D00AB7561 /* ZSScenterjustify.png in Resources */,
 				E40E24BE20B7DA3C009F8BE7 /* OOMeetingRoomDeviceListView.xib in Resources */,
 				E4D2312B20A29E2700837868 /* OOAppMainCollectionHeaderView.xib in Resources */,
+				B18398B1249B079B001C6FAA /* IMLocationChooseController.xib in Resources */,
 				E45755A31E0BA72E00EC44F4 /* qrcode_scan_btn_scan_off@2x.png in Resources */,
 				E46E6CA71DD41F5D00AB7561 /* ZSStable.png in Resources */,
 				E4C24BC120844F3C00E426B0 /* jiantou2@2x.png in Resources */,
@@ -5497,6 +5712,7 @@
 				B165CD682242093500373B66 /* Montserrat-Regular.ttf in Resources */,
 				E41441DB1DCAC5D700E3DDA3 /* bbs.storyboard in Resources */,
 				E46E6C9B1DD41F5D00AB7561 /* ZSSquicklink.png in Resources */,
+				B1489CB22492045D009EE9FD /* IMChatEmojiItemCell.xib in Resources */,
 				E45755A91E0BA72E00EC44F4 /* qrcode_Scan_weixin_Line@2x.png in Resources */,
 				E4B697B920764A2D0062F6E8 /* buildlist.json in Resources */,
 				E4C24B4320844F3C00E426B0 /* defaultTheme.bundle in Resources */,
@@ -5504,6 +5720,7 @@
 				E46E6CAF1DD41F5D00AB7561 /* ZSSunlink.png in Resources */,
 				E40E24C320B7DA3C009F8BE7 /* OOMeetingInforItemCell.xib in Resources */,
 				E46E6C811DD41F5D00AB7561 /* ZSShorizontalrule.png in Resources */,
+				B1173B5E2489F48C005075F0 /* O2Emoji.bundle in Resources */,
 				E46E6C7F1DD41F5D00AB7561 /* ZSSh6.png in Resources */,
 				E46E6C9C1DD41F5D00AB7561 /* ZSSquicklink@2x.png in Resources */,
 				E46E6C901DD41F5D00AB7561 /* ZSSleftjustify@2x.png in Resources */,
@@ -5519,6 +5736,7 @@
 				E4B889071D9D4C7E002E1A46 /* podfile in Resources */,
 				E46E6C841DD41F5D00AB7561 /* ZSSimage@2x.png in Resources */,
 				E4B697012075DE5F0062F6E8 /* OOGuidePageController.xib in Resources */,
+				B1489BFF2490BE51009EE9FD /* IMChatMessageSendViewCell.xib in Resources */,
 				E4D23110209C40F600837868 /* OOPersonCollectionViewCell.xib in Resources */,
 				B167F7672362C60200F182B8 /* CloudFileMoveFolderCell.xib in Resources */,
 				E46E6CAD1DD41F5D00AB7561 /* ZSSundo.png in Resources */,
@@ -5529,17 +5747,20 @@
 				E46E6C6F1DD41F5D00AB7561 /* ZSSclearstyle.png in Resources */,
 				E46E6CB11DD41F5D00AB7561 /* ZSSunorderedlist.png in Resources */,
 				E40E246D20B68AF6009F8BE7 /* OOAttandanceTotalHeaderView.xib in Resources */,
+				B1489CB724935104009EE9FD /* IMInstantMessageViewController.xib in Resources */,
 				E4C24C1720844F5200E426B0 /* yh_image_no_picked@3x.png in Resources */,
 				E46E6C7E1DD41F5D00AB7561 /* ZSSh5@2x.png in Resources */,
 				E46E6C871DD41F5D00AB7561 /* ZSSindent.png in Resources */,
 				E46E6CC31DD41F5D00AB7561 /* ZSSRichTextEditor.js in Resources */,
 				E4C24BC220844F3C00E426B0 /* icon_baidu_marker.png in Resources */,
 				B12FD1872283CE1D00E636BA /* red.plist in Resources */,
+				B183987D249AFF64001C6FAA /* IMLocationView.xib in Resources */,
 				E4B888E21D9D48F1002E1A46 /* cloudStorage.storyboard in Resources */,
 				E46E6C8E1DD41F5D00AB7561 /* ZSSkeyboard@2x.png in Resources */,
 				E4C24C49208D7EDE00E426B0 /* OOContactSearchSectionHeaderView.xib in Resources */,
 				E46E6C691DD41F5D00AB7561 /* ZSSbgcolor.png in Resources */,
 				E428AF4620A95FE800D964B9 /* OOAttanceTotalController.xib in Resources */,
+				B15BE10C249A0EFE008CD1DB /* IMAudioView.xib in Resources */,
 				B165CD6B2242093500373B66 /* Info.plist in Resources */,
 				E4C24C48208D7EDE00E426B0 /* OOContactGroupHeaderView.xib in Resources */,
 				E4B888DB1D9D48F1002E1A46 /* 隶变体.ttf in Resources */,
@@ -5601,9 +5822,7 @@
 				"${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework",
 				"${BUILT_PRODUCTS_DIR}/AlamofireNetworkActivityIndicator/AlamofireNetworkActivityIndicator.framework",
 				"${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper/AlamofireObjectMapper.framework",
-				"${BUILT_PRODUCTS_DIR}/BSGridCollectionViewLayout/BSGridCollectionViewLayout.framework",
 				"${BUILT_PRODUCTS_DIR}/BSImagePicker/BSImagePicker.framework",
-				"${BUILT_PRODUCTS_DIR}/BSImageView/BSImageView.framework",
 				"${BUILT_PRODUCTS_DIR}/BetterSegmentedControl/BetterSegmentedControl.framework",
 				"${BUILT_PRODUCTS_DIR}/Charts/Charts.framework",
 				"${BUILT_PRODUCTS_DIR}/Chrysan/Chrysan.framework",
@@ -5630,6 +5849,7 @@
 				"${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
 				"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
 				"${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework",
+				"${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework",
 				"${BUILT_PRODUCTS_DIR}/SwiftValidator/SwiftValidator.framework",
 				"${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework",
 				"${BUILT_PRODUCTS_DIR}/SwiftyTimer/SwiftyTimer.framework",
@@ -5643,9 +5863,7 @@
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireNetworkActivityIndicator.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireObjectMapper.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BSGridCollectionViewLayout.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BSImagePicker.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BSImageView.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BetterSegmentedControl.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Charts.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Chrysan.framework",
@@ -5672,6 +5890,7 @@
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftValidator.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyTimer.framework",
@@ -5739,6 +5958,7 @@
 				E4B8889E1D9D48F1002E1A46 /* MJRefreshFooter.m in Sources */,
 				E4F45446208EC359002FBC32 /* OOPersonsViewController.swift in Sources */,
 				09E02E841F16319600579887 /* CGSize+Swift.swift in Sources */,
+				B1F6CDBE24A88D26005CB1E0 /* BBSViewModel.swift in Sources */,
 				E4B888751D9D48F1002E1A46 /* Department.swift in Sources */,
 				E4C24B6D20844F3C00E426B0 /* JCAlertView.swift in Sources */,
 				B190923521071777009A7906 /* OOCalendarModels.swift in Sources */,
@@ -5849,6 +6069,7 @@
 				E4B888711D9D48F1002E1A46 /* ContactSearchViewController.swift in Sources */,
 				B130A7852281597000282AD1 /* DeviceManagerViewModel.swift in Sources */,
 				E40E24BF20B7DA3C009F8BE7 /* OOMeetingRoomDeviceListView.swift in Sources */,
+				B1173A632488C8EA005075F0 /* IMConversationInfo.swift in Sources */,
 				E4A748D51EC15EF100163F58 /* TaskAttachmentPreviewController.swift in Sources */,
 				E4B888A51D9D48F1002E1A46 /* MJRefreshBackStateFooter.m in Sources */,
 				E4B8885E1D9D48F1002E1A46 /* O2CollectionView.swift in Sources */,
@@ -5858,9 +6079,11 @@
 				E4D2310F209C40F600837868 /* OOPersonCollectionViewCell.swift in Sources */,
 				E4C24B4A20844F3C00E426B0 /* JCMessageImageCollectionViewCell.swift in Sources */,
 				E4C24B6920844F3C00E426B0 /* DLSlideView.m in Sources */,
+				B1173A672488CD5B005075F0 /* IMConversationItemCell.swift in Sources */,
 				B1534E3F21F712EA00CC8C35 /* O2DemoAlertView.swift in Sources */,
 				E4C24B7F20844F3C00E426B0 /* ImageFileCell.swift in Sources */,
 				B165CD602242093500373B66 /* AlertViewController.swift in Sources */,
+				B1173A5E2488C5DF005075F0 /* CommunicateAPI.swift in Sources */,
 				E441994A206C8A100050AE0C /* OORegisterTableView.swift in Sources */,
 				E40E24A920B7DA3C009F8BE7 /* OOMeetingCreateViewModel.swift in Sources */,
 				E40C41ED1E7F7C0D00568805 /* ZoneSubCategoryViewController.swift in Sources */,
@@ -5869,6 +6092,7 @@
 				E4CB27721E78D5B1004A7ACB /* UINavigationBar+Flat.swift in Sources */,
 				E45DA90C1DAF76C800E0735D /* SCommonViewController.swift in Sources */,
 				B108F401229E34D400778050 /* LBXScanWrapper.swift in Sources */,
+				B1489CB624935104009EE9FD /* IMInstantMessageViewController.swift in Sources */,
 				E40C41F21E83715C00568805 /* ZLUISearchBar.swift in Sources */,
 				E4B888791D9D48F1002E1A46 /* Person.swift in Sources */,
 				E4C24BA820844F3C00E426B0 /* JCChatViewController.swift in Sources */,
@@ -5882,6 +6106,8 @@
 				B167F7662362C60200F182B8 /* CloudFileMoveFolderCell.swift in Sources */,
 				B165CD5C2242093500373B66 /* CoverHorizontalAnimation.swift in Sources */,
 				B1908E1422685E8F00D75632 /* O2WebViewModels.swift in Sources */,
+				B1F6CDF024A89836005CB1E0 /* BBSSubjectAttachmentViewCell.swift in Sources */,
+				B1F6CDEE24A893B6005CB1E0 /* BBSSubjectAttachmentViewController.swift in Sources */,
 				E4B69738207602A40062F6E8 /* OOAccessTokenAuthorizable.swift in Sources */,
 				E4C24BB120844F3C00E426B0 /* JCMessageOptions.swift in Sources */,
 				E4B8889C1D9D48F1002E1A46 /* MJRefreshBackFooter.m in Sources */,
@@ -5896,6 +6122,7 @@
 				B1DE856623603408003C36E2 /* DispatchQueue+Extension.swift in Sources */,
 				E4B69772207630240062F6E8 /* String+Extenstion.swift in Sources */,
 				B175007A233C6908003DA7B9 /* BlockLongPress.swift in Sources */,
+				B1173A5B2488C546005075F0 /* IMConversationListViewController.swift in Sources */,
 				E4B69734207602A40062F6E8 /* OOAPIContext.swift in Sources */,
 				09E02E881F16319600579887 /* DiskFetcher.swift in Sources */,
 				E4C24B5520844F3C00E426B0 /* SAIToolboxInputView.swift in Sources */,
@@ -5903,10 +6130,12 @@
 				E4C24B5320844F3C00E426B0 /* SAIInputView.swift in Sources */,
 				E40E24CF20B7DA3C009F8BE7 /* OOFormDateItemView.swift in Sources */,
 				B1FBA01D230A3AB500A90722 /* O2JsApiBizUtil.swift in Sources */,
+				B1489B51248E192D009EE9FD /* IMChatMessageViewCell.swift in Sources */,
 				E4B69776207630240062F6E8 /* UIView+Extension.swift in Sources */,
 				E4C24BB420844F3C00E426B0 /* JCMessageContentViewType.swift in Sources */,
 				E4C24B9420844F3C00E426B0 /* JCGroupSettingCell.swift in Sources */,
 				E40E24D320B7DA3C009F8BE7 /* OOMeetingPersonSelectHeaderView.swift in Sources */,
+				B15BE0BE2499BCEF008CD1DB /* O2RecordVoiceManager.swift in Sources */,
 				B1DB6EA5237E6F2C00D7BA94 /* O2VersionInfoModel.swift in Sources */,
 				E4C24B9E20844F3C00E426B0 /* JCUpdateMemberCell.swift in Sources */,
 				09E02E9A1F1745E700579887 /* ZLTextView.swift in Sources */,
@@ -5959,6 +6188,7 @@
 				B1FBA01A230533FA00A90722 /* PersonPickerTableViewCell.swift in Sources */,
 				E4B6981A2079A8BB0062F6E8 /* OOBindNodeViewController.swift in Sources */,
 				E4F4544F20902263002FBC32 /* OOConfigInfoModels.swift in Sources */,
+				B1489CB12492045D009EE9FD /* IMChatEmojiItemCell.swift in Sources */,
 				E4B2321A20B3E9440082F30A /* OOAttanceCheckinPromptView.swift in Sources */,
 				E4B69810207652960062F6E8 /* OOTaskModels.swift in Sources */,
 				E4B888761D9D48F1002E1A46 /* DepartmentDuty.swift in Sources */,
@@ -5968,11 +6198,13 @@
 				B1EE2CD02281771600842F48 /* O2JsApiUtil.swift in Sources */,
 				E4B6975020762EA00062F6E8 /* OOPasswordTextField.swift in Sources */,
 				E491664C1E03C09C006133C5 /* O2Account.swift in Sources */,
+				B15BE111249A6002008CD1DB /* AudioPlayerManager.swift in Sources */,
 				E46E6CBA1DD41F5D00AB7561 /* CYRToken.m in Sources */,
 				E4C24C53208D7EDE00E426B0 /* OOContactGroupHeaderView.swift in Sources */,
 				E4C24BD120844F3C00E426B0 /* JCNoteNameViewController.swift in Sources */,
 				B1B110E2223622C400775BEF /* O2BioLocalAuth.swift in Sources */,
 				E4184B231DB4B29B00FCC907 /* SPasswordChangeViewController.swift in Sources */,
+				B1489C7B2491FEFE009EE9FD /* IMChatEmojiBarView.swift in Sources */,
 				E4B7816C1DF8F2B2007B58A9 /* CMSData.swift in Sources */,
 				B165CD592242093500373B66 /* PresentrController.swift in Sources */,
 				E4B7816D1DF8F2B2007B58A9 /* CMSWrapOutCategoryList.swift in Sources */,
@@ -6004,6 +6236,7 @@
 				B1EE2CCE2281729400842F48 /* QDatePicker.swift in Sources */,
 				E4B6975C20762EA00062F6E8 /* OOUIDownButtonTextField.swift in Sources */,
 				E4C24C0720844F4400E426B0 /* JCSearchFriendViewController.swift in Sources */,
+				B1173A602488C82F005075F0 /* IMViewModel.swift in Sources */,
 				E46E6CBB1DD41F5D00AB7561 /* HRBrightnessCursor.m in Sources */,
 				E4B697E920764A2D0062F6E8 /* OOWorkAPI.swift in Sources */,
 				E40E24C720B7DA3C009F8BE7 /* OOFormSegueItemView.swift in Sources */,
@@ -6050,6 +6283,7 @@
 				E46E6CBF1DD41F5D00AB7561 /* HRColorPickerViewController.m in Sources */,
 				E4C24B6E20844F3C00E426B0 /* JCFileManager.swift in Sources */,
 				09E02E0E1F16001B00579887 /* Head.swift in Sources */,
+				B18398AD249B00AA001C6FAA /* IMLocationView.swift in Sources */,
 				E4D2313020A29E9F00837868 /* OOAppMainCollectionReusableView.swift in Sources */,
 				B165CD5B2242093500373B66 /* PresentrShadow.swift in Sources */,
 				B107453C21A52FA00015F1B2 /* O2PersonInfo.swift in Sources */,
@@ -6113,6 +6347,7 @@
 				09E02E021F12736C00579887 /* PersonV2.swift in Sources */,
 				B1B0102F23586B34002BF874 /* CFFileTableViewCell.swift in Sources */,
 				E40E24AE20B7DA3C009F8BE7 /* OOMeetingAcceptController.swift in Sources */,
+				B15BE107249A06BF008CD1DB /* ConvertMp3.m in Sources */,
 				09E02E041F127CAF00579887 /* IdentityV2.swift in Sources */,
 				E42E41CE1E6ED13C00C5B5C7 /* CMS_PublishInfo.swift in Sources */,
 				E4B888801D9D48F1002E1A46 /* File.swift in Sources */,
@@ -6133,6 +6368,7 @@
 				E4B888C41D9D48F1002E1A46 /* CollectDeviceData.swift in Sources */,
 				E4B888731D9D48F1002E1A46 /* Company.swift in Sources */,
 				E4C24B9B20844F3C00E426B0 /* JCNetworkTipsCell.swift in Sources */,
+				B15BE10E249A107C008CD1DB /* IMAudioView.swift in Sources */,
 				E45DA8E91DACC11600E0735D /* BaseWebViewUIViewController.swift in Sources */,
 				E424BAD61EE105BB0078DB47 /* O2Logger.swift in Sources */,
 				E491664A1E038D09006133C5 /* O2AlamofireSource.swift in Sources */,
@@ -6158,6 +6394,7 @@
 				09E02E971F16319600579887 /* UIImageView+Haneke.swift in Sources */,
 				E4B8887D1D9D48F1002E1A46 /* FileMyDownloadViewController.swift in Sources */,
 				E4C24B6620844F3C00E426B0 /* DLFixedTabbarView.m in Sources */,
+				B18398B3249B4154001C6FAA /* IMShowLocationViewController.swift in Sources */,
 				E4C24B3520844F3C00E426B0 /* NSLayoutConstraint+JChat.swift in Sources */,
 				E45DA9121DAF7EBE00E0735D /* SZKCleanCache.m in Sources */,
 				090253DE1F0E8BA6006B1609 /* O2LoadingView.swift in Sources */,
@@ -6184,6 +6421,7 @@
 				E40E24D220B7DA3C009F8BE7 /* OOFormDateIntervalItemView.swift in Sources */,
 				E4184B251DB4F28800FCC907 /* SMobileChangeViewController.swift in Sources */,
 				E40E24B320B7DA3C009F8BE7 /* OOMeetingMeetingRoomManageController.swift in Sources */,
+				B15BE0EE2499DD7E008CD1DB /* IMChatAudioView.swift in Sources */,
 				E40E24D820B7DA3C009F8BE7 /* OOMeetingPersonFooterView.swift in Sources */,
 				B14E078A230141AC00AE85A0 /* ContactGroupPickerViewController.swift in Sources */,
 				E4B697C520764A2D0062F6E8 /* O2InformationAPI.swift in Sources */,
@@ -6215,6 +6453,7 @@
 				E40502C520722208009A8D30 /* ImagePickerController.swift in Sources */,
 				E4C24B7320844F3C00E426B0 /* JCCEmoticonGroup.swift in Sources */,
 				E4C24BB720844F3C00E426B0 /* JCEmoticonPreviewer.swift in Sources */,
+				8840A992248CDC9D005970A5 /* OOCalendarEditRemarkViewController.swift in Sources */,
 				B12FD1DC2283D5B700E636BA /* ThemeScrollViewIndicatorStylePicker.swift in Sources */,
 				B12FD1DD2283D5B700E636BA /* UITextField+PlaceholderAttributes.swift in Sources */,
 				E4C24B3920844F3C00E426B0 /* Array+JChat.swift in Sources */,
@@ -6282,6 +6521,7 @@
 				E4B888A41D9D48F1002E1A46 /* MJRefreshBackNormalFooter.m in Sources */,
 				E4B2320F20B2A9F60082F30A /* OOAttandanceWorkPlaceController.swift in Sources */,
 				E46E6CB91DD41F5D00AB7561 /* CYRTextView.m in Sources */,
+				B1489B1C248E0F4D009EE9FD /* IMChatViewController.swift in Sources */,
 				B175007C233C6908003DA7B9 /* BlockTap.swift in Sources */,
 				E4C24B5020844F3C00E426B0 /* SAIInputAccessoryViewLayout.swift in Sources */,
 				E4AA17151EE158E70030D9AB /* LogListViewController.swift in Sources */,
@@ -6371,6 +6611,7 @@
 				E4C24B8D20844F3C00E426B0 /* JCMessageLocationContentView.swift in Sources */,
 				E4CDB8851E7CFB9C008E788D /* ZLNormalNavViewController.swift in Sources */,
 				B1DA305F2282754500669418 /* QCalendarPicker.swift in Sources */,
+				B14E0C0C2484F1F0008AF6AE /* O2WebsocketManager.swift in Sources */,
 				E46E6CBC1DD41F5D00AB7561 /* HRCgUtil.m in Sources */,
 				E496E89E207314B100C68EEE /* NavView.swift in Sources */,
 				E4C24BD720844F3C00E426B0 /* JCMyInfoViewController.swift in Sources */,
@@ -6395,6 +6636,7 @@
 				E4C24BD920844F3C00E426B0 /* JCFeedbackViewController.swift in Sources */,
 				E4C24C4C208D7EDE00E426B0 /* OOCDLCell.swift in Sources */,
 				B158E95E215DD3F500AB2727 /* AIConstants.swift in Sources */,
+				B1489BFE2490BE51009EE9FD /* IMChatMessageSendViewCell.swift in Sources */,
 				E4BF45D71E74FB0C008B52F0 /* ImageSlidesShowView.swift in Sources */,
 				E4C24B5820844F3C00E426B0 /* SAIInputItem.swift in Sources */,
 				E40E24DF20B7E66E009F8BE7 /* O2BBSCreatorView.swift in Sources */,
@@ -6402,6 +6644,7 @@
 				E4C24B5720844F3C00E426B0 /* SAIToolboxInputViewLayout.swift in Sources */,
 				B1FD027021FAE00E000E9817 /* O2MainController.swift in Sources */,
 				E4B697092075FA560062F6E8 /* BaseModel.swift in Sources */,
+				B18398B0249B079B001C6FAA /* IMLocationChooseController.swift in Sources */,
 				E4B888621D9D48F1002E1A46 /* ZLCollectionView.swift in Sources */,
 				B1298E812366B2E7006E9236 /* CFImageViewCell.swift in Sources */,
 				E40E24B220B7DA3C009F8BE7 /* OOMeetingCreateViewController.swift in Sources */,
@@ -6417,6 +6660,7 @@
 				E4C24B8C20844F3C00E426B0 /* JCMessageNoticeContentView.swift in Sources */,
 				E4C24C3E208D7EDE00E426B0 /* OOContactViewModel.swift in Sources */,
 				E4D2312E20A29E7500837868 /* OOAppMainCollectionHeaderView.swift in Sources */,
+				B1173A6A2488D4AD005075F0 /* O2IM.swift in Sources */,
 				E4C24B5220844F3C00E426B0 /* SAIToolboxItemView.swift in Sources */,
 				E4C24B3C20844F3C00E426B0 /* Date+JChat.swift in Sources */,
 				E4C24C0120844F4400E426B0 /* JCUserInfoCell.swift in Sources */,
@@ -6619,7 +6863,7 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Manual;
-				CURRENT_PROJECT_VERSION = 67;
+				CURRENT_PROJECT_VERSION = 69;
 				DEVELOPMENT_TEAM = NTDRU2P6T4;
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -6650,8 +6894,11 @@
 					"$(PROJECT_DIR)/O2Platform/framework/thirdlibs",
 					"$(PROJECT_DIR)/O2Platform/framework/MegviiLicMgr-iOS-SDK",
 					"$(PROJECT_DIR)/O2Platform/framework/O2OA_Flutter_SDK",
+					"$(PROJECT_DIR)/O2Platform/Framework/lame/vo-amrwbenc/lib",
+					"$(PROJECT_DIR)/O2Platform/Framework/lame",
+					"$(PROJECT_DIR)/O2Platform/Framework/lame/opencore-amr/lib",
 				);
-				MARKETING_VERSION = 5.0.7;
+				MARKETING_VERSION = 5.1.0;
 				OTHER_LDFLAGS = (
 					"$(inherited)",
 					"-ObjC",
@@ -6664,8 +6911,6 @@
 					"-framework",
 					"\"AlamofireObjectMapper\"",
 					"-framework",
-					"\"BSGridCollectionViewLayout\"",
-					"-framework",
 					"\"BSImagePicker\"",
 					"-framework",
 					"\"Charts\"",
@@ -6734,7 +6979,7 @@
 				CODE_SIGN_IDENTITY = "iPhone Distribution";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
 				CODE_SIGN_STYLE = Manual;
-				CURRENT_PROJECT_VERSION = 67;
+				CURRENT_PROJECT_VERSION = 69;
 				DEVELOPMENT_TEAM = NTDRU2P6T4;
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -6765,8 +7010,11 @@
 					"$(PROJECT_DIR)/O2Platform/framework/thirdlibs",
 					"$(PROJECT_DIR)/O2Platform/framework/MegviiLicMgr-iOS-SDK",
 					"$(PROJECT_DIR)/O2Platform/framework/O2OA_Flutter_SDK",
+					"$(PROJECT_DIR)/O2Platform/Framework/lame/vo-amrwbenc/lib",
+					"$(PROJECT_DIR)/O2Platform/Framework/lame",
+					"$(PROJECT_DIR)/O2Platform/Framework/lame/opencore-amr/lib",
 				);
-				MARKETING_VERSION = 5.0.7;
+				MARKETING_VERSION = 5.1.0;
 				OTHER_LDFLAGS = (
 					"$(inherited)",
 					"-ObjC",
@@ -6779,8 +7027,6 @@
 					"-framework",
 					"\"AlamofireObjectMapper\"",
 					"-framework",
-					"\"BSGridCollectionViewLayout\"",
-					"-framework",
 					"\"BSImagePicker\"",
 					"-framework",
 					"\"Charts\"",

+ 14 - 4
o2ios/O2Platform/App/Applications/c/MailViewController.swift

@@ -51,14 +51,24 @@ class MailViewController: BaseWebViewUIViewController {
     }
 
     override func viewWillAppear(_ animated: Bool) {
+        
         if self.isIndexShow || self.hasInnerBar {
-            let statusBarWindow : UIView = UIApplication.shared.value(forKey: "statusBarWindow") as! UIView
-            let statusBar : UIView = statusBarWindow.value(forKey: "statusBar") as! UIView
-            if statusBar.responds(to:#selector(setter: UIView.backgroundColor)) {
-                statusBar.backgroundColor = base_color
+            if #available(iOS 13.0, *) {
+                if let frame = UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame {
+                    let statusBar = UIView(frame: frame)
+                   statusBar.backgroundColor = base_color
+                   UIApplication.shared.keyWindow?.addSubview(statusBar)
+                }
+            }else {
+              let statusBarWindow : UIView = UIApplication.shared.value(forKey: "statusBarWindow") as! UIView
+                let statusBar : UIView = statusBarWindow.value(forKey: "statusBar") as! UIView
+                if statusBar.responds(to:#selector(setter: UIView.backgroundColor)) {
+                    statusBar.backgroundColor = base_color
+                }
             }
             self.navigationController?.setNavigationBarHidden(true, animated: true)
         }
+        
     }
     
     override func viewWillDisappear(_ animated: Bool) {

+ 56 - 0
o2ios/O2Platform/App/BBS-论坛/BBSViewModel.swift

@@ -0,0 +1,56 @@
+//
+//  BBSViewModel.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/28.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Promises
+
+
+
+class BBSViewModel : NSObject {
+    override init() {
+        super.init()
+    }
+    private let bbsAPI = OOMoyaProvider<O2BBSAPI>()
+}
+
+extension BBSViewModel {
+    
+    //获取附件列表
+    func getSubjectAttachmentList(subjectId: String) -> Promise<[O2BBSSubjectAttachmentInfo]> {
+        return Promise{ fulfill, reject in
+            self.bbsAPI.request(.getSubjectAttachmentList(subjectId), completion: { result in
+                let response = OOResult<BaseModelClass<[O2BBSSubjectAttachmentInfo]>>(result)
+                if response.isResultSuccess() {
+                    if let data = response.model?.data {
+                        fulfill(data)
+                    }else {
+                        reject(OOAppError.apiEmptyResultError)
+                    }
+                }else {
+                    reject(response.error!)
+                }
+            })
+        }
+    }
+    
+    //下载附件
+    func downloadAttachment(att: O2BBSSubjectAttachmentInfo) -> Promise<URL> {
+        return Promise { fulfill, reject in
+            self.bbsAPI.request(.downloadAttachForSubject(att), completion: {result in
+                switch result {
+                case .success(_):
+                    //下载成功
+                    let fileURL = O2CloudFileManager.shared.cloudFileLocalFolder().appendingPathComponent(att.fileName!)
+                    fulfill(fileURL)
+                case .failure(let err):
+                    reject(err)
+                }
+            })
+        }
+    }
+    
+}

+ 230 - 94
o2ios/O2Platform/App/BBS-论坛/bbs.storyboard

@@ -1,12 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="WEC-RV-idi">
-    <device id="retina5_5" 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="WEC-RV-idi">
+    <device id="retina5_5" orientation="portrait" appearance="light"/>
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
-        <capability name="Alignment constraints to the first baseline" minToolsVersion="6.0"/>
-        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
@@ -73,13 +70,13 @@
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                         <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="todoedStatusIcon" translatesAutoresizingMaskIntoConstraints="NO" id="eCw-XQ-nPh">
-                                            <rect key="frame" x="8" y="13" width="15" height="15"/>
+                                            <rect key="frame" x="8" y="13" width="15" height="14"/>
                                             <constraints>
                                                 <constraint firstAttribute="width" constant="15" id="PmP-an-at8"/>
                                             </constraints>
                                         </imageView>
                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="分区标题" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="44b-Jk-OK6">
-                                            <rect key="frame" x="28" y="10" width="339" height="21"/>
+                                            <rect key="frame" x="28" y="9.6666666666666643" width="378" height="21"/>
                                             <fontDescription key="fontDescription" name="PingFangSC-Regular" family="PingFang SC" pointSize="15"/>
                                             <nil key="textColor"/>
                                             <nil key="highlightedColor"/>
@@ -149,54 +146,54 @@
                                         <rect key="frame" x="0.0" y="28" width="414" height="70"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ErA-A6-5RQ" id="YdI-rU-dXv">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="69.666666666666671"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="70"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="8Z6-6I-uQ0">
-                                                    <rect key="frame" x="8" y="14" width="40" height="40"/>
+                                                    <rect key="frame" x="20" y="17" width="40" height="36"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="40" id="PtW-Yl-UQc"/>
                                                     </constraints>
                                                 </imageView>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="标题" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kik-Ss-LkJ">
-                                                    <rect key="frame" x="56" y="3" width="328" height="21"/>
+                                                    <rect key="frame" x="68" y="6" width="304" height="21"/>
                                                     <fontDescription key="fontDescription" name="PingFangSC-Regular" family="PingFang SC" pointSize="15"/>
                                                     <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="v8A-H1-kpy">
-                                                    <rect key="frame" x="56" y="24" width="350" height="21"/>
+                                                    <rect key="frame" x="68" y="27" width="326" height="16"/>
                                                     <fontDescription key="fontDescription" name="PingFangSC-Light" family="PingFang SC" pointSize="12"/>
                                                     <nil key="textColor"/>
                                                     <nil key="highlightedColor"/>
                                                 </label>
                                                 <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_bbs_top" translatesAutoresizingMaskIntoConstraints="NO" id="e3D-3V-MR0">
-                                                    <rect key="frame" x="386" y="3" width="20" height="19"/>
+                                                    <rect key="frame" x="374" y="6" width="20" height="19"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="20" id="4Hn-Sw-BFq"/>
                                                     </constraints>
                                                 </imageView>
                                                 <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_bbs_view" translatesAutoresizingMaskIntoConstraints="NO" id="ra0-aj-i6e">
-                                                    <rect key="frame" x="325" y="50" width="15" height="15"/>
+                                                    <rect key="frame" x="313" y="48" width="15" height="15"/>
                                                     <constraints>
                                                         <constraint firstAttribute="height" constant="15" id="YBi-9q-hPx"/>
                                                         <constraint firstAttribute="width" constant="15" id="bKQ-tk-RSJ"/>
                                                     </constraints>
                                                 </imageView>
                                                 <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_bbs_reply" translatesAutoresizingMaskIntoConstraints="NO" id="JKc-Vg-H3T">
-                                                    <rect key="frame" x="365" y="50" width="15" height="15"/>
+                                                    <rect key="frame" x="353" y="48" width="15" height="15"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="15" id="qng-1A-KDn"/>
                                                     </constraints>
                                                 </imageView>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="日期" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zed-8e-goT">
-                                                    <rect key="frame" x="56" y="47" width="269" height="21"/>
+                                                    <rect key="frame" x="68" y="45" width="245" height="21"/>
                                                     <fontDescription key="fontDescription" name="PingFangSC-Light" family="PingFang SC" pointSize="12"/>
                                                     <nil key="textColor"/>
                                                     <nil key="highlightedColor"/>
                                                 </label>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OQZ-wY-Eqd">
-                                                    <rect key="frame" x="340" y="50" width="23" height="15"/>
+                                                    <rect key="frame" x="328" y="48" width="23" height="15"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="23" id="vNO-0X-FKq"/>
                                                     </constraints>
@@ -205,7 +202,7 @@
                                                     <nil key="highlightedColor"/>
                                                 </label>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ad6-Es-Z2s">
-                                                    <rect key="frame" x="380" y="50" width="23" height="15"/>
+                                                    <rect key="frame" x="368" y="48" width="23" height="15"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="23" id="a36-n3-yZt"/>
                                                     </constraints>
@@ -290,169 +287,180 @@
                             <tableViewSection headerTitle="发帖信息" id="OTR-Rg-Xlz">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="SsA-gX-Rbw">
-                                        <rect key="frame" x="0.0" y="55.333333333333336" width="414" height="50"/>
+                                        <rect key="frame" x="0.0" y="55.333332061767578" width="414" height="50"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="SsA-gX-Rbw" id="4ze-PR-4jQ">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="49.666666666666664"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="50"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="发帖版块" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c5v-yv-12W">
+                                                    <rect key="frame" x="20" y="17" width="89" height="15"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="89" id="dGu-FD-09P"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
                                                 <view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="10N-By-qwX">
-                                                    <rect key="frame" x="105" y="0.0" width="1" height="49"/>
+                                                    <rect key="frame" x="117" y="0.0" width="1" height="49"/>
                                                     <color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="calibratedRGB"/>
                                                     <constraints>
                                                         <constraint firstAttribute="height" constant="49" id="f5Y-Ru-yr8"/>
                                                         <constraint firstAttribute="width" constant="1" id="n96-im-SIj"/>
                                                     </constraints>
                                                 </view>
-                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="发帖版块" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m5F-2L-UB0">
-                                                    <rect key="frame" x="114" y="14" width="253" height="21"/>
-                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="发帖版块" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m5F-2L-UB0">
+                                                    <rect key="frame" x="126" y="15" width="244" height="19"/>
                                                     <fontDescription key="fontDescription" name="PingFangSC-Regular" family="PingFang SC" pointSize="14"/>
                                                     <color key="textColor" red="0.070588235294117646" green="0.070588235294117646" blue="0.070588235294117646" alpha="1" colorSpace="calibratedRGB"/>
                                                     <nil key="highlightedColor"/>
                                                 </label>
-                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="发帖版块" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c5v-yv-12W">
-                                                    <rect key="frame" x="43" y="14" width="54" height="21"/>
-                                                    <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                    <nil key="textColor"/>
-                                                    <nil key="highlightedColor"/>
-                                                </label>
                                             </subviews>
                                             <constraints>
+                                                <constraint firstItem="c5v-yv-12W" firstAttribute="leading" secondItem="4ze-PR-4jQ" secondAttribute="leadingMargin" id="4LL-7f-Q61"/>
                                                 <constraint firstItem="10N-By-qwX" firstAttribute="top" secondItem="4ze-PR-4jQ" secondAttribute="top" id="6g6-l3-RzA"/>
+                                                <constraint firstAttribute="bottomMargin" secondItem="m5F-2L-UB0" secondAttribute="bottom" constant="4" id="Gj5-U2-Gsd"/>
                                                 <constraint firstAttribute="bottom" secondItem="10N-By-qwX" secondAttribute="bottom" id="LH3-jg-c6Q"/>
+                                                <constraint firstAttribute="bottomMargin" secondItem="c5v-yv-12W" secondAttribute="bottom" constant="6" id="MIa-Aa-7MP"/>
+                                                <constraint firstItem="m5F-2L-UB0" firstAttribute="top" secondItem="4ze-PR-4jQ" secondAttribute="topMargin" constant="4" id="OCO-eZ-FFc"/>
+                                                <constraint firstItem="m5F-2L-UB0" firstAttribute="leading" secondItem="10N-By-qwX" secondAttribute="trailing" constant="8" id="PMc-Sn-c5e"/>
                                                 <constraint firstItem="10N-By-qwX" firstAttribute="leading" secondItem="c5v-yv-12W" secondAttribute="trailing" constant="8" id="R9a-kF-AJw"/>
-                                                <constraint firstItem="c5v-yv-12W" firstAttribute="centerY" secondItem="10N-By-qwX" secondAttribute="centerY" id="fBb-5n-vka"/>
-                                                <constraint firstItem="c5v-yv-12W" firstAttribute="top" secondItem="4ze-PR-4jQ" secondAttribute="topMargin" constant="6" id="puI-zS-lgB"/>
-                                                <constraint firstItem="c5v-yv-12W" firstAttribute="leading" secondItem="4ze-PR-4jQ" secondAttribute="leadingMargin" constant="35" id="wFL-ZP-X9Q"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="m5F-2L-UB0" secondAttribute="trailing" constant="24" id="iNc-n6-VUt"/>
+                                                <constraint firstItem="c5v-yv-12W" firstAttribute="top" secondItem="4ze-PR-4jQ" secondAttribute="topMargin" constant="6" id="m6G-Q7-yt6"/>
                                             </constraints>
                                         </tableViewCellContentView>
                                     </tableViewCell>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="aP3-PV-VE0">
-                                        <rect key="frame" x="0.0" y="105.33333333333334" width="414" height="50"/>
+                                        <rect key="frame" x="0.0" y="105.33333206176758" width="414" height="50"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="aP3-PV-VE0" id="68U-mJ-dtd">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="49.666666666666664"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="50"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
-                                                <view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jej-9K-Wwd">
-                                                    <rect key="frame" x="105" y="0.0" width="40" height="49"/>
-                                                    <color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="calibratedRGB"/>
-                                                </view>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="主题分类" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bq6-o8-XQc">
-                                                    <rect key="frame" x="43" y="14" width="54" height="21"/>
+                                                    <rect key="frame" x="20" y="17" width="89" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="89" id="0X1-bp-qUG"/>
+                                                    </constraints>
                                                     <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                     <nil key="textColor"/>
                                                     <nil key="highlightedColor"/>
                                                 </label>
-                                                <pickerView contentMode="left" translatesAutoresizingMaskIntoConstraints="NO" id="O4S-3V-wYR">
-                                                    <rect key="frame" x="153" y="4" width="142" height="40"/>
+                                                <view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jej-9K-Wwd">
+                                                    <rect key="frame" x="117" y="0.0" width="1" height="50"/>
+                                                    <color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="calibratedRGB"/>
                                                     <constraints>
-                                                        <constraint firstAttribute="width" constant="142" id="RLr-iY-eA3"/>
+                                                        <constraint firstAttribute="width" constant="1" id="gvD-g8-nLP"/>
                                                     </constraints>
+                                                </view>
+                                                <pickerView contentMode="left" translatesAutoresizingMaskIntoConstraints="NO" id="O4S-3V-wYR">
+                                                    <rect key="frame" x="126" y="-83" width="276" height="216"/>
                                                 </pickerView>
                                             </subviews>
                                             <constraints>
+                                                <constraint firstAttribute="bottomMargin" secondItem="bq6-o8-XQc" secondAttribute="bottom" constant="6" id="0ni-gU-aaq"/>
                                                 <constraint firstItem="jej-9K-Wwd" firstAttribute="top" secondItem="68U-mJ-dtd" secondAttribute="top" id="B1w-Kr-Kfw"/>
                                                 <constraint firstItem="jej-9K-Wwd" firstAttribute="centerY" secondItem="O4S-3V-wYR" secondAttribute="centerY" id="Cwh-GD-EWg"/>
+                                                <constraint firstItem="bq6-o8-XQc" firstAttribute="top" secondItem="68U-mJ-dtd" secondAttribute="topMargin" constant="6" id="OaW-D1-iXG"/>
                                                 <constraint firstAttribute="bottom" secondItem="jej-9K-Wwd" secondAttribute="bottom" id="RPX-TD-sna"/>
-                                                <constraint firstItem="jej-9K-Wwd" firstAttribute="leading" secondItem="bq6-o8-XQc" secondAttribute="trailing" constant="8" symbolic="YES" id="ReC-44-FA0"/>
-                                                <constraint firstItem="bq6-o8-XQc" firstAttribute="top" secondItem="68U-mJ-dtd" secondAttribute="topMargin" constant="6" id="ajf-ZP-AKs"/>
-                                                <constraint firstItem="O4S-3V-wYR" firstAttribute="top" secondItem="68U-mJ-dtd" secondAttribute="topMargin" constant="-4" id="eQM-mi-5vL"/>
-                                                <constraint firstItem="bq6-o8-XQc" firstAttribute="leading" secondItem="68U-mJ-dtd" secondAttribute="leadingMargin" constant="35" id="hCw-dm-9Q3"/>
-                                                <constraint firstItem="O4S-3V-wYR" firstAttribute="trailing" secondItem="68U-mJ-dtd" secondAttribute="trailingMargin" constant="-111" id="khw-9H-d5g"/>
-                                                <constraint firstItem="O4S-3V-wYR" firstAttribute="leading" secondItem="jej-9K-Wwd" secondAttribute="trailing" constant="8" symbolic="YES" id="oIN-ay-8aQ"/>
-                                                <constraint firstItem="bq6-o8-XQc" firstAttribute="centerY" secondItem="jej-9K-Wwd" secondAttribute="centerY" id="zjL-mV-Stb"/>
+                                                <constraint firstItem="jej-9K-Wwd" firstAttribute="leading" secondItem="bq6-o8-XQc" secondAttribute="trailing" constant="8" id="ReC-44-FA0"/>
+                                                <constraint firstItem="bq6-o8-XQc" firstAttribute="leading" secondItem="68U-mJ-dtd" secondAttribute="leadingMargin" id="hCw-dm-9Q3"/>
+                                                <constraint firstItem="O4S-3V-wYR" firstAttribute="trailing" secondItem="68U-mJ-dtd" secondAttribute="trailingMargin" constant="8" id="khw-9H-d5g"/>
+                                                <constraint firstItem="O4S-3V-wYR" firstAttribute="leading" secondItem="jej-9K-Wwd" secondAttribute="trailing" constant="8" id="oIN-ay-8aQ"/>
                                             </constraints>
                                         </tableViewCellContentView>
                                     </tableViewCell>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="Hli-rZ-69M">
-                                        <rect key="frame" x="0.0" y="155.33333333333334" width="414" height="50"/>
+                                        <rect key="frame" x="0.0" y="155.33333206176758" width="414" height="50"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Hli-rZ-69M" id="hqn-jq-lGd">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="49.666666666666664"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="50"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="主题" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eKF-8f-lk7">
-                                                    <rect key="frame" x="42" y="17" width="54" height="16"/>
+                                                    <rect key="frame" x="20" y="17" width="89" height="16"/>
                                                     <constraints>
-                                                        <constraint firstAttribute="width" constant="54" id="50E-aB-Kt6"/>
+                                                        <constraint firstAttribute="width" constant="89" id="50E-aB-Kt6"/>
                                                     </constraints>
                                                     <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                     <nil key="textColor"/>
                                                     <nil key="highlightedColor"/>
                                                 </label>
+                                                <view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="weU-We-eXr">
+                                                    <rect key="frame" x="117" y="0.0" width="1" height="50"/>
+                                                    <color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="1" id="NVz-Wh-aFM"/>
+                                                    </constraints>
+                                                </view>
                                                 <textField opaque="NO" clipsSubviews="YES" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="P2q-FF-3d3">
-                                                    <rect key="frame" x="156" y="9" width="250" height="30"/>
+                                                    <rect key="frame" x="126" y="13" width="276" height="24"/>
                                                     <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                                                     <constraints>
-                                                        <constraint firstAttribute="width" constant="250" id="XuE-Tb-NXG"/>
+                                                        <constraint firstAttribute="height" constant="24" id="YEY-jO-Zwu"/>
                                                     </constraints>
-                                                    <nil key="textColor"/>
                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                     <textInputTraits key="textInputTraits" returnKeyType="next" enablesReturnKeyAutomatically="YES"/>
                                                 </textField>
-                                                <view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="weU-We-eXr">
-                                                    <rect key="frame" x="105" y="0.0" width="40" height="49"/>
-                                                    <color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="calibratedRGB"/>
-                                                </view>
                                             </subviews>
                                             <constraints>
+                                                <constraint firstItem="eKF-8f-lk7" firstAttribute="leading" secondItem="hqn-jq-lGd" secondAttribute="leadingMargin" id="2ht-LN-tZ4"/>
                                                 <constraint firstItem="weU-We-eXr" firstAttribute="top" secondItem="hqn-jq-lGd" secondAttribute="top" id="3wN-QW-05b"/>
                                                 <constraint firstItem="weU-We-eXr" firstAttribute="centerY" secondItem="P2q-FF-3d3" secondAttribute="centerY" id="Jx1-9Q-gRk"/>
-                                                <constraint firstItem="weU-We-eXr" firstAttribute="leading" secondItem="eKF-8f-lk7" secondAttribute="trailing" constant="9" id="Mfx-j3-i85"/>
-                                                <constraint firstItem="P2q-FF-3d3" firstAttribute="top" secondItem="hqn-jq-lGd" secondAttribute="topMargin" constant="1" id="Y3Y-Ob-6hb"/>
-                                                <constraint firstItem="eKF-8f-lk7" firstAttribute="centerY" secondItem="weU-We-eXr" secondAttribute="centerY" id="bZe-Zk-9Kw"/>
-                                                <constraint firstItem="P2q-FF-3d3" firstAttribute="trailing" secondItem="hqn-jq-lGd" secondAttribute="trailingMargin" id="fLv-mH-Rvr"/>
-                                                <constraint firstItem="P2q-FF-3d3" firstAttribute="leading" secondItem="weU-We-eXr" secondAttribute="trailing" constant="11" id="iUS-dO-YOe"/>
-                                                <constraint firstItem="weU-We-eXr" firstAttribute="leading" secondItem="hqn-jq-lGd" secondAttribute="leading" constant="105" id="kwR-gv-DZs"/>
+                                                <constraint firstItem="weU-We-eXr" firstAttribute="leading" secondItem="eKF-8f-lk7" secondAttribute="trailing" constant="8" id="PG5-Fx-XgM"/>
+                                                <constraint firstAttribute="bottomMargin" secondItem="eKF-8f-lk7" secondAttribute="bottom" constant="6" id="ep8-da-lRJ"/>
+                                                <constraint firstItem="P2q-FF-3d3" firstAttribute="trailing" secondItem="hqn-jq-lGd" secondAttribute="trailingMargin" constant="8" id="fLv-mH-Rvr"/>
+                                                <constraint firstItem="eKF-8f-lk7" firstAttribute="top" secondItem="hqn-jq-lGd" secondAttribute="topMargin" constant="6" id="h9A-g0-4M7"/>
+                                                <constraint firstItem="P2q-FF-3d3" firstAttribute="leading" secondItem="weU-We-eXr" secondAttribute="trailing" constant="8" id="iUS-dO-YOe"/>
                                                 <constraint firstAttribute="bottom" secondItem="weU-We-eXr" secondAttribute="bottom" id="xDa-xi-lHS"/>
                                             </constraints>
                                         </tableViewCellContentView>
                                     </tableViewCell>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="5To-8g-yGx">
-                                        <rect key="frame" x="0.0" y="205.33333333333334" width="414" height="50"/>
+                                        <rect key="frame" x="0.0" y="205.33333206176758" width="414" height="50"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5To-8g-yGx" id="hnE-2h-G77">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="49.666666666666664"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="50"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="摘要" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j89-tM-Che">
-                                                    <rect key="frame" x="43" y="14" width="54" height="21"/>
+                                                    <rect key="frame" x="20" y="17" width="89" height="15"/>
                                                     <constraints>
-                                                        <constraint firstAttribute="width" constant="54" id="vr9-VH-V3L"/>
+                                                        <constraint firstAttribute="width" constant="89" id="vr9-VH-V3L"/>
                                                     </constraints>
                                                     <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                     <nil key="textColor"/>
                                                     <nil key="highlightedColor"/>
                                                 </label>
                                                 <view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9Wf-8S-tJ9">
-                                                    <rect key="frame" x="105" y="0.0" width="1" height="49"/>
+                                                    <rect key="frame" x="117" y="0.0" width="1" height="49"/>
                                                     <color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="calibratedRGB"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="1" id="bfK-wO-keP"/>
-                                                        <constraint firstAttribute="height" constant="49" id="onb-Ld-PFX"/>
                                                     </constraints>
                                                 </view>
                                                 <textField opaque="NO" clipsSubviews="YES" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="QW9-uT-w7q">
-                                                    <rect key="frame" x="117" y="9" width="289" height="30"/>
+                                                    <rect key="frame" x="126" y="12" width="276" height="24"/>
                                                     <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
-                                                    <nil key="textColor"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="24" id="VQs-GS-MPC"/>
+                                                    </constraints>
                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                     <textInputTraits key="textInputTraits" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
                                                 </textField>
                                             </subviews>
                                             <constraints>
-                                                <constraint firstItem="j89-tM-Che" firstAttribute="centerY" secondItem="9Wf-8S-tJ9" secondAttribute="centerY" id="0MR-b4-SYU"/>
-                                                <constraint firstAttribute="bottom" secondItem="9Wf-8S-tJ9" secondAttribute="bottom" id="4K8-Ms-Dy8"/>
+                                                <constraint firstAttribute="bottom" secondItem="9Wf-8S-tJ9" secondAttribute="bottom" id="7FC-Ck-pSM"/>
+                                                <constraint firstItem="QW9-uT-w7q" firstAttribute="leading" secondItem="9Wf-8S-tJ9" secondAttribute="trailing" constant="8" id="8Q5-fg-4mo"/>
                                                 <constraint firstItem="QW9-uT-w7q" firstAttribute="top" secondItem="hnE-2h-G77" secondAttribute="topMargin" constant="1" id="9nR-Wk-UkC"/>
-                                                <constraint firstItem="9Wf-8S-tJ9" firstAttribute="leading" secondItem="j89-tM-Che" secondAttribute="trailing" constant="8" symbolic="YES" id="ICz-aN-B7Q"/>
-                                                <constraint firstItem="QW9-uT-w7q" firstAttribute="leading" secondItem="9Wf-8S-tJ9" secondAttribute="trailing" constant="11" id="JRo-bb-7DD"/>
-                                                <constraint firstItem="QW9-uT-w7q" firstAttribute="trailing" secondItem="hnE-2h-G77" secondAttribute="trailingMargin" id="L2j-mS-VT1"/>
-                                                <constraint firstItem="j89-tM-Che" firstAttribute="top" secondItem="hnE-2h-G77" secondAttribute="topMargin" constant="6" id="YAK-gK-kQu"/>
+                                                <constraint firstItem="QW9-uT-w7q" firstAttribute="trailing" secondItem="hnE-2h-G77" secondAttribute="trailingMargin" constant="8" id="CKB-Qg-st8"/>
                                                 <constraint firstItem="9Wf-8S-tJ9" firstAttribute="top" secondItem="hnE-2h-G77" secondAttribute="top" id="ilW-BI-5Wi"/>
-                                                <constraint firstItem="j89-tM-Che" firstAttribute="centerY" secondItem="QW9-uT-w7q" secondAttribute="centerY" id="inU-0A-5v6"/>
-                                                <constraint firstItem="j89-tM-Che" firstAttribute="leading" secondItem="hnE-2h-G77" secondAttribute="leadingMargin" constant="35" id="rkN-IC-U1z"/>
+                                                <constraint firstItem="j89-tM-Che" firstAttribute="top" secondItem="hnE-2h-G77" secondAttribute="topMargin" constant="6" id="oZ3-MP-xUl"/>
+                                                <constraint firstAttribute="bottomMargin" secondItem="j89-tM-Che" secondAttribute="bottom" constant="6" id="p30-Dx-y8B"/>
+                                                <constraint firstItem="QW9-uT-w7q" firstAttribute="centerY" secondItem="hnE-2h-G77" secondAttribute="centerY" id="qNs-Z4-2BK"/>
+                                                <constraint firstItem="j89-tM-Che" firstAttribute="leading" secondItem="hnE-2h-G77" secondAttribute="leadingMargin" id="rkN-IC-U1z"/>
+                                                <constraint firstItem="9Wf-8S-tJ9" firstAttribute="leading" secondItem="j89-tM-Che" secondAttribute="trailing" constant="8" id="wlj-gI-f0e"/>
                                             </constraints>
                                         </tableViewCellContentView>
                                     </tableViewCell>
@@ -461,14 +469,14 @@
                             <tableViewSection headerTitle="主题内容" id="5NA-G9-NMb">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="292" id="QrM-zd-ggt">
-                                        <rect key="frame" x="0.0" y="311.33333333333337" width="414" height="292"/>
+                                        <rect key="frame" x="0.0" y="311.33333206176758" width="414" height="292"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="QrM-zd-ggt" id="aDQ-GC-gCE">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="291.66666666666669"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="292"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <webView contentMode="scaleToFill" allowsInlineMediaPlayback="NO" mediaPlaybackRequiresUserAction="NO" mediaPlaybackAllowsAirPlay="NO" keyboardDisplayRequiresUserAction="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BuN-0G-Kfq">
-                                                    <rect key="frame" x="0.0" y="0.0" width="414" height="291"/>
+                                                    <rect key="frame" x="0.0" y="0.0" width="414" height="292"/>
                                                     <color key="backgroundColor" red="0.36078431370000003" green="0.38823529410000002" blue="0.4039215686" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                 </webView>
                                             </subviews>
@@ -508,7 +516,7 @@
                 <placeholder placeholderIdentifier="IBFirstResponder" id="nIO-g1-962" userLabel="First Responder" sceneMemberID="firstResponder"/>
                 <exit id="lp1-k7-1Bm" userLabel="Exit" sceneMemberID="exit"/>
             </objects>
-            <point key="canvasLocation" x="2709.5999999999999" y="-107.49625187406298"/>
+            <point key="canvasLocation" x="2708.6956521739135" y="-107.60869565217392"/>
         </scene>
         <!--主题内容-->
         <scene sceneID="WVJ-LU-xxx">
@@ -519,7 +527,7 @@
                         <viewControllerLayoutGuide type="bottom" id="yUj-ny-2sr"/>
                     </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="gR5-ax-AlI">
-                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="716"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                     </view>
@@ -557,25 +565,72 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Akk-vR-6JN">
-                                <rect key="frame" x="0.0" y="64" width="414" height="2"/>
+                                <rect key="frame" x="0.0" y="44" width="414" height="2"/>
                             </progressView>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i8Q-Zy-ou1">
+                                <rect key="frame" x="0.0" y="46" width="414" height="654"/>
+                                <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                            </view>
+                            <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eaE-vD-SEu">
+                                <rect key="frame" x="342" y="648" width="40" height="40"/>
+                                <color key="backgroundColor" red="0.98431372549999996" green="0.2784313725" blue="0.2784313725" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="40" id="8f7-bC-0xg"/>
+                                    <constraint firstAttribute="width" constant="40" id="UU5-lg-wTb"/>
+                                </constraints>
+                                <state key="normal" image="icon_tu"/>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <real key="value" value="20"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                                <connections>
+                                    <action selector="clickAttachmentBtn:" destination="NrM-as-KMX" eventType="touchUpInside" id="qIi-rT-Aa5"/>
+                                </connections>
+                            </button>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" pointerInteraction="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xcv-tG-eaX">
+                                <rect key="frame" x="0.0" y="700" width="414" height="36"/>
+                                <color key="backgroundColor" red="0.95294117649999999" green="0.95294117649999999" blue="0.95294117649999999" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="36" id="MEl-uW-98Y"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                <state key="normal" title="写评论">
+                                    <color key="titleColor" cocoaTouchSystemColor="darkTextColor"/>
+                                </state>
+                                <connections>
+                                    <action selector="replaySubject:" destination="NrM-as-KMX" eventType="touchUpInside" id="pNN-AF-Imz"/>
+                                </connections>
+                            </button>
                         </subviews>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                         <constraints>
+                            <constraint firstItem="i8Q-Zy-ou1" firstAttribute="leading" secondItem="3FR-QI-FR9" secondAttribute="leading" id="2Bl-6f-gcE"/>
+                            <constraint firstItem="i8Q-Zy-ou1" firstAttribute="top" secondItem="Akk-vR-6JN" secondAttribute="bottom" id="AE1-HJ-hDZ"/>
                             <constraint firstItem="Akk-vR-6JN" firstAttribute="top" secondItem="vpJ-pG-keM" secondAttribute="bottom" id="Dmz-Vi-Pop"/>
                             <constraint firstAttribute="trailing" secondItem="Akk-vR-6JN" secondAttribute="trailing" id="J5K-Y9-svZ"/>
+                            <constraint firstAttribute="trailing" secondItem="i8Q-Zy-ou1" secondAttribute="trailing" id="QGr-gd-PrC"/>
+                            <constraint firstAttribute="trailing" secondItem="xcv-tG-eaX" secondAttribute="trailing" id="WZ0-G6-Cle"/>
+                            <constraint firstItem="xcv-tG-eaX" firstAttribute="top" secondItem="eaE-vD-SEu" secondAttribute="bottom" constant="12" id="aoM-63-FKg"/>
+                            <constraint firstItem="xcv-tG-eaX" firstAttribute="top" secondItem="i8Q-Zy-ou1" secondAttribute="bottom" id="d9r-7V-WT7"/>
+                            <constraint firstItem="xcv-tG-eaX" firstAttribute="leading" secondItem="3FR-QI-FR9" secondAttribute="leading" id="dEU-cE-lQ9"/>
+                            <constraint firstAttribute="trailingMargin" secondItem="eaE-vD-SEu" secondAttribute="trailing" constant="12" id="fcw-Hj-yEU"/>
                             <constraint firstItem="Akk-vR-6JN" firstAttribute="leading" secondItem="3FR-QI-FR9" secondAttribute="leading" id="uFf-zV-Irc"/>
+                            <constraint firstItem="NJN-cN-NpB" firstAttribute="top" secondItem="xcv-tG-eaX" secondAttribute="bottom" id="vaa-9Z-8Zw"/>
                         </constraints>
                     </view>
                     <navigationItem key="navigationItem" title="帖子详细" id="Ay2-kD-eE6"/>
                     <connections>
+                        <outlet property="attachmentBtn" destination="eaE-vD-SEu" id="UKT-VQ-WJw"/>
                         <outlet property="progressView" destination="Akk-vR-6JN" id="DP8-IQ-Oya"/>
+                        <outlet property="webViewContainer" destination="i8Q-Zy-ou1" id="ScW-bZ-3t8"/>
                         <segue destination="XX2-U5-jZ2" kind="show" identifier="showReplyActionSegue" id="vTH-tB-kgB"/>
+                        <segue destination="AVx-tq-ogH" kind="show" identifier="showSubAttachmentActionSegue" id="YRv-7t-BC3"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="lRs-If-sZJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="2711.1999999999998" y="603.14842578710648"/>
+            <point key="canvasLocation" x="2710.144927536232" y="602.44565217391312"/>
         </scene>
         <!--回帖-->
         <scene sceneID="xzo-uP-W1c">
@@ -617,7 +672,7 @@
                 <navigationController automaticallyAdjustsScrollViewInsets="NO" id="WEC-RV-idi" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="sHw-y8-D2g">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -635,7 +690,7 @@
                 <navigationController automaticallyAdjustsScrollViewInsets="NO" id="XX2-U5-jZ2" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="FZc-TX-cBF">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -647,13 +702,73 @@
             </objects>
             <point key="canvasLocation" x="3559" y="603"/>
         </scene>
+        <!--附件列表-->
+        <scene sceneID="Wye-zE-rG9">
+            <objects>
+                <tableViewController id="jw1-bl-BWV" customClass="BBSSubjectAttachmentViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="ioC-Rq-Dxq">
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                        <prototypes>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="subjectAttachmentCell" id="Exz-Xm-k3F" customClass="BBSSubjectAttachmentViewCell" customModule="O2Platform" customModuleProvider="target">
+                                <rect key="frame" x="0.0" y="28" width="414" height="43.666667938232422"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Exz-Xm-k3F" id="CUi-FS-STd">
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.666667938232422"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_moren" translatesAutoresizingMaskIntoConstraints="NO" id="mWX-iw-NIE">
+                                            <rect key="frame" x="12" y="4" width="36" height="36"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="36" id="rQV-1r-6vR"/>
+                                                <constraint firstAttribute="width" constant="36" id="vUW-9L-17u"/>
+                                            </constraints>
+                                        </imageView>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="文件.pdf" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9q8-ZA-rPN">
+                                            <rect key="frame" x="72" y="13.333333333333336" width="54.333333333333343" height="17"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                            <nil key="textColor"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="9q8-ZA-rPN" firstAttribute="leading" secondItem="mWX-iw-NIE" secondAttribute="trailing" constant="24" id="Ppt-X1-TIK"/>
+                                        <constraint firstItem="mWX-iw-NIE" firstAttribute="leading" secondItem="CUi-FS-STd" secondAttribute="leading" constant="12" id="YLI-ml-reW"/>
+                                        <constraint firstItem="mWX-iw-NIE" firstAttribute="centerY" secondItem="CUi-FS-STd" secondAttribute="centerY" id="kbw-6C-qVb"/>
+                                        <constraint firstItem="9q8-ZA-rPN" firstAttribute="centerY" secondItem="CUi-FS-STd" secondAttribute="centerY" id="mgh-sU-k86"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <connections>
+                                    <outlet property="fileNameLabel" destination="9q8-ZA-rPN" id="udp-77-gAL"/>
+                                    <outlet property="typeImage" destination="mWX-iw-NIE" id="fpJ-37-UhH"/>
+                                </connections>
+                            </tableViewCell>
+                        </prototypes>
+                        <connections>
+                            <outlet property="dataSource" destination="jw1-bl-BWV" id="nTq-0N-7Fj"/>
+                            <outlet property="delegate" destination="jw1-bl-BWV" id="3e8-Pf-ueS"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="附件列表" id="Tal-mN-hrK">
+                        <barButtonItem key="leftBarButtonItem" title="关闭" id="lue-5t-S3f">
+                            <connections>
+                                <action selector="closeAction:" destination="jw1-bl-BWV" id="pTs-c1-rDk"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="lXO-nd-bq8" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="4465.217391304348" y="1297.0108695652175"/>
+        </scene>
         <!--Navigation Controller-->
         <scene sceneID="59C-FF-LRs">
             <objects>
                 <navigationController automaticallyAdjustsScrollViewInsets="NO" id="Owj-wk-JM6" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="ry5-8Z-U7w">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="56"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -665,12 +780,33 @@
             </objects>
             <point key="canvasLocation" x="3668" y="-107.49625187406298"/>
         </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="QHB-rq-K3F">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="AVx-tq-ogH" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationItem key="navigationItem" id="Cs6-ep-mlf"/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Nrt-Do-VFm">
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="jw1-bl-BWV" kind="relationship" relationship="rootViewController" id="shq-cV-eeK"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="bPo-wG-IaD" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="3557.971014492754" y="1296.1956521739132"/>
+        </scene>
     </scenes>
     <resources>
         <image name="icon_bbs_publish_item" width="16" height="16"/>
         <image name="icon_bbs_reply" width="24" height="24"/>
         <image name="icon_bbs_top" width="13" height="12"/>
         <image name="icon_bbs_view" width="24" height="24"/>
+        <image name="icon_moren" width="40" height="40"/>
+        <image name="icon_tu" width="22" height="22"/>
         <image name="todoedStatusIcon" width="32" height="32"/>
     </resources>
 </document>

+ 0 - 3
o2ios/O2Platform/App/BBS-论坛/c/BBSReplySubjectViewController.swift

@@ -30,14 +30,11 @@ class BBSReplySubjectViewController: UIViewController {
     override func viewDidLoad() {
         super.viewDidLoad()
         htmlEditorController  = ZSSRichTextEditor()
-        //htmlEditorController.setSelectedColor(<#T##color: UIColor!##UIColor!#>, tag: <#T##Int32#>)
         htmlEditorController.view.frame = self.view.frame
         self.view.addSubview(htmlEditorController.view)
         htmlEditorController.alwaysShowToolbar = true
         htmlEditorController.placeholder = "请输入回复内容"
         self.addChild(htmlEditorController)
-
-        
     }
 
     override func didReceiveMemoryWarning() {

+ 82 - 0
o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectAttachmentViewController.swift

@@ -0,0 +1,82 @@
+//
+//  BBSSubjectAttachmentViewController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/28.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import QuickLook
+import CocoaLumberjack
+
+class BBSSubjectAttachmentViewController: UITableViewController {
+    
+    
+    var attachmentList:[O2BBSSubjectAttachmentInfo] = []
+    
+    //预览文件
+    private lazy var previewVC: CloudFilePreviewController = {
+        return CloudFilePreviewController()
+    }()
+    
+    private lazy var viewModel: BBSViewModel = {
+       return BBSViewModel()
+   }()
+    
+    @IBAction func closeAction(_ sender: UIBarButtonItem) {
+        self.dismiss(animated: true, completion: nil)
+    }
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.tableView.tableFooterView = UIView()
+        
+    }
+
+    // MARK: - Table view data source
+
+    override func numberOfSections(in tableView: UITableView) -> Int {
+        
+        return 1
+    }
+
+    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        
+        return self.attachmentList.count
+    }
+    
+    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        if let cell = tableView.dequeueReusableCell(withIdentifier: "subjectAttachmentCell", for: indexPath) as? BBSSubjectAttachmentViewCell {
+            cell.setAttachment(file: self.attachmentList[indexPath.row])
+            return cell
+        }
+        return UITableViewCell()
+    }
+    
+    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        tableView.deselectRow(at: indexPath, animated: false)
+        self.showLoading()
+        self.viewModel
+            .downloadAttachment(att: self.attachmentList[indexPath.row])
+            .always {
+                self.hideLoading()
+        }.then({ (url)  in
+            let currentURL = NSURL(fileURLWithPath: url.path)
+            if QLPreviewController.canPreview(currentURL) {
+                self.previewVC.currentFileURLS.removeAll()
+                self.previewVC.currentFileURLS.append(currentURL)
+                self.previewVC.reloadData()
+                self.pushVC(self.previewVC)
+            }else {
+                self.showError(title: "当前文件类型不支持预览!")
+            }
+        }).catch { (err) in
+            DDLogError(err.localizedDescription)
+            self.showError(title: "下载文件失败!")
+        }
+    }
+
+     
+
+}

+ 1 - 1
o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectCreateTableViewController.swift

@@ -17,7 +17,7 @@ import CocoaLumberjack
 class BBSSubjectCreateTableViewController: UITableViewController {
 
     
-    let subjectcategory = ["讨论","投票","新闻","悬赏","辩论","灌水","知识","动态"]
+    let subjectcategory = ["讨论","新闻","灌水","知识","动态"]
     
     var sectionData:BBSectionListData?
     

+ 55 - 34
o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectDetailViewController.swift

@@ -18,53 +18,69 @@ class BBSSubjectDetailViewController: BaseWebViewUIViewController {
     
     
     @IBOutlet weak var progressView: UIProgressView!
-    
+    @IBOutlet weak var webViewContainer: UIView!
+    @IBOutlet weak var attachmentBtn: UIButton!
     var loadUrl:String?
     
-    var window:UIWindow?
-    
-    var button:UIButton?
-    
     var subject:BBSSubjectData? {
         didSet {
             loadUrl = AppDelegate.o2Collect.genrateURLWithWebContextKey(DesktopContext.DesktopContextKey, query: DesktopContext.bbsItemDetailQuery, parameter: ["##subjectId##":subject?.id as AnyObject])
         }
     }
     
+    private lazy var viewModel: BBSViewModel = {
+        return BBSViewModel()
+    }()
+    private var attachmentList: [O2BBSSubjectAttachmentInfo] = []
+    
     override func viewWillAppear(_ animated: Bool) {
-        self.window?.isHidden = false
+        //监控进度
+        webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
     }
     
     override func viewWillDisappear(_ animated: Bool) {
-        self.window?.isHidden = true
+        webView.removeObserver(self, forKeyPath: "estimatedProgress")
     }
-
+    
+    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
+       if keyPath == "estimatedPrgress" {
+           progressView.isHidden = webView.estimatedProgress == 1
+           progressView.setProgress(Float(webView.estimatedProgress), animated: true)
+       }
+   }
+    
+    
     override func viewDidLoad() {
         super.viewDidLoad()
-        createButton()
+        self.attachmentBtn.isHidden = true
+        if let subjectId = self.subject?.id {
+            self.viewModel.getSubjectAttachmentList(subjectId: subjectId)
+                .then { attachments  in
+                    if attachments.count > 0 {
+                        self.attachmentList = attachments
+                        self.attachmentBtn.isHidden = false
+                    }
+            }.catch { (error) in
+                DDLogError(error.localizedDescription)
+            }
+        }
+        
         self.theWebView()
-        self.view = webView
+        self.webViewContainer.addSubview(self.webView)
+        
     }
     
-    func createButton(){
-        let width = SCREEN_WIDTH
-        let height = SCREEN_HEIGHT
-        self.button  = UIButton(frame: CGRect(x: 0,y: 0,width: 40,height: 40))
-        self.button?.setImage(UIImage(named: "icon_bbs_reply_white"), for: UIControl.State())
-        self.button?.addTarget(self, action: #selector(replyAction), for: .touchUpInside)
-        self.window = UIWindow(frame: CGRect(x: width - 60, y: height - 60, width: 40, height: 40))
-        self.window?.windowLevel = UIWindow.Level.alert + 1
-        self.window?.backgroundColor = UIColor.green
-        self.window?.layer.cornerRadius = 20
-        self.window?.layer.masksToBounds = true
-        self.window?.addSubview(self.button!)
-        self.window?.makeKeyAndVisible()
-    }
     
-    func replyAction(sender:Any?){
-        self.performSegue(withIdentifier:"showReplyActionSegue", sender: nil)
+    @IBAction func clickAttachmentBtn(_ sender: UIButton) {
+        DDLogDebug("点击附件列表")
+        if self.attachmentList.count > 0 {
+            self.performSegue(withIdentifier: "showSubAttachmentActionSegue", sender: nil)
+        }else {
+            self.showError(title: "没有附件!")
+        }
     }
     
+    
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
         if segue.identifier == "showReplyActionSegue" {
             let navVC = segue.destination as! ZLNavigationController
@@ -73,6 +89,10 @@ class BBSSubjectDetailViewController: BaseWebViewUIViewController {
             if let parentId = sender {
                 destVC.parentId = parentId as? String
             }
+        }else if segue.identifier == "showSubAttachmentActionSegue" {
+            let navVC = segue.destination as! ZLNavigationController
+            let destVC = navVC.topViewController as! BBSSubjectAttachmentViewController
+            destVC.attachmentList = self.attachmentList
         }
     }
     
@@ -101,17 +121,18 @@ class BBSSubjectDetailViewController: BaseWebViewUIViewController {
         loadDetailSubject()
     }
 
+    //写评论
+    @IBAction func replaySubject(_ sender: UIButton) {
+        self.performSegue(withIdentifier:"showReplyActionSegue", sender: nil)
+    }
+    
+    
     override func didReceiveMemoryWarning() {
         super.didReceiveMemoryWarning()
         // Dispose of any resources that can be recreated.
     }
     
-    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
-        if keyPath == "estimatedPrgress" {
-            progressView.isHidden = webView.estimatedProgress == 1
-            progressView.setProgress(Float(webView.estimatedProgress), animated: true)
-        }
-    }
+   
     
 
 }
@@ -121,12 +142,12 @@ class BBSSubjectDetailViewController: BaseWebViewUIViewController {
 extension BBSSubjectDetailViewController:WKNavigationDelegate,WKUIDelegate {
     
     func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
-        DDLogDebug("didFailProvisionalNavigation \(navigation)  error = \(error)")
+        DDLogDebug("didFailProvisionalNavigation \(String(describing: navigation))  error = \(error)")
     }
 
     
     func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
-        DDLogDebug("didStartProvisionalNavigation \(navigation)")
+        DDLogDebug("didStartProvisionalNavigation \(String(describing: navigation))")
     }
     
     func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {

+ 4 - 3
o2ios/O2Platform/App/BBS-论坛/c/BBSSubjectListViewController.swift

@@ -77,14 +77,14 @@ class BBSSubjectListViewController: UIViewController {
         self.button?.addTarget(self, action: #selector(createAction), for: .touchUpInside)
         self.window = UIWindow(frame: CGRect(x: width - 60, y: height - 60, width: 40, height: 40))
         self.window?.windowLevel = UIWindow.Level.alert + 1
-        self.window?.backgroundColor = UIColor.green
+        self.window?.backgroundColor = base_color
         self.window?.layer.cornerRadius = 20
         self.window?.layer.masksToBounds = true
         self.window?.addSubview(self.button!)
         self.window?.makeKeyAndVisible()
     }
     
-    func createAction(sender:Any?){
+    @objc func createAction(sender:Any?){
         self.performSegue(withIdentifier: "showCreateSubjectSegue", sender: nil)
     }
     
@@ -92,7 +92,7 @@ class BBSSubjectListViewController: UIViewController {
         self.subjects.removeAll()
         let url = AppDelegate.o2Collect.generateURLWithAppContextKey(BBSContext.bbsContextKey, query: BBSContext.subjectFromSectionByPageQuery, parameter: ["##pageNumber##":self.pageModel.pageNumber.toString as AnyObject,"##pageSize##":self.pageModel.pageSize.toString as AnyObject])
         Alamofire.request(url!, method: .put, parameters: ["sectionId":(sectionData?.id)!,"withTopSubject":true], encoding: JSONEncoding.default, headers: nil).responseJSON { (response) in
-            debugPrint("sectionId = \(self.sectionData?.id)!")
+            debugPrint("sectionId = \(String(describing: self.sectionData?.id))!")
             debugPrint(response)
             switch response.result {
             case .success(let val):
@@ -184,6 +184,7 @@ extension BBSSubjectListViewController:UITableViewDataSource {
 
 extension BBSSubjectListViewController:UITableViewDelegate {
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        tableView.deselectRow(at: indexPath, animated: false)
         let subject = subjects[indexPath.row]
         self.performSegue(withIdentifier: "showSubjectDetailSegue", sender: subject)
     }

+ 176 - 141
o2ios/O2Platform/App/BBS-论坛/m/OOBBSModels.swift

@@ -8,24 +8,27 @@
 
 import Foundation
 import HandyJSON
+import ObjectMapper
+
+
 // MARK:- 读取Section列表参数
 class SubjectsParameter {
-    var sectionId:String?
-    var withTopSubject:Bool?
-    var pageParameter:CommonPageParameter?
+    var sectionId: String?
+    var withTopSubject: Bool?
+    var pageParameter: CommonPageParameter?
 }
 
 
 class CommonPageParameter {
     //当前页
-    var currentPageNo:Int = 1
+    var currentPageNo: Int = 1
     //每页行数
-    let countByPage:Int = 20
+    let countByPage: Int = 20
     //总页数
     private var totalPageCount = 1
-    
+
     //总行数
-    var totalLineCount:Int = -1 {
+    var totalLineCount: Int = -1 {
         didSet {
             if totalLineCount > 0 && totalLineCount > countByPage * currentPageNo {
                 //总页数
@@ -33,168 +36,200 @@ class CommonPageParameter {
             }
         }
     }
-    
+
     init() {
-        
+
     }
-    
+
     func calcNextPageNo() -> Bool {
         if currentPageNo < totalPageCount {
             currentPageNo += 1
             return true
-        }else{
+        } else {
             return false
         }
     }
 }
 
 // MARK:- O2ForumInfo
-class O2ForumInfo:NSObject,DataModel {
-    var createTime : String?
-    var creatorName : String?
-    var forumColor : String?
-    var forumIndexStyle : String?
-    var forumManagerName : String?
-    var forumName : String?
-    var forumNotice : String?
-    var forumStatus : String?
-    var forumVisible : String?
-    var id : String?
-    var indexListStyle : String?
-    var indexRecommendable : Bool?
-    var orderNumber : Int?
-    var replyNeedAudit : Bool?
-    var replyPublishAble : String?
-    var replyTotal : Int?
-    var replyTotalToday : Int?
-    var sectionCreateAble : Bool?
-    var sectionInfoList : [O2SectionInfo]?
-    var sectionTotal : Int?
-    var subjectNeedAudit : Bool?
-    var subjectPublishAble : String?
-    var subjectTotal : Int?
-    var subjectTotalToday : Int?
-    var subjectType : String?
-    var typeCategory : String?
-    var updateTime : String?
-    
+class O2ForumInfo: NSObject, DataModel {
+    var createTime: String?
+    var creatorName: String?
+    var forumColor: String?
+    var forumIndexStyle: String?
+    var forumManagerName: String?
+    var forumName: String?
+    var forumNotice: String?
+    var forumStatus: String?
+    var forumVisible: String?
+    var id: String?
+    var indexListStyle: String?
+    var indexRecommendable: Bool?
+    var orderNumber: Int?
+    var replyNeedAudit: Bool?
+    var replyPublishAble: String?
+    var replyTotal: Int?
+    var replyTotalToday: Int?
+    var sectionCreateAble: Bool?
+    var sectionInfoList: [O2SectionInfo]?
+    var sectionTotal: Int?
+    var subjectNeedAudit: Bool?
+    var subjectPublishAble: String?
+    var subjectTotal: Int?
+    var subjectTotalToday: Int?
+    var subjectType: String?
+    var typeCategory: String?
+    var updateTime: String?
+
     required override init() {
-        
+
     }
 }
 
 
 // MARK:- O2SectionInfo
-class O2SectionInfo:NSObject,DataModel {
-    var createTime : String?
-    var creatorName : String?
-    var forumId : String?
-    var forumName : String?
-    var icon : String?
-    var id : String?
-    var indexRecommendable : Bool?
-    var mainSectionId : String?
-    var mainSectionName : String?
-    var moderatorNames : String?
-    var orderNumber : Int?
-    var replyNeedAudit : Bool?
-    var replyPublishAble : String?
-    var replyTotal : Int?
-    var replyTotalToday : Int?
-    var sectionDescription : String?
-    var sectionLevel : String?
-    var sectionName : String?
-    var sectionNotice : String?
-    var sectionStatus : String?
-    var sectionType : String?
-    var sectionVisible : String?
-    var subSectionCreateAble : Bool?
-    var subjectNeedAudit : Bool?
-    var subjectPublishAble : String?
-    var subjectTotal : Int?
-    var subjectTotalToday : Int?
-    var subjectType : String?
-    var typeCategory : String?
-    var updateTime : String?
+class O2SectionInfo: NSObject, DataModel {
+    var createTime: String?
+    var creatorName: String?
+    var forumId: String?
+    var forumName: String?
+    var icon: String?
+    var id: String?
+    var indexRecommendable: Bool?
+    var mainSectionId: String?
+    var mainSectionName: String?
+    var moderatorNames: String?
+    var orderNumber: Int?
+    var replyNeedAudit: Bool?
+    var replyPublishAble: String?
+    var replyTotal: Int?
+    var replyTotalToday: Int?
+    var sectionDescription: String?
+    var sectionLevel: String?
+    var sectionName: String?
+    var sectionNotice: String?
+    var sectionStatus: String?
+    var sectionType: String?
+    var sectionVisible: String?
+    var subSectionCreateAble: Bool?
+    var subjectNeedAudit: Bool?
+    var subjectPublishAble: String?
+    var subjectTotal: Int?
+    var subjectTotalToday: Int?
+    var subjectType: String?
+    var typeCategory: String?
+    var updateTime: String?
     required override init() {
-        
+
     }
 }
 
 
 // MARK:- O2BBSubjectDetailInfo
-class O2BBSubjectDetailInfo:NSObject,DataModel {
-    var lastSubject:O2BBSSubjectInfo?
-    var currentSubject:O2BBSSubjectInfo?
-    var nextSubject:O2BBSSubjectInfo?
+class O2BBSubjectDetailInfo: NSObject, DataModel {
+    var lastSubject: O2BBSSubjectInfo?
+    var currentSubject: O2BBSSubjectInfo?
+    var nextSubject: O2BBSSubjectInfo?
     required override init() {
-        
+
     }
 }
 
 // MARK:- O2BBSSubjectInfo
-class O2BBSSubjectInfo:NSObject,DataModel {
-    var acceptReplyId : String?
-    var attachmentList : [AnyObject]?
-    var auditorName : String?
-    var auditorNameShort : String?
-    var bBSIndexSetterName : String?
-    var bBSIndexSetterNameShort : String?
-    var createTime : String?
-    var creatorName : String?
-    var creatorNameShort : String?
-    var forumId : String?
-    var forumIndexSetterName : String?
-    var forumName : String?
-    var hostIp : String?
-    var hot : Int?
-    var id : String?
-    var isCompleted : Bool?
-    var isCreamSubject : Bool?
-    var isOriginalSubject : Bool?
-    var isRecommendSubject : Bool?
-    var isTopSubject : Bool?
-    var latestReplyId : String?
-    var latestReplyTime : String?
-    var latestReplyUser : String?
-    var latestReplyUserShort : String?
-    var machineName : String?
-    var mainSectionId : String?
-    var mainSectionName : String?
-    var orderNumber : Int?
-    var originalSetterName : String?
-    var originalSetterNameShort : String?
-    var picId : String?
-    var recommendTime : String?
-    var recommendToBBSIndex : Bool?
-    var recommendToForumIndex : Bool?
-    var recommendorName : String?
-    var replyTotal : Int?
-    var screamSetterName : String?
-    var screamSetterNameShort : String?
-    var screamSetterTime : String?
-    var sectionId : String?
-    var sectionName : String?
-    var stopReply : Bool?
-    var subjectAuditStatus : String?
-    var subjectStatus : String?
-    var summary : String?
-    var systemType : String?
-    var title : String?
-    var topToBBS : Bool?
-    var topToForum : Bool?
-    var topToMainSection : Bool?
-    var topToSection : Bool?
-    var type : String?
-    var typeCategory : String?
-    var updateTime : String?
-    var viewTotal : Int?
-    var voteCount : Int?
-    var votePersonVisible : Bool?
-    var voteResultVisible : Bool?
-    var voted : Bool?
-    required override init() {
-        
-    }
+class O2BBSSubjectInfo: NSObject, DataModel {
+    var acceptReplyId: String?
+    var attachmentList: [AnyObject]?
+    var auditorName: String?
+    var auditorNameShort: String?
+    var bBSIndexSetterName: String?
+    var bBSIndexSetterNameShort: String?
+    var createTime: String?
+    var creatorName: String?
+    var creatorNameShort: String?
+    var forumId: String?
+    var forumIndexSetterName: String?
+    var forumName: String?
+    var hostIp: String?
+    var hot: Int?
+    var id: String?
+    var isCompleted: Bool?
+    var isCreamSubject: Bool?
+    var isOriginalSubject: Bool?
+    var isRecommendSubject: Bool?
+    var isTopSubject: Bool?
+    var latestReplyId: String?
+    var latestReplyTime: String?
+    var latestReplyUser: String?
+    var latestReplyUserShort: String?
+    var machineName: String?
+    var mainSectionId: String?
+    var mainSectionName: String?
+    var orderNumber: Int?
+    var originalSetterName: String?
+    var originalSetterNameShort: String?
+    var picId: String?
+    var recommendTime: String?
+    var recommendToBBSIndex: Bool?
+    var recommendToForumIndex: Bool?
+    var recommendorName: String?
+    var replyTotal: Int?
+    var screamSetterName: String?
+    var screamSetterNameShort: String?
+    var screamSetterTime: String?
+    var sectionId: String?
+    var sectionName: String?
+    var stopReply: Bool?
+    var subjectAuditStatus: String?
+    var subjectStatus: String?
+    var summary: String?
+    var systemType: String?
+    var title: String?
+    var topToBBS: Bool?
+    var topToForum: Bool?
+    var topToMainSection: Bool?
+    var topToSection: Bool?
+    var type: String?
+    var typeCategory: String?
+    var updateTime: String?
+    var viewTotal: Int?
+    var voteCount: Int?
+    var votePersonVisible: Bool?
+    var voteResultVisible: Bool?
+    var voted: Bool?
+    
+    required override init() {}
 }
 
+
+//附件对象列表
+class O2BBSSubjectAttachmentInfo: NSObject, DataModel {
+    @objc var id: String?
+    @objc var createTime: String?
+    @objc var updateTime: String?
+    @objc var lastUpdateTime: String?
+    @objc var storage: String?
+    @objc var forumId: String?
+    @objc var forumName: String?
+    @objc var sectionId: String?
+    @objc var sectionName: String?
+    @objc var mainSectionId: String?
+    @objc var mainSectionName: String?
+    @objc var subjectId: String?
+    @objc var title: String?
+    @objc var name: String?
+    @objc var fileName: String?
+    @objc var fileHost: String?
+    @objc var filePath: String?
+    @objc var storageName: String?
+    @objc var desc: String?
+    @objc var creatorUid: String?
+    @objc var ext: String?
+    var length: Int?
+
+    required override init() {}
+
+    func mapping(mapper: HelpingMapper) {
+        mapper <<< self.ext <-- "extension"
+        mapper <<< self.desc <-- "description"
+    }
+}

+ 72 - 0
o2ios/O2Platform/App/BBS-论坛/v/BBSSubjectAttachmentViewCell.swift

@@ -0,0 +1,72 @@
+//
+//  BBSSubjectAttachmentViewCell.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/28.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+
+class BBSSubjectAttachmentViewCell: UITableViewCell {
+
+    @IBOutlet weak var fileNameLabel: UILabel!
+    @IBOutlet weak var typeImage: 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 setAttachment(file: O2BBSSubjectAttachmentInfo)  {
+        self.fileNameLabel.text = file.name
+        self.setFileTypeImage(ext: file.ext)
+    }
+
+    private func setFileTypeImage(ext: String?) {
+        if let type = ext {
+            switch type {
+            case "jpg", "png", "jepg", "gif":
+                self.typeImage.image = UIImage(named: "icon_img")
+                break
+            case "html":
+                self.typeImage.image = UIImage(named: "icon_html")
+                break
+            case "xls", "xlsx":
+                self.typeImage.image = UIImage(named: "icon_excel")
+                break
+            case "doc", "docx":
+                self.typeImage.image = UIImage(named: "icon_word")
+                break
+            case "ppt", "pptx":
+                self.typeImage.image = UIImage(named: "icon_ppt")
+                break
+            case "pdf":
+                self.typeImage.image = UIImage(named: "icon_pdf")
+                break
+            case "mp4":
+                self.typeImage.image = UIImage(named: "icon_mp4")
+                break
+            case "mp3":
+                self.typeImage.image = UIImage(named: "icon_mp3")
+                break
+            case "zip", "rar", "7z":
+                self.typeImage.image = UIImage(named: "icon_zip")
+                break
+            default :
+                self.typeImage.image = UIImage(named: "icon_moren")
+                break
+            }
+        }else {
+            self.typeImage.image = UIImage(named: "icon_moren")
+        }
+    }
+    
+}

+ 62 - 0
o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarEditRemarkViewController.swift

@@ -0,0 +1,62 @@
+//
+//  OOCalendarEditRemarkViewController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/11.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+import UIKit
+
+protocol ContentEditBackDelegate {
+    func backEditContent(contentHtml:String)
+}
+class OOCalendarEditRemarkViewController: ZSSRichTextEditor {
+    var contentHTML:String?
+       
+    var backDelegate:ContentEditBackDelegate?
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        //self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "保存", style: .plain, target: self, action: #selector(tapSave))
+        self.navigationItem.title = "编辑内容"
+        
+        if let content = contentHTML {
+                   self.setHTML(content)
+               }
+        // Do any additional setup after loading the view.
+    }
+    
+
+    @IBAction func save(_ sender: Any) {
+        self.dismiss(animated: true) {
+            ()-> Void in
+            print("save.....")
+             let dataDict = ["contentHtml" : self.getHTML()]
+            NotificationCenter.default.post(name:Notification.Name(rawValue: "RegisterCompletionNotification"),object:nil,userInfo:dataDict)
+        }
+    }
+    
+    
+    @IBAction func cancel(_ sender: Any) {
+        self.dismiss(animated: true, completion: {print("cancel....")})
+    }
+    
+    
+    func tapSave(){
+        print("dddd");
+        
+        
+    }
+    
+    
+    /*
+    // MARK: - Navigation
+
+    // In a storyboard-based application, you will often want to do a little preparation before navigation
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        // Get the new view controller using segue.destination.
+        // Pass the selected object to the new view controller.
+    }
+    */
+
+}

+ 33 - 8
o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarEventViewController.swift

@@ -9,6 +9,7 @@
 import UIKit
 import CocoaLumberjack
 import O2OA_Auth_SDK
+import WebKit
 
 
 struct Options {
@@ -88,11 +89,14 @@ class OOCalendarEventViewController: UITableViewController {
     @IBOutlet weak var evenEndTimeStackView: UIStackView!
     @IBOutlet weak var eventColorStackView: UIStackView!
     @IBOutlet weak var weekDaysStackView: UIStackView!
-    @IBOutlet weak var eventRemark: UITextField!
+//    @IBOutlet weak var eventRemark: UITextField!
+    var eventRemark:String = ""
     @IBOutlet weak var untilDateLabel: UILabel!
     @IBOutlet weak var untilDateStackView: UIStackView!
     @IBOutlet weak var deleteBtn: UIButton!
     
+    @IBOutlet weak var webRemark: UIWebView!
+    
     override func viewDidLoad() {
         super.viewDidLoad()
         if eventInfo != nil && eventInfo?.id != nil {
@@ -124,8 +128,8 @@ class OOCalendarEventViewController: UITableViewController {
         //隐藏输入法
         eventTitle.delegate = self
         eventTitle.returnKeyType = .done
-        eventRemark.delegate = self
-        eventRemark.returnKeyType = .done
+//        eventRemark.delegate = self
+//        eventRemark.returnKeyType = .done
         
         eventStartTime.text = Date().toString("yyyy-MM-dd HH:mm")
         eventEndTime.text = Date().add(component: .hour, value: 1).toString("yyyy-MM-dd HH:mm")
@@ -181,7 +185,7 @@ class OOCalendarEventViewController: UITableViewController {
             }
         })
         viewModel.getMyCalendarList().then { (calendars) in
-            self.calendarList = calendars.myCalendars ?? []
+            self.calendarList = (calendars.myCalendars ?? []) + (calendars.unitCalendars ?? [])
             self.calendarPickerView.reloadAllComponents()
             //初始化颜色
             if !self.calendarList.isEmpty {
@@ -201,8 +205,21 @@ class OOCalendarEventViewController: UITableViewController {
         }.catch { (error) in
             DDLogError(error.localizedDescription)
         }
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(registerCompletion), name: Notification.Name(rawValue:"RegisterCompletionNotification"),
+                                                             object: nil)
+
+    }
+
+    @objc func registerCompletion(notification:Notification){
+        let theData = notification.userInfo!
+        let contentHtml = theData["contentHtml"] as! String
+        print("contentHtml =" , contentHtml)
+        self.eventRemark = contentHtml
+        self.webRemark.loadHTMLString(contentHtml == nil ? "" : contentHtml, baseURL: nil)
     }
 
+    
     override func didReceiveMemoryWarning() {
         super.didReceiveMemoryWarning()
         // Dispose of any resources that can be recreated.
@@ -210,7 +227,10 @@ class OOCalendarEventViewController: UITableViewController {
     }
     
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
-        
+        let navVC = segue.destination as! ZLNavigationController
+        let destVC = navVC.topViewController as! OOCalendarEditRemarkViewController
+         print(self.eventRemark)
+        destVC.contentHTML = self.eventRemark
     }
     
     
@@ -336,7 +356,8 @@ class OOCalendarEventViewController: UITableViewController {
                 return
             }
             let allday = eventAllDaySwitch.isOn
-            let remark = eventRemark.text ?? ""
+            //let remark = eventRemark.text ?? ""
+            let remark = eventRemark
             let startTime = eventStartTime.text ?? ""
             let endTime = eventEndTime.text ?? ""
            
@@ -384,7 +405,8 @@ class OOCalendarEventViewController: UITableViewController {
             return
         }
         let allday = eventAllDaySwitch.isOn
-        let remark = eventRemark.text ?? ""
+        // remark = eventRemark.text ?? ""
+        let remark = eventRemark
         let startTime = eventStartTime.text ?? ""
         let endTime = eventEndTime.text ?? ""
         let start = allday ? Date.date(startTime, formatter: "yyyy-MM-dd") : Date.date(startTime, formatter: "yyyy-MM-dd HH:mm")
@@ -550,7 +572,10 @@ class OOCalendarEventViewController: UITableViewController {
                 self.repeatPickerView.selectRow(index, inComponent: 0, animated: true)
             }
         }
-        eventRemark.text = eventInfo?.comment
+        // eventRemark.text = eventInfo?.comment
+         eventRemark = eventInfo?.comment as! String
+         self.webRemark.loadHTMLString(eventRemark == nil ? "" : eventRemark, baseURL: nil)
+
     }
     
     private func rruleDecode(rrule: String) {

+ 11 - 0
o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarLeftMenuController.swift

@@ -120,6 +120,10 @@ class OOCalendarLeftMenuController: UITableViewController {
         if indexPath.section == 0 {
             self.performSegue(withIdentifier: "showCalendarSegue", sender: "update")
         }
+        
+        if indexPath.section == 1 {
+            self.performSegue(withIdentifier: "showCalendarSegue", sender: "updateDept")
+        }
         tableView.deselectRow(at: indexPath, animated: false)
     }
 
@@ -137,6 +141,13 @@ class OOCalendarLeftMenuController: UITableViewController {
                     let row  = tableView.indexPathForSelectedRow!.row
                     cc.calendarInfo = self.myCalendarList[row]
                 }
+                
+                if type == "updateDept"{
+                    let cc = segue.destination as! OOCalendarViewController
+                    let row  = tableView.indexPathForSelectedRow!.row
+                    cc.calendarInfo = self.departmentCalendarList[row]
+                }
+
             }
         }
     }

+ 405 - 54
o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarViewController.swift

@@ -18,18 +18,83 @@ class OOCalendarViewController: UITableViewController {
     }()
     var calendarInfo: OOCalendarInfo?
     private var colorValue = "#428ffc"
+    private var count = 0
 
-    // MARK: - IB
-    @IBOutlet weak var calendarNameField: UITextField!
-    @IBOutlet weak var calendarIsOpenSwitch: UISwitch!
-    @IBOutlet weak var calendarColorStackView: UIStackView!
-    @IBOutlet weak var calendarRemarkField: UITextField!
-    @IBOutlet weak var calendarDeleteBtn: UIButton!
-    @IBAction func deleteBtnTap(_ sender: UIButton) {
-        showDefaultConfirm(title: "删除日历", message: "确定要删除当前日历吗,会同时删除该日历下的日程事件?") { (action) in
-            self.deleteCalendar()
-        }
+    override func numberOfSections(in tableView: UITableView) -> Int {
+       // #warning Incomplete implementation, return the number of sections
+       return 3
+    }
+
+    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+       // #warning Incomplete implementation, return the number of rows
+           if  section == 0 {
+                return 5
+            }else if section == 1 {
+                return count
+            }else{
+                return 1
+            }
     }
+
+
+    // MARK: - IB
+      @IBOutlet weak var calendarNameField: UITextField!
+      @IBOutlet weak var calendarIsOpenSwitch: UISwitch!
+      @IBOutlet weak var calendarColorStackView: UIStackView!
+      @IBOutlet weak var calendarRemarkField: UITextField!
+      @IBOutlet weak var calendarDeleteBtn: UIButton!
+      
+    
+      @IBOutlet weak var calendarTypeField: UITextField!
+      @IBOutlet weak var calendarOrgField: UITextField!
+      @IBOutlet weak var calendarManagerField: UITextField!
+      @IBOutlet weak var calendarScopeField: UITextField!
+      @IBOutlet weak var calendarNewScopeField: UITextField!
+      
+      @IBOutlet weak var calendarStatusSwitch: UISwitch!
+      
+      @IBOutlet weak var calendarIsOpenBtn: UIButton!
+      
+      @IBAction func editRemarkBtn(_ sender: Any) {
+            self.performSegue(withIdentifier: "ShowEditRemark", sender: nil)
+      }
+      
+
+      
+      
+      @IBAction func deleteBtnTap(_ sender: UIButton) {
+          showDefaultConfirm(title: "删除日历", message: "确定要删除当前日历吗,会同时删除该日历下的日程事件?") { (action) in
+              self.deleteCalendar()
+          }
+      }
+      
+      //选择是否公开
+      @IBAction func selectType(_ sender: Any) {
+          let alertController = UIAlertController(title: "请选择类型", message: "",preferredStyle:.actionSheet)
+          var selectStyle = UIAlertAction.Style.default
+          selectStyle = (calendarTypeField.text == "个人日历") ?  UIAlertAction.Style.default:UIAlertAction.Style.destructive
+          let personAction = UIAlertAction(title: "个人日历", style:selectStyle, handler: {action in
+          self.calendarTypeField.text =  action.title
+          self.count = 0
+          let section = NSIndexSet(index: 1)
+          self.tableView.beginUpdates()
+          self.tableView.reloadSections(section as IndexSet, with: .automatic)
+          self.tableView.endUpdates()
+         })
+          selectStyle = (calendarTypeField.text == "组织日历") ? UIAlertAction.Style.default:UIAlertAction.Style.destructive
+         let orgAction = UIAlertAction(title: "组织日历", style: selectStyle, handler: {action in
+              self.calendarTypeField.text = action.title
+              self.count = 4
+              let section = NSIndexSet(index: 1)
+              self.tableView.beginUpdates()
+              self.tableView.reloadSections(section as IndexSet, with: .automatic)
+              self.tableView.endUpdates()
+         })
+         alertController.addAction(personAction)
+         alertController.addAction(orgAction)
+         self.present(alertController, animated: true, completion: nil)
+      }
+
     
     
     override func viewDidLoad() {
@@ -47,18 +112,26 @@ class OOCalendarViewController: UITableViewController {
             loadCalendarInfoFromNet()
             calendarDeleteBtn.isHidden = false
         }else {
+            self.calendarInfo = OOCalendarInfo.init()
             calendarDeleteBtn.isHidden = true
         }
+
         
         //隐藏输入法
         calendarNameField.delegate = self
         calendarNameField.returnKeyType = .done
+        
+        calendarTypeField.delegate = self
+        calendarTypeField.returnKeyType = .done
+        
         calendarRemarkField.delegate = self
         calendarRemarkField.returnKeyType = .done
+        
         calendarColorStackView?.subviews.forEach({ (colorView) in
             colorView.isUserInteractionEnabled = true
             colorView.addGestureRecognizer(UITapGestureRecognizer(target: self, action:#selector(tapColorView)))
         })
+
     }
 
     override func didReceiveMemoryWarning() {
@@ -74,38 +147,61 @@ class OOCalendarViewController: UITableViewController {
     
     @objc func tapSave() {
         hideKeyboard()
-        let name = calendarNameField.text
-        let isopen = calendarIsOpenSwitch.isOn
-        let type = "PERSON"
-        let remark = calendarRemarkField.text
-        if name == nil || name == "" {
-            showError(title: "日历名称不能为空!")
-            return
-        }
-        MBProgressHUD_JChat.showMessage(message: "正在保存...", toView: self.view)
-        let calendar = OOCalendarInfo.init()
-        calendar.name = name
-        calendar.isPublic = isopen
-        if let account = O2AuthSDK.shared.myInfo() {
-           calendar.target = account.distinguishedName
-        }
-        calendar.color = colorValue
-        calendar.type = type
-        calendar.desc = remark ?? ""
-        
-        if calendarInfo != nil && calendarInfo?.id != nil { // 修改
-            calendar.id = calendarInfo?.id!
-        }
-        viewModel.saveCalendar(calendar: calendar)
-            .then { (result) in
-                DDLogInfo("保存日历成功!!!\(result)")
-                self.closeWindow()
-            }.always{
-                MBProgressHUD_JChat.hide(forView: self.view, animated: false)
-            }.catch { (error) in
-                DDLogError(error.localizedDescription)
-                self.showError(title: "保存日历错误!")
-        }
+      let name = calendarNameField.text
+      let isopen = calendarIsOpenSwitch.isOn
+      
+      var type = "PERSON"
+      if let typeValue = calendarTypeField.text{
+          if typeValue == "个人日历" {
+               type = "PERSON"
+          }else{
+               type = "UNIT"
+          }
+      }
+      let remark = calendarRemarkField.text
+      if name == nil || name == "" {
+          showError(title: "日历名称不能为空!")
+          return
+      }
+      
+      MBProgressHUD_JChat.showMessage(message: "正在保存...", toView: self.view)
+      /*
+      var calendar = self.calendarInfo
+      if calendarInfo != nil && calendarInfo?.id != nil { // 修改
+          //calendar.id = calendarInfo?.id!
+          calendar = calendarInfo ?? OOCalendarInfo.init()
+      }*/
+      
+      self.calendarInfo!.name = name
+      self.calendarInfo!.isPublic = isopen
+      
+      if type == "PERSON" {
+          if let account = O2AuthSDK.shared.myInfo() {
+              self.calendarInfo!.target = account.distinguishedName
+          }
+      }
+      self.calendarInfo!.color = colorValue
+      self.calendarInfo!.type = type
+      self.calendarInfo!.desc = remark ?? ""
+      
+     // calendar.status=="OPEN",
+      if calendarStatusSwitch.isOn {
+          self.calendarInfo!.status = "OPEN"
+      }else{
+          self.calendarInfo!.status = "CLOSE"
+      }
+    
+     viewModel.saveCalendar(calendar: self.calendarInfo!)
+          .then { (result) in
+              DDLogInfo("保存日历成功!!!\(result)")
+              self.closeWindow()
+          }.always{
+              MBProgressHUD_JChat.hide(forView: self.view, animated: false)
+          }.catch { (error) in
+              DDLogError(error.localizedDescription)
+              self.showError(title: "保存日历错误!")
+      }
+
     }
     private func deleteCalendar() {
         MBProgressHUD_JChat.showMessage(message: "正在删除...", toView: self.view)
@@ -137,7 +233,205 @@ class OOCalendarViewController: UITableViewController {
             }
         }
     }
+    //选择所属组织
+    @IBAction func selectOrg(_ sender: Any) {
+        let  arrModes = [ContactPickerType.unit]
+        showContactPicker(modes: arrModes, callback: {
+            (O2BizContactPickerResult) in
+            if let depts = O2BizContactPickerResult.departments {
+                var allDept = ""
+                var target = ""
+                for dept in depts{
+                    if allDept == "" {
+                        allDept = dept.name ?? ""
+                    }else{
+                        allDept = allDept + "," + ( dept.name ??  "" )
+                    }
+                    target = dept.distinguishedName ?? ""
+                }
+                
+                self.calendarOrgField.text = allDept
+                self.calendarInfo?.target = target
+            }
+        })
+    }
+    //选择管理者
+    @IBAction func selectManager(_ sender: Any) {
+        let  arrModes = [ContactPickerType.person]
+             showContactPicker(modes: arrModes, callback: {
+                 (O2BizContactPickerResult) in
+                if let users = O2BizContactPickerResult.users {
+                     var allUser = ""
+                     var manageablePersonList = [String]()
+                     for user in users{
+                         if allUser == "" {
+                             allUser = user.name ?? ""
+                         }else{
+                             allUser = allUser + "," + ( user.name ??  "" )
+                             
+                         }
+                        if let distinguishedName = user.distinguishedName{
+                               manageablePersonList.append(distinguishedName)
+                           }
+                     }
+                    self.calendarManagerField.text = allUser
+                    self.calendarInfo?.manageablePersonList = manageablePersonList
+                 }
+             })
+      }
+    
+
+    //选择可见范围
+    @IBAction func selectScope(_ sender: Any) {
+        var allUser = ""
+        var allDept = ""
+        var allGroup = ""
+        var all = ""
+        var viewablePersonList = [String]()
+        var viewableUnitList = [String]()
+        var viewableGroupList = [String]()
+        let  arrModes = [ContactPickerType.person,ContactPickerType.unit,ContactPickerType.group]
+        showContactPicker(modes: arrModes, callback: {
+            (O2BizContactPickerResult) in
+           if let users = O2BizContactPickerResult.users {
+                for user in users{
+                    if allUser == "" {
+                        allUser = user.name ?? ""
+                    }else{
+                        allUser = allUser + "," + ( user.name ??  "" )
+                    }
+                   if let distinguishedName = user.distinguishedName{
+                        viewablePersonList.append(distinguishedName)
+                    }
+                }
+              all = allUser
+            }
+            
+            if let depts = O2BizContactPickerResult.departments {
+                for dept in depts{
+                    if allDept == "" {
+                        allDept = dept.name ?? ""
+                    }else{
+                        allDept = allDept + "," + ( dept.name ??  "" )
+                    }
+                    
+                  if let distinguishedName = dept.distinguishedName{
+                        viewableUnitList.append(distinguishedName)
+                  }
+                    
+                }
+                if "" == all {
+                    all =  allDept
+                 }else{
+                    if "" != allDept {
+                      all = all + "," + allDept
+                    }
+                }
+            }
+            
+            if let groups = O2BizContactPickerResult.groups {
+                 for group in groups{
+                     if allGroup == "" {
+                         allGroup = group.name ?? ""
+                     }else{
+                         allGroup = allGroup + "," + (group.name ??  "" )
+                     }
+                    
+                    if let distinguishedName = group.distinguishedName{
+                          viewableGroupList.append(distinguishedName)
+                     }
+                 }
+                  if "" == all {
+                       all =  allGroup
+                    }else{
+                      if "" != allGroup {
+                         all = all + "," + allGroup
+                       }
+                    }
+                }
+            
+            self.calendarScopeField.text = all
+            self.calendarInfo?.viewablePersonList = viewablePersonList
+            self.calendarInfo?.viewableUnitList = viewableUnitList
+            self.calendarInfo?.viewableGroupList = viewableGroupList
+        })
+    }
     
+    //可新建范围
+    @IBAction func selectNewScope(_ sender: Any) {
+             var allUser = ""
+             var allDept = ""
+             var allGroup = ""
+             var all = ""
+             var publishablePersonList = [String]()
+             var publishableGroupList = [String]()
+             var publishableUnitList = [String]()
+             let  arrModes = [ContactPickerType.person,ContactPickerType.unit,ContactPickerType.group]
+             showContactPicker(modes: arrModes, callback: {
+                 (O2BizContactPickerResult) in
+                if let users = O2BizContactPickerResult.users {
+                     for user in users{
+                         if allUser == "" {
+                             allUser = user.name ?? ""
+                         }else{
+                             allUser = allUser + "," + ( user.name ??  "" )
+                        }
+                        
+                        if let distinguishedName = user.distinguishedName{
+                              publishablePersonList.append(distinguishedName)
+                        }
+                     }
+                   all = allUser
+                 }
+                 
+                 if let depts = O2BizContactPickerResult.departments {
+                     for dept in depts{
+                         if allDept == "" {
+                             allDept = dept.name ?? ""
+                         }else{
+                             allDept = allDept + "," + ( dept.name ??  "" )
+                         }
+                        
+                        if let distinguishedName = dept.distinguishedName{
+                              publishableUnitList.append(distinguishedName)
+                        }
+                     }
+                     if "" == all {
+                         all =  allDept
+                      }else{
+                        if "" != allDept {
+                          all = all + "," + allDept
+                        }
+                     }
+                 }
+                 
+                 if let groups = O2BizContactPickerResult.groups {
+                      for group in groups{
+                          if allGroup == "" {
+                              allGroup = group.name ?? ""
+                          }else{
+                              allGroup = allGroup + "," + (group.name ??  "" )
+                          }
+                        
+                        if let distinguishedName = group.distinguishedName{
+                              publishableGroupList.append(distinguishedName)
+                         }
+                      }
+                       if "" == all {
+                            all =  allGroup
+                         }else{
+                            if "" != allGroup{
+                               all = all + "," + allGroup
+                            }
+                         }
+                     }
+                self.calendarNewScopeField.text = all
+                self.calendarInfo?.publishablePersonList = publishablePersonList
+                self.calendarInfo?.publishableUnitList = publishableUnitList
+                self.calendarInfo?.publishableGroupList = publishableGroupList
+             })
+    }
+
     
     private func loadCalendarInfoFromNet() {
         viewModel.getCalendar(id: (calendarInfo?.id)!)
@@ -147,18 +441,60 @@ class OOCalendarViewController: UITableViewController {
                 DDLogError("查询日历信息出错,\(error.localizedDescription)")
         }
     }
+    
     private func updateStuffValue(calendar: OOCalendarInfo) {
-        calendarNameField.text = calendar.name
-        calendarIsOpenSwitch.setOn(calendar.isPublic == true, animated: true)
-        if let color = calendar.color {
-            if let index = colorOptions.index(where: { (colorItem) -> Bool in
-                return colorItem == color
-            }) {
-                self.selectColorView(tag: index)
-            }
-        }
-        calendarRemarkField.text = calendar.desc
-    }
+          calendarNameField.text = calendar.name
+    
+          if calendar.type == "UNIT" {
+              self.count = 4;
+          }else{
+              self.count = 0;
+          }
+          let section = NSIndexSet(index: 1)
+          self.tableView.beginUpdates()
+          self.tableView.reloadSections(section as IndexSet, with: .automatic)
+          self.tableView.endUpdates()
+          //所属组织
+          calendarOrgField.text = calendar.target?.getChinaName()
+          //管理员
+          calendarManagerField.text = calendar.manageablePersonList?.getChinaName().joined(separator: ",")
+          
+          //可见范围
+         var viewablePersonList = [String]()
+          viewablePersonList += calendar.viewablePersonList ?? []
+          viewablePersonList += calendar.viewableUnitList ?? []
+          viewablePersonList += calendar.viewableGroupList ?? []
+          calendarScopeField.text = viewablePersonList.getChinaName().joined(separator: ",")
+          
+          //可新建范围
+          var publishableList = [String]()
+          publishableList += calendar.publishablePersonList ?? []
+          publishableList += calendar.publishableGroupList ?? []
+          publishableList += calendar.publishableUnitList ?? []
+          calendarNewScopeField.text = publishableList.getChinaName().joined(separator: ",")
+          
+          if calendar.type == "PERSON" {
+               calendarTypeField.text = "个人日历"
+          }else{
+               calendarTypeField.text = "组织日历"
+          }
+         
+          calendarStatusSwitch.setOn(calendar.status=="OPEN", animated: true)
+          calendarIsOpenSwitch.setOn(calendar.isPublic == true, animated: true)
+          //隐藏类型选择按钮
+          calendarIsOpenBtn.isHidden = true
+          
+          if let color = calendar.color {
+              if let index = colorOptions.index(where: { (colorItem) -> Bool in
+                  return colorItem == color
+              }) {
+                  self.selectColorView(tag: index)
+              }
+          }
+          
+          calendarRemarkField.text = calendar.desc
+      }
+
     
 
     
@@ -188,7 +524,22 @@ class OOCalendarViewController: UITableViewController {
 }
 
 extension OOCalendarViewController: UITextFieldDelegate {
+    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool{
+        if let Identifier = textField.accessibilityIdentifier{
+            if Identifier == "calendarType" {
+                return false
+            } else{
+                return true
+            }
+        }else{
+            return true
+        }
+    }
     func textFieldShouldReturn(_ textField: UITextField) -> Bool {
-        return textField.resignFirstResponder()
+        //return textField.resignFirstResponder()
+        let res = textField.resignFirstResponder()
+        return  false
+      
     }
+
 }

+ 12 - 0
o2ios/O2Platform/App/Calendar-日程管理/Model/OOCalendarModels.swift

@@ -23,6 +23,18 @@ class OOCalendarInfo: NSObject, DataModel {
     @objc var status: String?
     @objc var createor: String?
     
+    // @objc var publishable:Bool?
+    @objc var source:String?
+    @objc var manageablePersonList:[String]?
+    @objc var followers:[String]?
+    @objc var viewablePersonList:[String]?
+    @objc var viewableUnitList:[String]?
+    @objc var viewableGroupList:[String]?
+    @objc var publishablePersonList:[String]?
+    @objc var publishableUnitList:[String]?
+    @objc var publishableGroupList:[String]?
+
+    
     required override init(){}
     
     func mapping(mapper: HelpingMapper) {

+ 1428 - 1209
o2ios/O2Platform/App/Calendar-日程管理/calendar.storyboard

@@ -1,1219 +1,1438 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="tKt-3P-uQz">
-    <device id="retina4_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
-        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
-        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <scenes>
-        <!--Calendar Main Month View Controller-->
-        <scene sceneID="g48-mo-Kla">
-            <objects>
-                <viewController id="xYY-yG-JGa" customClass="OOCalendarMainMonthViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
-                    <view key="view" contentMode="scaleToFill" id="QKO-bs-p7W">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <subviews>
-                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="KJj-zi-dZB">
-                                <rect key="frame" x="0.0" y="64" width="375" height="563"/>
-                                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                <prototypes>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="CalendarEventCell" id="n53-PB-sk0" customClass="CalendarEventTableViewCell" customModule="O2Platform" customModuleProvider="target">
-                                        <rect key="frame" x="0.0" y="28" width="375" height="44"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" restorationIdentifier="monthCalendarContent" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="n53-PB-sk0" id="lyc-3f-O6N">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JXL-RY-KpG">
-                                                    <rect key="frame" x="18" y="13" width="18" height="18"/>
-                                                    <color key="backgroundColor" red="0.29803921570000003" green="0.68627450980000004" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="width" constant="18" id="9R9-Im-fh5"/>
-                                                        <constraint firstAttribute="height" constant="18" id="bNg-p4-EmP"/>
-                                                    </constraints>
-                                                </view>
-                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="这里是内容" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YuP-80-oar">
-                                                    <rect key="frame" x="44" y="11.5" width="263" height="20.5"/>
-                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                                    <nil key="textColor"/>
-                                                    <nil key="highlightedColor"/>
-                                                </label>
-                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" alignment="center" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="2ui-5h-ZC7">
-                                                    <rect key="frame" x="315" y="5" width="42" height="34"/>
-                                                    <subviews>
-                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="18:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="les-0j-Mxf" userLabel="Event StartTime">
-                                                            <rect key="frame" x="5" y="0.0" width="32" height="14.5"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            <nil key="highlightedColor"/>
-                                                        </label>
-                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="19:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jIB-o0-arB" userLabel="Event EndTime">
-                                                            <rect key="frame" x="5" y="19.5" width="32" height="14.5"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            <nil key="highlightedColor"/>
-                                                        </label>
-                                                    </subviews>
-                                                    <constraints>
-                                                        <constraint firstAttribute="width" constant="42" id="r9t-sb-ycD"/>
-                                                    </constraints>
-                                                </stackView>
-                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="全天" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KIV-kE-cmY" userLabel="Event AllDay">
-                                                    <rect key="frame" x="326" y="13" width="31" height="18"/>
-                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
-                                                    <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                    <nil key="highlightedColor"/>
-                                                </label>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstItem="2ui-5h-ZC7" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="1JL-Dp-A6W"/>
-                                                <constraint firstItem="JXL-RY-KpG" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="Ibd-e8-GXJ"/>
-                                                <constraint firstItem="YuP-80-oar" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="QdU-mY-k9o"/>
-                                                <constraint firstItem="2ui-5h-ZC7" firstAttribute="leading" secondItem="YuP-80-oar" secondAttribute="trailing" constant="8" id="V6b-cg-chx"/>
-                                                <constraint firstItem="JXL-RY-KpG" firstAttribute="leading" secondItem="lyc-3f-O6N" secondAttribute="leading" constant="18" id="dSx-3I-cxQ"/>
-                                                <constraint firstAttribute="trailing" secondItem="2ui-5h-ZC7" secondAttribute="trailing" constant="18" id="fwY-HU-g8c"/>
-                                                <constraint firstItem="YuP-80-oar" firstAttribute="leading" secondItem="JXL-RY-KpG" secondAttribute="trailing" constant="8" id="kgr-jn-t9O"/>
-                                                <constraint firstAttribute="trailing" secondItem="KIV-kE-cmY" secondAttribute="trailing" constant="18" id="mam-ns-u2j"/>
-                                                <constraint firstItem="KIV-kE-cmY" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="rH1-jv-JMV"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                        <connections>
-                                            <outlet property="eventAllDay" destination="KIV-kE-cmY" id="34j-Xs-8z2"/>
-                                            <outlet property="eventColorView" destination="JXL-RY-KpG" id="FzI-2i-OMO"/>
-                                            <outlet property="eventEndTime" destination="jIB-o0-arB" id="TDp-Ag-gq3"/>
-                                            <outlet property="eventStartTime" destination="les-0j-Mxf" id="eJA-Fg-C5K"/>
-                                            <outlet property="eventTimeStack" destination="2ui-5h-ZC7" id="RcE-jB-uZq"/>
-                                            <outlet property="eventTitleView" destination="YuP-80-oar" id="GaE-LI-V7N"/>
-                                            <segue destination="Vxk-45-vB1" kind="show" identifier="showEventDetail" id="VOH-7P-zaY"/>
-                                        </connections>
-                                    </tableViewCell>
-                                </prototypes>
-                            </tableView>
-                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="M0F-7m-vuY" userLabel="BottomBar">
-                                <rect key="frame" x="0.0" y="627" width="375" height="40"/>
-                                <subviews>
-                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wt1-wW-6mZ">
-                                        <rect key="frame" x="16" y="3.5" width="35" height="33"/>
-                                        <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
-                                        <state key="normal" title="今天"/>
-                                        <connections>
-                                            <action selector="todayAction:" destination="xYY-yG-JGa" eventType="touchUpInside" id="Wd8-Ne-Gwr"/>
-                                        </connections>
-                                    </button>
-                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="71T-qf-T8Z">
-                                        <rect key="frame" x="324" y="4" width="35" height="33"/>
-                                        <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
-                                        <state key="normal" title="日历"/>
-                                        <connections>
-                                            <segue destination="L5W-fh-UuH" kind="show" id="DF4-xt-Rlu"/>
-                                        </connections>
-                                    </button>
-                                </subviews>
-                                <color key="backgroundColor" red="0.97647058823529409" green="0.97647058823529409" blue="0.97647058823529409" alpha="1" colorSpace="calibratedRGB"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="40" id="EPO-5J-aQ8"/>
-                                    <constraint firstItem="wt1-wW-6mZ" firstAttribute="leading" secondItem="M0F-7m-vuY" secondAttribute="leading" constant="16" id="aoT-z2-Iuk"/>
-                                    <constraint firstAttribute="trailing" secondItem="71T-qf-T8Z" secondAttribute="trailing" constant="16" id="bQo-4L-Bhv"/>
-                                    <constraint firstItem="wt1-wW-6mZ" firstAttribute="centerY" secondItem="M0F-7m-vuY" secondAttribute="centerY" id="opA-fa-ziv"/>
-                                    <constraint firstItem="71T-qf-T8Z" firstAttribute="centerY" secondItem="M0F-7m-vuY" secondAttribute="centerY" id="ufw-UJ-60Y"/>
-                                </constraints>
-                            </view>
-                        </subviews>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <constraints>
-                            <constraint firstItem="M0F-7m-vuY" firstAttribute="bottom" secondItem="YOP-fD-eOB" secondAttribute="bottom" id="1g7-OC-yaV"/>
-                            <constraint firstItem="KJj-zi-dZB" firstAttribute="leading" secondItem="YOP-fD-eOB" secondAttribute="leading" id="8Bi-5G-lvJ"/>
-                            <constraint firstItem="M0F-7m-vuY" firstAttribute="top" secondItem="KJj-zi-dZB" secondAttribute="bottom" id="AIF-zg-ryj"/>
-                            <constraint firstItem="KJj-zi-dZB" firstAttribute="trailing" secondItem="YOP-fD-eOB" secondAttribute="trailing" id="MLm-Tk-l38"/>
-                            <constraint firstItem="M0F-7m-vuY" firstAttribute="trailing" secondItem="YOP-fD-eOB" secondAttribute="trailing" id="dJ4-wm-Y8z"/>
-                            <constraint firstItem="M0F-7m-vuY" firstAttribute="leading" secondItem="YOP-fD-eOB" secondAttribute="leading" id="kLc-Qp-gzN"/>
-                            <constraint firstItem="KJj-zi-dZB" firstAttribute="top" secondItem="YOP-fD-eOB" secondAttribute="top" id="plZ-2M-2pz"/>
-                        </constraints>
-                        <viewLayoutGuide key="safeArea" id="YOP-fD-eOB"/>
-                    </view>
-                    <navigationItem key="navigationItem" id="4qR-Bd-8HM"/>
-                    <connections>
-                        <outlet property="calendarBtn" destination="71T-qf-T8Z" id="kmy-qp-47B"/>
-                        <outlet property="tableView" destination="KJj-zi-dZB" id="BLE-0u-ldM"/>
-                        <outlet property="todayBtn" destination="wt1-wW-6mZ" id="oTj-Yv-omZ"/>
-                    </connections>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="NFS-3Q-UWF" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="848.79999999999995" y="-694.00299850074964"/>
-        </scene>
-        <!--Calendar Event View Controller-->
-        <scene sceneID="Aj2-RD-S3x">
-            <objects>
-                <tableViewController id="Vxk-45-vB1" customClass="OOCalendarEventViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
-                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="7H1-7C-M3e">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <sections>
-                            <tableViewSection id="Ogn-vO-7jG">
-                                <cells>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="45" id="uxG-oP-2Jx">
-                                        <rect key="frame" x="0.0" y="0.0" width="375" height="45"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="uxG-oP-2Jx" id="MKv-co-tJv">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="例如:开会" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="gaP-Lw-V7E">
-                                                    <rect key="frame" x="16" y="5" width="354" height="34.5"/>
-                                                    <nil key="textColor"/>
-                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                                                    <textInputTraits key="textInputTraits"/>
-                                                </textField>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstItem="gaP-Lw-V7E" firstAttribute="top" secondItem="MKv-co-tJv" secondAttribute="top" constant="5" id="Umh-GC-vHb"/>
-                                                <constraint firstAttribute="bottom" secondItem="gaP-Lw-V7E" secondAttribute="bottom" constant="5" id="aYp-Fg-OyP"/>
-                                                <constraint firstItem="gaP-Lw-V7E" firstAttribute="leading" secondItem="MKv-co-tJv" secondAttribute="leading" constant="16" id="szc-Rj-gp8"/>
-                                                <constraint firstAttribute="trailing" secondItem="gaP-Lw-V7E" secondAttribute="trailing" constant="5" id="uFD-7h-XoM"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="120" id="Nqb-uU-RgB">
-                                        <rect key="frame" x="0.0" y="45" width="375" height="120"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Nqb-uU-RgB" id="PQX-mp-zBS">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="119.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <stackView opaque="NO" contentMode="scaleToFill" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="lpS-Ep-u9o">
-                                                    <rect key="frame" x="16" y="5" width="100" height="24"/>
-                                                    <subviews>
-                                                        <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="PwN-cV-5Cp">
-                                                            <rect key="frame" x="0.0" y="0.0" width="50" height="24"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="width" constant="48" id="Cy3-uM-ruq"/>
-                                                                <constraint firstAttribute="height" constant="24" id="VCr-I8-jVq"/>
-                                                            </constraints>
-                                                            <connections>
-                                                                <action selector="tapAllDaySwitch:" destination="Vxk-45-vB1" eventType="valueChanged" id="rrC-lO-H2n"/>
-                                                            </connections>
-                                                        </switch>
-                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="全天" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rdY-4r-1NV">
-                                                            <rect key="frame" x="63" y="0.0" width="37" height="24"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
-                                                            <nil key="textColor"/>
-                                                            <nil key="highlightedColor"/>
-                                                        </label>
-                                                    </subviews>
-                                                    <constraints>
-                                                        <constraint firstAttribute="width" constant="100" id="s4W-o2-CN4"/>
-                                                    </constraints>
-                                                </stackView>
-                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_shijian" translatesAutoresizingMaskIntoConstraints="NO" id="sfg-C9-T2u">
-                                                    <rect key="frame" x="16" y="45" width="22" height="22"/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="width" constant="22" id="6WJ-71-uTo"/>
-                                                        <constraint firstAttribute="height" constant="22" id="9gU-gy-aua"/>
-                                                    </constraints>
-                                                </imageView>
-                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="NNc-Zq-e8a">
-                                                    <rect key="frame" x="74" y="46" width="285" height="64"/>
-                                                    <subviews>
-                                                        <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HqM-sQ-xhn">
-                                                            <rect key="frame" x="0.0" y="0.0" width="285" height="22"/>
-                                                            <subviews>
-                                                                <label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2018年07月30日 13:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dub-8d-dx7">
-                                                                    <rect key="frame" x="0.0" y="0.0" width="261" height="22"/>
-                                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
-                                                                    <nil key="textColor"/>
-                                                                    <nil key="highlightedColor"/>
-                                                                </label>
-                                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_arrow" translatesAutoresizingMaskIntoConstraints="NO" id="23o-Vb-7fY">
-                                                                    <rect key="frame" x="261" y="0.0" width="24" height="22"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="width" constant="24" id="HAj-Bt-7rV"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                        </stackView>
-                                                        <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lNF-vK-WbX">
-                                                            <rect key="frame" x="0.0" y="42" width="285" height="22"/>
-                                                            <subviews>
-                                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2018年07月30日 13:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rqe-Vw-UzF">
-                                                                    <rect key="frame" x="0.0" y="0.0" width="261" height="22"/>
-                                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
-                                                                    <nil key="textColor"/>
-                                                                    <nil key="highlightedColor"/>
-                                                                </label>
-                                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_arrow" translatesAutoresizingMaskIntoConstraints="NO" id="y7l-as-AD6">
-                                                                    <rect key="frame" x="261" y="0.0" width="24" height="22"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="width" constant="24" id="sMs-sB-hyI"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                        </stackView>
-                                                    </subviews>
-                                                    <gestureRecognizers/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="height" constant="64" id="S4m-1J-ydh"/>
-                                                    </constraints>
-                                                </stackView>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstItem="NNc-Zq-e8a" firstAttribute="leading" secondItem="sfg-C9-T2u" secondAttribute="trailing" constant="36" id="am8-ML-krx"/>
-                                                <constraint firstItem="lpS-Ep-u9o" firstAttribute="top" secondItem="PQX-mp-zBS" secondAttribute="top" constant="5" id="c3D-PO-yJC"/>
-                                                <constraint firstItem="sfg-C9-T2u" firstAttribute="leading" secondItem="PQX-mp-zBS" secondAttribute="leadingMargin" id="dds-UT-Ghg"/>
-                                                <constraint firstItem="sfg-C9-T2u" firstAttribute="top" secondItem="lpS-Ep-u9o" secondAttribute="bottom" constant="16" id="kcR-EW-imZ"/>
-                                                <constraint firstAttribute="trailingMargin" secondItem="NNc-Zq-e8a" secondAttribute="trailing" id="pmh-Pn-TSi"/>
-                                                <constraint firstItem="lpS-Ep-u9o" firstAttribute="leading" secondItem="PQX-mp-zBS" secondAttribute="leading" constant="16" id="s0k-x8-Y6F"/>
-                                                <constraint firstItem="NNc-Zq-e8a" firstAttribute="top" secondItem="lpS-Ep-u9o" secondAttribute="bottom" constant="17" id="vUd-A0-kwF"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="60" id="4Gg-JY-9Yo">
-                                        <rect key="frame" x="0.0" y="165" width="375" height="60"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="4Gg-JY-9Yo" id="7Su-0t-5EZ">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="evq-G0-rF6">
-                                                    <rect key="frame" x="16" y="0.0" width="359" height="59.5"/>
-                                                    <subviews>
-                                                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_hdjr" translatesAutoresizingMaskIntoConstraints="NO" id="kBX-9l-V1q">
-                                                            <rect key="frame" x="0.0" y="19" width="22" height="22"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="width" constant="22" id="1FT-SO-P9R"/>
-                                                                <constraint firstAttribute="height" constant="22" id="rqM-2X-wbT"/>
-                                                            </constraints>
-                                                        </imageView>
-                                                        <pickerView tag="110" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pyF-R2-ql8">
-                                                            <rect key="frame" x="37" y="0.0" width="322" height="59.5"/>
-                                                            <connections>
-                                                                <outlet property="dataSource" destination="Vxk-45-vB1" id="5Dd-B7-Q9q"/>
-                                                                <outlet property="delegate" destination="Vxk-45-vB1" id="8qX-9R-aTO"/>
-                                                            </connections>
-                                                        </pickerView>
-                                                    </subviews>
-                                                </stackView>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstItem="evq-G0-rF6" firstAttribute="top" secondItem="7Su-0t-5EZ" secondAttribute="top" id="1VO-mL-jHa"/>
-                                                <constraint firstItem="evq-G0-rF6" firstAttribute="leading" secondItem="7Su-0t-5EZ" secondAttribute="leading" constant="16" id="h8s-cf-9Sd"/>
-                                                <constraint firstAttribute="trailing" secondItem="evq-G0-rF6" secondAttribute="trailing" id="oUj-3c-7gc"/>
-                                                <constraint firstAttribute="bottom" secondItem="evq-G0-rF6" secondAttribute="bottom" id="uSr-V1-QZu"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="45" id="qQX-Lv-NHQ">
-                                        <rect key="frame" x="0.0" y="225" width="375" height="45"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qQX-Lv-NHQ" id="Tln-Ch-B5c">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="i8o-dB-E0v">
-                                                    <rect key="frame" x="20" y="8" width="339" height="28.5"/>
-                                                    <subviews>
-                                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Dgr-Bu-MAQ" userLabel="blue">
-                                                            <rect key="frame" x="0.0" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="gmX-mE-SDk">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="6VV-qr-hlC"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="Uxh-wh-1YZ"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.25882352941176467" green="0.5607843137254902" blue="0.9882352941176471" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="gmX-mE-SDk" firstAttribute="centerX" secondItem="Dgr-Bu-MAQ" secondAttribute="centerX" id="9aJ-c0-KjP"/>
-                                                                <constraint firstAttribute="width" constant="24" id="Ivw-Nt-e8L"/>
-                                                                <constraint firstItem="gmX-mE-SDk" firstAttribute="centerY" secondItem="Dgr-Bu-MAQ" secondAttribute="centerY" id="Y6X-EZ-SM0"/>
-                                                                <constraint firstAttribute="height" constant="24" id="aY4-rA-in7"/>
-                                                            </constraints>
-                                                        </view>
-                                                        <view tag="1" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nS3-qA-VwA" userLabel="green">
-                                                            <rect key="frame" x="45" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="D3N-kh-Mq7">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="WOI-Ze-YEg"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="ZQ2-1O-AN1"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.35686274509803922" green="0.80000000000000004" blue="0.38039215686274508" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="D3N-kh-Mq7" firstAttribute="centerY" secondItem="nS3-qA-VwA" secondAttribute="centerY" id="8BK-XT-xJE"/>
-                                                                <constraint firstAttribute="width" constant="24" id="SRZ-Rw-NfW"/>
-                                                                <constraint firstAttribute="height" constant="24" id="kPY-21-Y5A"/>
-                                                                <constraint firstItem="D3N-kh-Mq7" firstAttribute="centerX" secondItem="nS3-qA-VwA" secondAttribute="centerX" id="ltQ-jl-c7u"/>
-                                                            </constraints>
-                                                        </view>
-                                                        <view tag="2" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hRM-n9-khc" userLabel="orangle">
-                                                            <rect key="frame" x="90" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="KzE-S1-77g">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="AUe-S7-hB3"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="aFI-ew-wtP"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.97647058823529409" green="0.74901960784313726" blue="0.14117647058823529" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="KzE-S1-77g" firstAttribute="centerY" secondItem="hRM-n9-khc" secondAttribute="centerY" id="HEF-qz-tnK"/>
-                                                                <constraint firstAttribute="height" constant="24" id="HQu-84-yYi"/>
-                                                                <constraint firstItem="KzE-S1-77g" firstAttribute="centerX" secondItem="hRM-n9-khc" secondAttribute="centerX" id="ceb-An-1Tu"/>
-                                                                <constraint firstAttribute="width" constant="24" id="mck-HZ-ZCw"/>
-                                                            </constraints>
-                                                        </view>
-                                                        <view tag="3" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ggx-2y-fDS" userLabel="crimson">
-                                                            <rect key="frame" x="135" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="GK6-ih-mWE">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="ae3-zr-8aw"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="w5l-GX-PJI"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.96862745098039216" green="0.37254901960784315" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="width" constant="24" id="UMl-J7-DNy"/>
-                                                                <constraint firstItem="GK6-ih-mWE" firstAttribute="centerX" secondItem="Ggx-2y-fDS" secondAttribute="centerX" id="bXf-5U-QEv"/>
-                                                                <constraint firstAttribute="height" constant="24" id="hfe-b7-39J"/>
-                                                                <constraint firstItem="GK6-ih-mWE" firstAttribute="centerY" secondItem="Ggx-2y-fDS" secondAttribute="centerY" id="w1I-Sz-h3c"/>
-                                                            </constraints>
-                                                        </view>
-                                                        <view tag="4" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OGU-7P-pbj" userLabel="lightpurple">
-                                                            <rect key="frame" x="180" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="yE3-0X-Ixh">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="width" constant="18" id="ARI-92-xj5"/>
-                                                                        <constraint firstAttribute="height" constant="18" id="Rnx-ld-gJh"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.94509803921568625" green="0.50196078431372548" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="yE3-0X-Ixh" firstAttribute="centerY" secondItem="OGU-7P-pbj" secondAttribute="centerY" id="782-Qj-Dlk"/>
-                                                                <constraint firstAttribute="width" constant="24" id="Fv9-El-C1c"/>
-                                                                <constraint firstAttribute="height" constant="24" id="HVA-E8-C61"/>
-                                                                <constraint firstItem="yE3-0X-Ixh" firstAttribute="centerX" secondItem="OGU-7P-pbj" secondAttribute="centerX" id="dqb-xX-kM8"/>
-                                                            </constraints>
-                                                        </view>
-                                                        <view tag="5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="H7n-vf-H9J" userLabel="purple">
-                                                            <rect key="frame" x="225" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="D0E-yX-QaI">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="TFo-D4-GPF"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="iAL-KH-v80"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.56470588235294117" green="0.44705882352941173" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="height" constant="24" id="8gq-CO-eTY"/>
-                                                                <constraint firstItem="D0E-yX-QaI" firstAttribute="centerY" secondItem="H7n-vf-H9J" secondAttribute="centerY" id="99s-cw-T7m"/>
-                                                                <constraint firstAttribute="width" constant="24" id="E8S-ZW-5fe"/>
-                                                                <constraint firstItem="D0E-yX-QaI" firstAttribute="centerX" secondItem="H7n-vf-H9J" secondAttribute="centerX" id="sRT-G7-gp6"/>
-                                                            </constraints>
-                                                        </view>
-                                                        <view tag="6" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="118-Aw-aif" userLabel="gray">
-                                                            <rect key="frame" x="270" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="8UA-Zc-sdH">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="J8p-K5-Xsp"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="KUz-t8-9b4"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.56470588235294117" green="0.56470588235294117" blue="0.56470588235294117" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="8UA-Zc-sdH" firstAttribute="centerY" secondItem="118-Aw-aif" secondAttribute="centerY" id="5PU-ld-WL6"/>
-                                                                <constraint firstAttribute="height" constant="24" id="EoQ-gB-JFa"/>
-                                                                <constraint firstAttribute="width" constant="24" id="gYN-JO-57r"/>
-                                                                <constraint firstItem="8UA-Zc-sdH" firstAttribute="centerX" secondItem="118-Aw-aif" secondAttribute="centerX" id="lfI-fD-zeO"/>
-                                                            </constraints>
-                                                        </view>
-                                                        <view tag="7" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aua-TK-Qnv" userLabel="cyanine">
-                                                            <rect key="frame" x="315" y="2.5" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="tye-Jf-YHm">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="5WS-2e-3QG"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="mHx-1M-qnT"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.078431372549019607" green="0.38431372549019605" blue="0.74509803921568629" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="width" constant="24" id="4nx-sl-RIa"/>
-                                                                <constraint firstAttribute="height" constant="24" id="Kpb-lJ-sTI"/>
-                                                                <constraint firstItem="tye-Jf-YHm" firstAttribute="centerY" secondItem="aua-TK-Qnv" secondAttribute="centerY" id="cKv-Ul-QD0"/>
-                                                                <constraint firstItem="tye-Jf-YHm" firstAttribute="centerX" secondItem="aua-TK-Qnv" secondAttribute="centerX" id="cYE-GL-WBJ"/>
-                                                            </constraints>
-                                                        </view>
-                                                    </subviews>
-                                                </stackView>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstAttribute="trailing" secondItem="i8o-dB-E0v" secondAttribute="trailing" constant="16" id="8Ox-ef-kQX"/>
-                                                <constraint firstAttribute="bottom" secondItem="i8o-dB-E0v" secondAttribute="bottom" constant="8" id="Zut-5K-hJS"/>
-                                                <constraint firstItem="i8o-dB-E0v" firstAttribute="leading" secondItem="Tln-Ch-B5c" secondAttribute="leading" constant="20" id="iT4-S9-mfI"/>
-                                                <constraint firstItem="i8o-dB-E0v" firstAttribute="top" secondItem="Tln-Ch-B5c" secondAttribute="top" constant="8" id="lBf-sr-HQW"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="60" id="u6G-MU-dPL">
-                                        <rect key="frame" x="0.0" y="270" width="375" height="60"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="u6G-MU-dPL" id="auw-zx-G07">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="Nvw-Uv-y4F">
-                                                    <rect key="frame" x="16" y="0.0" width="359" height="59.5"/>
-                                                    <subviews>
-                                                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_tixing" translatesAutoresizingMaskIntoConstraints="NO" id="JPO-Kb-7YE">
-                                                            <rect key="frame" x="0.0" y="19" width="22" height="22"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="width" constant="22" id="XHQ-Ne-kEe"/>
-                                                                <constraint firstAttribute="height" constant="22" id="i2w-Kk-1a1"/>
-                                                            </constraints>
-                                                        </imageView>
-                                                        <pickerView tag="111" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eRL-b7-sZv">
-                                                            <rect key="frame" x="37" y="0.0" width="322" height="59.5"/>
-                                                            <connections>
-                                                                <outlet property="dataSource" destination="Vxk-45-vB1" id="X6V-QF-7cw"/>
-                                                                <outlet property="delegate" destination="Vxk-45-vB1" id="cI2-NL-CGH"/>
-                                                            </connections>
-                                                        </pickerView>
-                                                    </subviews>
-                                                </stackView>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstItem="Nvw-Uv-y4F" firstAttribute="top" secondItem="auw-zx-G07" secondAttribute="top" id="BS2-oE-3V6"/>
-                                                <constraint firstAttribute="bottom" secondItem="Nvw-Uv-y4F" secondAttribute="bottom" id="S9Y-Ea-NPh"/>
-                                                <constraint firstAttribute="trailing" secondItem="Nvw-Uv-y4F" secondAttribute="trailing" id="mVM-zG-UZP"/>
-                                                <constraint firstItem="Nvw-Uv-y4F" firstAttribute="leading" secondItem="auw-zx-G07" secondAttribute="leading" constant="16" id="oXw-gx-pWs"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="60" id="e5P-Ds-0Jm">
-                                        <rect key="frame" x="0.0" y="330" width="375" height="60"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="e5P-Ds-0Jm" id="vBL-Zg-uX0">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="o2n-Cg-nQo">
-                                                    <rect key="frame" x="16" y="0.0" width="359" height="60"/>
-                                                    <subviews>
-                                                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_chongfu" translatesAutoresizingMaskIntoConstraints="NO" id="W5r-qL-MRy">
-                                                            <rect key="frame" x="0.0" y="19" width="22" height="22"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="height" constant="22" id="eN6-V0-CcT"/>
-                                                                <constraint firstAttribute="width" constant="22" id="mxs-yb-OVM"/>
-                                                            </constraints>
-                                                        </imageView>
-                                                        <pickerView tag="112" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fbt-RB-x4p">
-                                                            <rect key="frame" x="37" y="0.0" width="322" height="60"/>
-                                                            <connections>
-                                                                <outlet property="dataSource" destination="Vxk-45-vB1" id="cCT-Ga-6th"/>
-                                                                <outlet property="delegate" destination="Vxk-45-vB1" id="TRG-7c-mdR"/>
-                                                            </connections>
-                                                        </pickerView>
-                                                    </subviews>
-                                                    <constraints>
-                                                        <constraint firstAttribute="height" constant="60" id="gjT-w1-VIx"/>
-                                                    </constraints>
-                                                </stackView>
-                                                <stackView hidden="YES" opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="F44-6G-rM2">
-                                                    <rect key="frame" x="32" y="65" width="311" height="20"/>
-                                                    <subviews>
-                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="截至日期:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IMf-BA-twt">
-                                                            <rect key="frame" x="0.0" y="3" width="64" height="14.5"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="width" constant="64" id="oup-D2-hLu"/>
-                                                            </constraints>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <nil key="textColor"/>
-                                                            <nil key="highlightedColor"/>
-                                                        </label>
-                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="k6W-yh-OR2">
-                                                            <rect key="frame" x="79" y="0.0" width="232" height="20"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            <nil key="highlightedColor"/>
-                                                        </label>
-                                                    </subviews>
-                                                    <constraints>
-                                                        <constraint firstAttribute="height" constant="20" id="iwQ-Pk-1HS"/>
-                                                    </constraints>
-                                                </stackView>
-                                                <stackView hidden="YES" opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="vc3-qe-cTN">
-                                                    <rect key="frame" x="32" y="90" width="327" height="27"/>
-                                                    <subviews>
-                                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qy2-Ll-2FL">
-                                                            <rect key="frame" x="0.0" y="0.0" width="30" height="27"/>
-                                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <state key="normal" title="周一">
-                                                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                                <color key="titleShadowColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            </state>
-                                                        </button>
-                                                        <button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hQt-nQ-yDV">
-                                                            <rect key="frame" x="49.5" y="0.0" width="30" height="27"/>
-                                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <state key="normal" title="周二">
-                                                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            </state>
-                                                        </button>
-                                                        <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GeN-7S-V8E">
-                                                            <rect key="frame" x="99" y="0.0" width="30" height="27"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <state key="normal" title="周三">
-                                                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            </state>
-                                                        </button>
-                                                        <button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xOJ-cj-hMc">
-                                                            <rect key="frame" x="148.5" y="0.0" width="30" height="27"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <state key="normal" title="周四">
-                                                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            </state>
-                                                        </button>
-                                                        <button opaque="NO" tag="4" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Szk-bc-YOL">
-                                                            <rect key="frame" x="198" y="0.0" width="30" height="27"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <state key="normal" title="周五">
-                                                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            </state>
-                                                        </button>
-                                                        <button opaque="NO" tag="5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Qxa-Na-eLg">
-                                                            <rect key="frame" x="247.5" y="0.0" width="30" height="27"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <state key="normal" title="周六">
-                                                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            </state>
-                                                        </button>
-                                                        <button opaque="NO" tag="6" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="To9-IU-AE6">
-                                                            <rect key="frame" x="297" y="0.0" width="30" height="27"/>
-                                                            <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
-                                                            <state key="normal" title="周日">
-                                                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                            </state>
-                                                        </button>
-                                                    </subviews>
-                                                </stackView>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstAttribute="trailingMargin" secondItem="F44-6G-rM2" secondAttribute="trailing" constant="16" id="2ZB-Co-2pB"/>
-                                                <constraint firstItem="F44-6G-rM2" firstAttribute="top" secondItem="o2n-Cg-nQo" secondAttribute="bottom" constant="5" id="8pt-BZ-t3e"/>
-                                                <constraint firstAttribute="trailingMargin" secondItem="vc3-qe-cTN" secondAttribute="trailing" id="F4z-Sg-29S"/>
-                                                <constraint firstItem="vc3-qe-cTN" firstAttribute="top" secondItem="F44-6G-rM2" secondAttribute="bottom" constant="5" id="SS2-2g-5NJ"/>
-                                                <constraint firstItem="vc3-qe-cTN" firstAttribute="leading" secondItem="vBL-Zg-uX0" secondAttribute="leadingMargin" constant="16" id="XMb-c7-8LK"/>
-                                                <constraint firstItem="o2n-Cg-nQo" firstAttribute="leading" secondItem="vBL-Zg-uX0" secondAttribute="leading" constant="16" id="eqQ-It-Ump"/>
-                                                <constraint firstAttribute="trailing" secondItem="o2n-Cg-nQo" secondAttribute="trailing" id="oxH-8z-faW"/>
-                                                <constraint firstItem="F44-6G-rM2" firstAttribute="leading" secondItem="vBL-Zg-uX0" secondAttribute="leadingMargin" constant="16" id="qc8-ft-bgf"/>
-                                                <constraint firstItem="o2n-Cg-nQo" firstAttribute="top" secondItem="vBL-Zg-uX0" secondAttribute="top" id="xMp-X8-TEi"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="93" id="mRu-Km-9dY">
-                                        <rect key="frame" x="0.0" y="390" width="375" height="93"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="mRu-Km-9dY" id="HFU-yb-U6N">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="92.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" placeholder="添加说明" minimumFontSize="12" translatesAutoresizingMaskIntoConstraints="NO" id="reH-A1-vQT">
-                                                    <rect key="frame" x="16" y="8" width="343" height="80"/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="height" constant="80" id="FA7-HO-1NJ"/>
-                                                    </constraints>
-                                                    <nil key="textColor"/>
-                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
-                                                    <textInputTraits key="textInputTraits"/>
-                                                </textField>
-                                                <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OMA-Fp-nFl">
-                                                    <rect key="frame" x="16" y="47.5" width="343" height="40"/>
-                                                    <color key="backgroundColor" red="0.98431372549019602" green="0.27843137254901962" blue="0.27843137254901962" alpha="1" colorSpace="calibratedRGB"/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="height" constant="40" id="z38-hq-zd6"/>
-                                                    </constraints>
-                                                    <state key="normal" title="删   除">
-                                                        <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                    </state>
-                                                    <userDefinedRuntimeAttributes>
-                                                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                            <real key="value" value="5"/>
-                                                        </userDefinedRuntimeAttribute>
-                                                    </userDefinedRuntimeAttributes>
-                                                    <connections>
-                                                        <action selector="tapDeleteBtn:" destination="Vxk-45-vB1" eventType="touchUpInside" id="d3V-gw-XoF"/>
-                                                    </connections>
-                                                </button>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstAttribute="bottom" secondItem="OMA-Fp-nFl" secondAttribute="bottom" constant="5" id="7tr-rB-tZn"/>
-                                                <constraint firstAttribute="trailing" secondItem="OMA-Fp-nFl" secondAttribute="trailing" constant="16" id="C1B-kF-d5q"/>
-                                                <constraint firstAttribute="trailing" secondItem="reH-A1-vQT" secondAttribute="trailing" constant="16" id="UEQ-Sj-WGw"/>
-                                                <constraint firstItem="OMA-Fp-nFl" firstAttribute="leading" secondItem="HFU-yb-U6N" secondAttribute="leading" constant="16" id="aya-2K-2Jr"/>
-                                                <constraint firstItem="reH-A1-vQT" firstAttribute="top" secondItem="HFU-yb-U6N" secondAttribute="top" constant="8" id="fM7-pG-HCc"/>
-                                                <constraint firstItem="reH-A1-vQT" firstAttribute="leading" secondItem="HFU-yb-U6N" secondAttribute="leading" constant="16" id="jeR-07-P4W"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                </cells>
-                            </tableViewSection>
-                        </sections>
-                        <connections>
-                            <outlet property="dataSource" destination="Vxk-45-vB1" id="XpN-cu-Ay8"/>
-                            <outlet property="delegate" destination="Vxk-45-vB1" id="18X-HM-sWl"/>
-                        </connections>
-                    </tableView>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="tKt-3P-uQz">
+  <device id="retina4_7" orientation="portrait" appearance="light"/>
+  <dependencies>
+    <deployment identifier="iOS"/>
+    <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16086"/>
+    <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+    <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+  </dependencies>
+  <scenes>
+    <!--Calendar Main Month View Controller-->
+    <scene sceneID="g48-mo-Kla">
+      <objects>
+        <viewController id="xYY-yG-JGa" customClass="OOCalendarMainMonthViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+          <view key="view" contentMode="scaleToFill" id="QKO-bs-p7W">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+              <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="KJj-zi-dZB">
+                <rect key="frame" x="0.0" y="44" width="375" height="583"/>
+                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                <prototypes>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="CalendarEventCell" id="n53-PB-sk0" customClass="CalendarEventTableViewCell" customModule="O2Platform" customModuleProvider="target">
+                    <rect key="frame" x="0.0" y="28" width="375" height="43.5"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" restorationIdentifier="monthCalendarContent" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="n53-PB-sk0" id="lyc-3f-O6N">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JXL-RY-KpG">
+                          <rect key="frame" x="18" y="13" width="18" height="18"/>
+                          <color key="backgroundColor" red="0.29803921570000003" green="0.68627450980000004" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
+                          <constraints>
+                            <constraint firstAttribute="width" constant="18" id="9R9-Im-fh5"/>
+                            <constraint firstAttribute="height" constant="18" id="bNg-p4-EmP"/>
+                          </constraints>
+                        </view>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="这里是内容" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YuP-80-oar">
+                          <rect key="frame" x="44" y="11.5" width="263" height="20.5"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                          <nil key="textColor"/>
+                          <nil key="highlightedColor"/>
+                        </label>
+                        <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" alignment="center" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="2ui-5h-ZC7">
+                          <rect key="frame" x="315" y="5" width="42" height="34"/>
+                          <subviews>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="18:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="les-0j-Mxf" userLabel="Event StartTime">
+                              <rect key="frame" x="5" y="0.0" width="32" height="14.5"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="19:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jIB-o0-arB" userLabel="Event EndTime">
+                              <rect key="frame" x="5" y="19.5" width="32" height="14.5"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              <nil key="highlightedColor"/>
+                            </label>
+                          </subviews>
+                          <constraints>
+                            <constraint firstAttribute="width" constant="42" id="r9t-sb-ycD"/>
+                          </constraints>
+                        </stackView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="全天" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KIV-kE-cmY" userLabel="Event AllDay">
+                          <rect key="frame" x="326" y="13" width="31" height="18"/>
+                          <fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
+                          <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                          <nil key="highlightedColor"/>
+                        </label>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="2ui-5h-ZC7" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="1JL-Dp-A6W"/>
+                        <constraint firstItem="JXL-RY-KpG" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="Ibd-e8-GXJ"/>
+                        <constraint firstItem="YuP-80-oar" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="QdU-mY-k9o"/>
+                        <constraint firstItem="2ui-5h-ZC7" firstAttribute="leading" secondItem="YuP-80-oar" secondAttribute="trailing" constant="8" id="V6b-cg-chx"/>
+                        <constraint firstItem="JXL-RY-KpG" firstAttribute="leading" secondItem="lyc-3f-O6N" secondAttribute="leading" constant="18" id="dSx-3I-cxQ"/>
+                        <constraint firstAttribute="trailing" secondItem="2ui-5h-ZC7" secondAttribute="trailing" constant="18" id="fwY-HU-g8c"/>
+                        <constraint firstItem="YuP-80-oar" firstAttribute="leading" secondItem="JXL-RY-KpG" secondAttribute="trailing" constant="8" id="kgr-jn-t9O"/>
+                        <constraint firstAttribute="trailing" secondItem="KIV-kE-cmY" secondAttribute="trailing" constant="18" id="mam-ns-u2j"/>
+                        <constraint firstItem="KIV-kE-cmY" firstAttribute="centerY" secondItem="lyc-3f-O6N" secondAttribute="centerY" id="rH1-jv-JMV"/>
+                      </constraints>
+                    </tableViewCellContentView>
                     <connections>
-                        <outlet property="calendarPickerView" destination="pyF-R2-ql8" id="ff9-q3-kSd"/>
-                        <outlet property="deleteBtn" destination="OMA-Fp-nFl" id="TGm-RG-0hj"/>
-                        <outlet property="evenEndTimeStackView" destination="lNF-vK-WbX" id="Ad5-xH-qU5"/>
-                        <outlet property="eventAllDaySwitch" destination="PwN-cV-5Cp" id="2NZ-HE-72x"/>
-                        <outlet property="eventColorStackView" destination="i8o-dB-E0v" id="cbm-j1-pSM"/>
-                        <outlet property="eventEndTime" destination="Rqe-Vw-UzF" id="TET-gY-0on"/>
-                        <outlet property="eventRemark" destination="reH-A1-vQT" id="o9n-yx-WTB"/>
-                        <outlet property="eventStartTime" destination="Dub-8d-dx7" id="9np-fO-mk8"/>
-                        <outlet property="eventStartTimeStackView" destination="HqM-sQ-xhn" id="kkn-0i-smN"/>
-                        <outlet property="eventTitle" destination="gaP-Lw-V7E" id="7V2-hB-clk"/>
-                        <outlet property="remindPickerView" destination="eRL-b7-sZv" id="XWt-3h-5tg"/>
-                        <outlet property="repeatPickerView" destination="fbt-RB-x4p" id="hTZ-eo-mYS"/>
-                        <outlet property="repeatTableViewCell" destination="e5P-Ds-0Jm" id="vbx-6i-wdG"/>
-                        <outlet property="untilDateLabel" destination="k6W-yh-OR2" id="Z4N-tW-TwM"/>
-                        <outlet property="untilDateStackView" destination="F44-6G-rM2" id="od1-Zb-XkP"/>
-                        <outlet property="weekDaysStackView" destination="vc3-qe-cTN" id="D73-xs-enz"/>
+                      <outlet property="eventAllDay" destination="KIV-kE-cmY" id="34j-Xs-8z2"/>
+                      <outlet property="eventColorView" destination="JXL-RY-KpG" id="FzI-2i-OMO"/>
+                      <outlet property="eventEndTime" destination="jIB-o0-arB" id="TDp-Ag-gq3"/>
+                      <outlet property="eventStartTime" destination="les-0j-Mxf" id="eJA-Fg-C5K"/>
+                      <outlet property="eventTimeStack" destination="2ui-5h-ZC7" id="RcE-jB-uZq"/>
+                      <outlet property="eventTitleView" destination="YuP-80-oar" id="GaE-LI-V7N"/>
+                      <segue destination="Vxk-45-vB1" kind="show" identifier="showEventDetail" id="VOH-7P-zaY"/>
                     </connections>
-                </tableViewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="UiU-q1-2zR" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="1816.8" y="-694.00299850074964"/>
-        </scene>
-        <!--Navigation Controller-->
-        <scene sceneID="Uen-X6-xyC">
-            <objects>
-                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="tKt-3P-uQz" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
-                    <toolbarItems/>
-                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="tBY-YA-bTM">
-                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
-                        <autoresizingMask key="autoresizingMask"/>
-                    </navigationBar>
-                    <nil name="viewControllers"/>
+                  </tableViewCell>
+                </prototypes>
+              </tableView>
+              <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="M0F-7m-vuY" userLabel="BottomBar">
+                <rect key="frame" x="0.0" y="627" width="375" height="40"/>
+                <subviews>
+                  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wt1-wW-6mZ">
+                    <rect key="frame" x="16" y="3.5" width="35" height="33"/>
+                    <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
+                    <state key="normal" title="今天"/>
                     <connections>
-                        <segue destination="xYY-yG-JGa" kind="relationship" relationship="rootViewController" id="1nR-FI-RTb"/>
+                      <action selector="todayAction:" destination="xYY-yG-JGa" eventType="touchUpInside" id="Wd8-Ne-Gwr"/>
                     </connections>
-                </navigationController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="Ia6-rz-Icf" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="-90.400000000000006" y="-694.00299850074964"/>
-        </scene>
-        <!--Calendar Left Menu Controller-->
-        <scene sceneID="3By-VB-pei">
-            <objects>
-                <tableViewController id="L5W-fh-UuH" customClass="OOCalendarLeftMenuController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
-                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="FSW-kR-JAk">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <containerView key="tableHeaderView" opaque="NO" contentMode="scaleToFill" id="KcX-qQ-DIF">
-                            <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
-                            <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
-                            <connections>
-                                <segue destination="xFe-Nw-gR2" kind="embed" id="JrC-H1-NOw"/>
-                            </connections>
-                        </containerView>
-                        <prototypes>
-                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="calendarTableCell" id="hIV-F8-hEt" customClass="CalendarTableViewCell" customModule="O2Platform" customModuleProvider="target">
-                                <rect key="frame" x="0.0" y="78" width="375" height="44"/>
-                                <autoresizingMask key="autoresizingMask"/>
-                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hIV-F8-hEt" id="vcr-nc-qYD">
-                                    <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
-                                    <autoresizingMask key="autoresizingMask"/>
-                                    <subviews>
-                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nUr-LS-pfg">
-                                            <rect key="frame" x="24" y="13" width="18" height="18"/>
-                                            <color key="backgroundColor" red="0.29803921570000003" green="0.68627450980000004" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
-                                            <constraints>
-                                                <constraint firstAttribute="width" constant="18" id="5lB-4A-bhs"/>
-                                                <constraint firstAttribute="height" constant="18" id="GBp-du-Gru"/>
-                                            </constraints>
-                                            <userDefinedRuntimeAttributes>
-                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                    <real key="value" value="9"/>
-                                                </userDefinedRuntimeAttribute>
-                                            </userDefinedRuntimeAttributes>
-                                        </view>
-                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我的日历" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="onv-WL-BxB">
-                                            <rect key="frame" x="52" y="11.5" width="263" height="20.5"/>
-                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                            <nil key="textColor"/>
-                                            <nil key="highlightedColor"/>
-                                        </label>
-                                        <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BTT-cO-3bH">
-                                            <rect key="frame" x="325" y="10" width="34" height="24"/>
-                                            <constraints>
-                                                <constraint firstAttribute="height" constant="24" id="vBm-Id-XQ9"/>
-                                                <constraint firstAttribute="width" constant="32" id="ySg-20-HOz"/>
-                                            </constraints>
-                                            <connections>
-                                                <action selector="calendarSwitchTap:" destination="hIV-F8-hEt" eventType="valueChanged" id="cgk-KU-AwN"/>
-                                            </connections>
-                                        </switch>
-                                    </subviews>
-                                    <constraints>
-                                        <constraint firstItem="nUr-LS-pfg" firstAttribute="centerY" secondItem="vcr-nc-qYD" secondAttribute="centerY" id="0fm-s1-CUn"/>
-                                        <constraint firstItem="BTT-cO-3bH" firstAttribute="centerY" secondItem="vcr-nc-qYD" secondAttribute="centerY" id="JcJ-17-Hw0"/>
-                                        <constraint firstItem="onv-WL-BxB" firstAttribute="centerY" secondItem="vcr-nc-qYD" secondAttribute="centerY" id="MiO-8E-It5"/>
-                                        <constraint firstItem="BTT-cO-3bH" firstAttribute="leading" secondItem="onv-WL-BxB" secondAttribute="trailing" constant="10" id="ZWp-uB-5KZ"/>
-                                        <constraint firstItem="onv-WL-BxB" firstAttribute="leading" secondItem="nUr-LS-pfg" secondAttribute="trailing" constant="10" id="bbS-0Q-jnE"/>
-                                        <constraint firstAttribute="trailing" secondItem="BTT-cO-3bH" secondAttribute="trailing" constant="18" id="kUb-UW-eTW"/>
-                                        <constraint firstItem="nUr-LS-pfg" firstAttribute="leading" secondItem="vcr-nc-qYD" secondAttribute="leading" constant="24" id="sih-O1-7td"/>
-                                    </constraints>
-                                </tableViewCellContentView>
-                                <connections>
-                                    <outlet property="calendarColorView" destination="nUr-LS-pfg" id="OOL-1P-0oF"/>
-                                    <outlet property="calendarNameView" destination="onv-WL-BxB" id="QCD-H7-VUE"/>
-                                    <outlet property="calendarSwitch" destination="BTT-cO-3bH" id="dFh-ng-dUj"/>
-                                </connections>
-                            </tableViewCell>
-                        </prototypes>
-                        <sections/>
-                        <connections>
-                            <outlet property="dataSource" destination="L5W-fh-UuH" id="Sjl-ck-xz3"/>
-                            <outlet property="delegate" destination="L5W-fh-UuH" id="Hl3-Fp-5PQ"/>
-                        </connections>
-                    </tableView>
+                  </button>
+                  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="71T-qf-T8Z">
+                    <rect key="frame" x="324" y="3.5" width="35" height="33"/>
+                    <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
+                    <state key="normal" title="日历"/>
                     <connections>
-                        <outlet property="addCalendarBtnView" destination="KcX-qQ-DIF" id="kAk-es-Ig5"/>
-                        <segue destination="6hI-Zf-Dol" kind="show" identifier="showCalendarSegue" id="dTl-zx-3mn"/>
+                      <segue destination="L5W-fh-UuH" kind="show" id="DF4-xt-Rlu"/>
                     </connections>
-                </tableViewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="ffa-JI-hF2" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="-90" y="139"/>
-        </scene>
-        <!--View Controller-->
-        <scene sceneID="EQw-x0-gJd">
-            <objects>
-                <viewController id="xFe-Nw-gR2" sceneMemberID="viewController">
-                    <view key="view" contentMode="scaleToFill" id="lIW-wy-yeL">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <subviews>
-                            <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="9kE-CW-qbe">
-                                <rect key="frame" x="32" y="0.0" width="311" height="50"/>
-                                <subviews>
-                                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_zengjia" translatesAutoresizingMaskIntoConstraints="NO" id="fce-xE-dhf">
-                                        <rect key="frame" x="0.0" y="14" width="22" height="22"/>
-                                        <constraints>
-                                            <constraint firstAttribute="height" constant="22" id="nfU-kQ-Cuu"/>
-                                            <constraint firstAttribute="width" constant="22" id="sK8-rN-1yv"/>
-                                        </constraints>
-                                    </imageView>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="新增日历" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lgr-ZD-kXw">
-                                        <rect key="frame" x="38" y="15" width="273" height="20.5"/>
-                                        <gestureRecognizers/>
-                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                        <nil key="textColor"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
-                                </subviews>
+                  </button>
+                </subviews>
+                <color key="backgroundColor" red="0.97647058823529409" green="0.97647058823529409" blue="0.97647058823529409" alpha="1" colorSpace="calibratedRGB"/>
+                <constraints>
+                  <constraint firstAttribute="height" constant="40" id="EPO-5J-aQ8"/>
+                  <constraint firstItem="wt1-wW-6mZ" firstAttribute="leading" secondItem="M0F-7m-vuY" secondAttribute="leading" constant="16" id="aoT-z2-Iuk"/>
+                  <constraint firstAttribute="trailing" secondItem="71T-qf-T8Z" secondAttribute="trailing" constant="16" id="bQo-4L-Bhv"/>
+                  <constraint firstItem="wt1-wW-6mZ" firstAttribute="centerY" secondItem="M0F-7m-vuY" secondAttribute="centerY" id="opA-fa-ziv"/>
+                  <constraint firstItem="71T-qf-T8Z" firstAttribute="centerY" secondItem="M0F-7m-vuY" secondAttribute="centerY" id="ufw-UJ-60Y"/>
+                </constraints>
+              </view>
+            </subviews>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+              <constraint firstItem="M0F-7m-vuY" firstAttribute="bottom" secondItem="YOP-fD-eOB" secondAttribute="bottom" id="1g7-OC-yaV"/>
+              <constraint firstItem="KJj-zi-dZB" firstAttribute="leading" secondItem="YOP-fD-eOB" secondAttribute="leading" id="8Bi-5G-lvJ"/>
+              <constraint firstItem="M0F-7m-vuY" firstAttribute="top" secondItem="KJj-zi-dZB" secondAttribute="bottom" id="AIF-zg-ryj"/>
+              <constraint firstItem="KJj-zi-dZB" firstAttribute="trailing" secondItem="YOP-fD-eOB" secondAttribute="trailing" id="MLm-Tk-l38"/>
+              <constraint firstItem="M0F-7m-vuY" firstAttribute="trailing" secondItem="YOP-fD-eOB" secondAttribute="trailing" id="dJ4-wm-Y8z"/>
+              <constraint firstItem="M0F-7m-vuY" firstAttribute="leading" secondItem="YOP-fD-eOB" secondAttribute="leading" id="kLc-Qp-gzN"/>
+              <constraint firstItem="KJj-zi-dZB" firstAttribute="top" secondItem="YOP-fD-eOB" secondAttribute="top" id="plZ-2M-2pz"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="YOP-fD-eOB"/>
+          </view>
+          <navigationItem key="navigationItem" id="4qR-Bd-8HM"/>
+          <connections>
+            <outlet property="calendarBtn" destination="71T-qf-T8Z" id="kmy-qp-47B"/>
+            <outlet property="tableView" destination="KJj-zi-dZB" id="BLE-0u-ldM"/>
+            <outlet property="todayBtn" destination="wt1-wW-6mZ" id="oTj-Yv-omZ"/>
+          </connections>
+        </viewController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="NFS-3Q-UWF" userLabel="First Responder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="848.79999999999995" y="-694.00299850074964"/>
+    </scene>
+    <!--Calendar Event View Controller-->
+    <scene sceneID="Aj2-RD-S3x">
+      <objects>
+        <tableViewController id="Vxk-45-vB1" customClass="OOCalendarEventViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+          <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="7H1-7C-M3e">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <sections>
+              <tableViewSection id="Ogn-vO-7jG">
+                <cells>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="45" id="uxG-oP-2Jx">
+                    <rect key="frame" x="0.0" y="28" width="375" height="45"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="uxG-oP-2Jx" id="MKv-co-tJv">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="45"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="例如:开会" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="gaP-Lw-V7E">
+                          <rect key="frame" x="16" y="5" width="354" height="35"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="gaP-Lw-V7E" firstAttribute="top" secondItem="MKv-co-tJv" secondAttribute="top" constant="5" id="Umh-GC-vHb"/>
+                        <constraint firstAttribute="bottom" secondItem="gaP-Lw-V7E" secondAttribute="bottom" constant="5" id="aYp-Fg-OyP"/>
+                        <constraint firstItem="gaP-Lw-V7E" firstAttribute="leading" secondItem="MKv-co-tJv" secondAttribute="leading" constant="16" id="szc-Rj-gp8"/>
+                        <constraint firstAttribute="trailing" secondItem="gaP-Lw-V7E" secondAttribute="trailing" constant="5" id="uFD-7h-XoM"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="120" id="Nqb-uU-RgB">
+                    <rect key="frame" x="0.0" y="73" width="375" height="120"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Nqb-uU-RgB" id="PQX-mp-zBS">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="120"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="lpS-Ep-u9o">
+                          <rect key="frame" x="16" y="5" width="100" height="24"/>
+                          <subviews>
+                            <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="PwN-cV-5Cp">
+                              <rect key="frame" x="0.0" y="0.0" width="50" height="24"/>
+                              <constraints>
+                                <constraint firstAttribute="width" constant="48" id="Cy3-uM-ruq"/>
+                                <constraint firstAttribute="height" constant="24" id="VCr-I8-jVq"/>
+                              </constraints>
+                              <connections>
+                                <action selector="tapAllDaySwitch:" destination="Vxk-45-vB1" eventType="valueChanged" id="rrC-lO-H2n"/>
+                              </connections>
+                            </switch>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="全天" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rdY-4r-1NV">
+                              <rect key="frame" x="63" y="0.0" width="37" height="24"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
+                              <nil key="textColor"/>
+                              <nil key="highlightedColor"/>
+                            </label>
+                          </subviews>
+                          <constraints>
+                            <constraint firstAttribute="width" constant="100" id="s4W-o2-CN4"/>
+                          </constraints>
+                        </stackView>
+                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_shijian" translatesAutoresizingMaskIntoConstraints="NO" id="sfg-C9-T2u">
+                          <rect key="frame" x="16" y="45" width="22" height="22"/>
+                          <constraints>
+                            <constraint firstAttribute="width" constant="22" id="6WJ-71-uTo"/>
+                            <constraint firstAttribute="height" constant="22" id="9gU-gy-aua"/>
+                          </constraints>
+                        </imageView>
+                        <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="NNc-Zq-e8a">
+                          <rect key="frame" x="74" y="46" width="285" height="64"/>
+                          <subviews>
+                            <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HqM-sQ-xhn">
+                              <rect key="frame" x="0.0" y="0.0" width="285" height="22"/>
+                              <subviews>
+                                <label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2018年07月30日 13:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dub-8d-dx7">
+                                  <rect key="frame" x="0.0" y="0.0" width="261" height="22"/>
+                                  <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
+                                  <nil key="textColor"/>
+                                  <nil key="highlightedColor"/>
+                                </label>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_arrow" translatesAutoresizingMaskIntoConstraints="NO" id="23o-Vb-7fY">
+                                  <rect key="frame" x="261" y="0.0" width="24" height="22"/>
+                                  <constraints>
+                                    <constraint firstAttribute="width" constant="24" id="HAj-Bt-7rV"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                            </stackView>
+                            <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lNF-vK-WbX">
+                              <rect key="frame" x="0.0" y="42" width="285" height="22"/>
+                              <subviews>
+                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2018年07月30日 13:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rqe-Vw-UzF">
+                                  <rect key="frame" x="0.0" y="0.0" width="261" height="22"/>
+                                  <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
+                                  <nil key="textColor"/>
+                                  <nil key="highlightedColor"/>
+                                </label>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_arrow" translatesAutoresizingMaskIntoConstraints="NO" id="y7l-as-AD6">
+                                  <rect key="frame" x="261" y="0.0" width="24" height="22"/>
+                                  <constraints>
+                                    <constraint firstAttribute="width" constant="24" id="sMs-sB-hyI"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
                             </stackView>
-                        </subviews>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <constraints>
-                            <constraint firstItem="9kE-CW-qbe" firstAttribute="leading" secondItem="lIW-wy-yeL" secondAttribute="leadingMargin" constant="16" id="5rg-Vk-iwb"/>
-                            <constraint firstAttribute="trailingMargin" secondItem="9kE-CW-qbe" secondAttribute="trailing" constant="16" id="Bjh-rF-QQo"/>
-                            <constraint firstItem="9kE-CW-qbe" firstAttribute="top" secondItem="lIW-wy-yeL" secondAttribute="topMargin" id="DIn-lL-K5V"/>
-                            <constraint firstAttribute="bottomMargin" secondItem="9kE-CW-qbe" secondAttribute="bottom" id="vQB-at-qUU"/>
-                        </constraints>
-                        <viewLayoutGuide key="safeArea" id="VP9-5C-v7b"/>
+                          </subviews>
+                          <gestureRecognizers/>
+                          <constraints>
+                            <constraint firstAttribute="height" constant="64" id="S4m-1J-ydh"/>
+                          </constraints>
+                        </stackView>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="NNc-Zq-e8a" firstAttribute="leading" secondItem="sfg-C9-T2u" secondAttribute="trailing" constant="36" id="am8-ML-krx"/>
+                        <constraint firstItem="lpS-Ep-u9o" firstAttribute="top" secondItem="PQX-mp-zBS" secondAttribute="top" constant="5" id="c3D-PO-yJC"/>
+                        <constraint firstItem="sfg-C9-T2u" firstAttribute="leading" secondItem="PQX-mp-zBS" secondAttribute="leadingMargin" id="dds-UT-Ghg"/>
+                        <constraint firstItem="sfg-C9-T2u" firstAttribute="top" secondItem="lpS-Ep-u9o" secondAttribute="bottom" constant="16" id="kcR-EW-imZ"/>
+                        <constraint firstAttribute="trailingMargin" secondItem="NNc-Zq-e8a" secondAttribute="trailing" id="pmh-Pn-TSi"/>
+                        <constraint firstItem="lpS-Ep-u9o" firstAttribute="leading" secondItem="PQX-mp-zBS" secondAttribute="leading" constant="16" id="s0k-x8-Y6F"/>
+                        <constraint firstItem="NNc-Zq-e8a" firstAttribute="top" secondItem="lpS-Ep-u9o" secondAttribute="bottom" constant="17" id="vUd-A0-kwF"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="60" id="4Gg-JY-9Yo">
+                    <rect key="frame" x="0.0" y="193" width="375" height="60"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="4Gg-JY-9Yo" id="7Su-0t-5EZ">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="evq-G0-rF6">
+                          <rect key="frame" x="16" y="0.0" width="359" height="60"/>
+                          <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_hdjr" translatesAutoresizingMaskIntoConstraints="NO" id="kBX-9l-V1q">
+                              <rect key="frame" x="0.0" y="19" width="22" height="22"/>
+                              <constraints>
+                                <constraint firstAttribute="width" constant="22" id="1FT-SO-P9R"/>
+                                <constraint firstAttribute="height" constant="22" id="rqM-2X-wbT"/>
+                              </constraints>
+                            </imageView>
+                            <pickerView tag="110" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pyF-R2-ql8">
+                              <rect key="frame" x="37" y="0.0" width="322" height="60"/>
+                              <connections>
+                                <outlet property="dataSource" destination="Vxk-45-vB1" id="5Dd-B7-Q9q"/>
+                                <outlet property="delegate" destination="Vxk-45-vB1" id="8qX-9R-aTO"/>
+                              </connections>
+                            </pickerView>
+                          </subviews>
+                        </stackView>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="evq-G0-rF6" firstAttribute="top" secondItem="7Su-0t-5EZ" secondAttribute="top" id="1VO-mL-jHa"/>
+                        <constraint firstItem="evq-G0-rF6" firstAttribute="leading" secondItem="7Su-0t-5EZ" secondAttribute="leading" constant="16" id="h8s-cf-9Sd"/>
+                        <constraint firstAttribute="trailing" secondItem="evq-G0-rF6" secondAttribute="trailing" id="oUj-3c-7gc"/>
+                        <constraint firstAttribute="bottom" secondItem="evq-G0-rF6" secondAttribute="bottom" id="uSr-V1-QZu"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="45" id="qQX-Lv-NHQ">
+                    <rect key="frame" x="0.0" y="253" width="375" height="45"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qQX-Lv-NHQ" id="Tln-Ch-B5c">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="45"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="i8o-dB-E0v">
+                          <rect key="frame" x="20" y="8" width="339" height="29"/>
+                          <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Dgr-Bu-MAQ" userLabel="blue">
+                              <rect key="frame" x="0.0" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="gmX-mE-SDk">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="6VV-qr-hlC"/>
+                                    <constraint firstAttribute="width" constant="18" id="Uxh-wh-1YZ"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.25882352941176467" green="0.5607843137254902" blue="0.9882352941176471" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="gmX-mE-SDk" firstAttribute="centerX" secondItem="Dgr-Bu-MAQ" secondAttribute="centerX" id="9aJ-c0-KjP"/>
+                                <constraint firstAttribute="width" constant="24" id="Ivw-Nt-e8L"/>
+                                <constraint firstItem="gmX-mE-SDk" firstAttribute="centerY" secondItem="Dgr-Bu-MAQ" secondAttribute="centerY" id="Y6X-EZ-SM0"/>
+                                <constraint firstAttribute="height" constant="24" id="aY4-rA-in7"/>
+                              </constraints>
+                            </view>
+                            <view tag="1" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nS3-qA-VwA" userLabel="green">
+                              <rect key="frame" x="45" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="D3N-kh-Mq7">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="WOI-Ze-YEg"/>
+                                    <constraint firstAttribute="width" constant="18" id="ZQ2-1O-AN1"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.35686274509803922" green="0.80000000000000004" blue="0.38039215686274508" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="D3N-kh-Mq7" firstAttribute="centerY" secondItem="nS3-qA-VwA" secondAttribute="centerY" id="8BK-XT-xJE"/>
+                                <constraint firstAttribute="width" constant="24" id="SRZ-Rw-NfW"/>
+                                <constraint firstAttribute="height" constant="24" id="kPY-21-Y5A"/>
+                                <constraint firstItem="D3N-kh-Mq7" firstAttribute="centerX" secondItem="nS3-qA-VwA" secondAttribute="centerX" id="ltQ-jl-c7u"/>
+                              </constraints>
+                            </view>
+                            <view tag="2" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hRM-n9-khc" userLabel="orangle">
+                              <rect key="frame" x="90" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="KzE-S1-77g">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="AUe-S7-hB3"/>
+                                    <constraint firstAttribute="width" constant="18" id="aFI-ew-wtP"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.97647058823529409" green="0.74901960784313726" blue="0.14117647058823529" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="KzE-S1-77g" firstAttribute="centerY" secondItem="hRM-n9-khc" secondAttribute="centerY" id="HEF-qz-tnK"/>
+                                <constraint firstAttribute="height" constant="24" id="HQu-84-yYi"/>
+                                <constraint firstItem="KzE-S1-77g" firstAttribute="centerX" secondItem="hRM-n9-khc" secondAttribute="centerX" id="ceb-An-1Tu"/>
+                                <constraint firstAttribute="width" constant="24" id="mck-HZ-ZCw"/>
+                              </constraints>
+                            </view>
+                            <view tag="3" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ggx-2y-fDS" userLabel="crimson">
+                              <rect key="frame" x="135" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="GK6-ih-mWE">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="ae3-zr-8aw"/>
+                                    <constraint firstAttribute="width" constant="18" id="w5l-GX-PJI"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.96862745098039216" green="0.37254901960784315" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstAttribute="width" constant="24" id="UMl-J7-DNy"/>
+                                <constraint firstItem="GK6-ih-mWE" firstAttribute="centerX" secondItem="Ggx-2y-fDS" secondAttribute="centerX" id="bXf-5U-QEv"/>
+                                <constraint firstAttribute="height" constant="24" id="hfe-b7-39J"/>
+                                <constraint firstItem="GK6-ih-mWE" firstAttribute="centerY" secondItem="Ggx-2y-fDS" secondAttribute="centerY" id="w1I-Sz-h3c"/>
+                              </constraints>
+                            </view>
+                            <view tag="4" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OGU-7P-pbj" userLabel="lightpurple">
+                              <rect key="frame" x="180" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="yE3-0X-Ixh">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="width" constant="18" id="ARI-92-xj5"/>
+                                    <constraint firstAttribute="height" constant="18" id="Rnx-ld-gJh"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.94509803921568625" green="0.50196078431372548" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="yE3-0X-Ixh" firstAttribute="centerY" secondItem="OGU-7P-pbj" secondAttribute="centerY" id="782-Qj-Dlk"/>
+                                <constraint firstAttribute="width" constant="24" id="Fv9-El-C1c"/>
+                                <constraint firstAttribute="height" constant="24" id="HVA-E8-C61"/>
+                                <constraint firstItem="yE3-0X-Ixh" firstAttribute="centerX" secondItem="OGU-7P-pbj" secondAttribute="centerX" id="dqb-xX-kM8"/>
+                              </constraints>
+                            </view>
+                            <view tag="5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="H7n-vf-H9J" userLabel="purple">
+                              <rect key="frame" x="225" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="D0E-yX-QaI">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="TFo-D4-GPF"/>
+                                    <constraint firstAttribute="width" constant="18" id="iAL-KH-v80"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.56470588235294117" green="0.44705882352941173" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstAttribute="height" constant="24" id="8gq-CO-eTY"/>
+                                <constraint firstItem="D0E-yX-QaI" firstAttribute="centerY" secondItem="H7n-vf-H9J" secondAttribute="centerY" id="99s-cw-T7m"/>
+                                <constraint firstAttribute="width" constant="24" id="E8S-ZW-5fe"/>
+                                <constraint firstItem="D0E-yX-QaI" firstAttribute="centerX" secondItem="H7n-vf-H9J" secondAttribute="centerX" id="sRT-G7-gp6"/>
+                              </constraints>
+                            </view>
+                            <view tag="6" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="118-Aw-aif" userLabel="gray">
+                              <rect key="frame" x="270" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="8UA-Zc-sdH">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="J8p-K5-Xsp"/>
+                                    <constraint firstAttribute="width" constant="18" id="KUz-t8-9b4"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.56470588235294117" green="0.56470588235294117" blue="0.56470588235294117" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="8UA-Zc-sdH" firstAttribute="centerY" secondItem="118-Aw-aif" secondAttribute="centerY" id="5PU-ld-WL6"/>
+                                <constraint firstAttribute="height" constant="24" id="EoQ-gB-JFa"/>
+                                <constraint firstAttribute="width" constant="24" id="gYN-JO-57r"/>
+                                <constraint firstItem="8UA-Zc-sdH" firstAttribute="centerX" secondItem="118-Aw-aif" secondAttribute="centerX" id="lfI-fD-zeO"/>
+                              </constraints>
+                            </view>
+                            <view tag="7" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aua-TK-Qnv" userLabel="cyanine">
+                              <rect key="frame" x="315" y="2.5" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="tye-Jf-YHm">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="5WS-2e-3QG"/>
+                                    <constraint firstAttribute="width" constant="18" id="mHx-1M-qnT"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.078431372549019607" green="0.38431372549019605" blue="0.74509803921568629" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstAttribute="width" constant="24" id="4nx-sl-RIa"/>
+                                <constraint firstAttribute="height" constant="24" id="Kpb-lJ-sTI"/>
+                                <constraint firstItem="tye-Jf-YHm" firstAttribute="centerY" secondItem="aua-TK-Qnv" secondAttribute="centerY" id="cKv-Ul-QD0"/>
+                                <constraint firstItem="tye-Jf-YHm" firstAttribute="centerX" secondItem="aua-TK-Qnv" secondAttribute="centerX" id="cYE-GL-WBJ"/>
+                              </constraints>
+                            </view>
+                          </subviews>
+                        </stackView>
+                      </subviews>
+                      <constraints>
+                        <constraint firstAttribute="trailing" secondItem="i8o-dB-E0v" secondAttribute="trailing" constant="16" id="8Ox-ef-kQX"/>
+                        <constraint firstAttribute="bottom" secondItem="i8o-dB-E0v" secondAttribute="bottom" constant="8" id="Zut-5K-hJS"/>
+                        <constraint firstItem="i8o-dB-E0v" firstAttribute="leading" secondItem="Tln-Ch-B5c" secondAttribute="leading" constant="20" id="iT4-S9-mfI"/>
+                        <constraint firstItem="i8o-dB-E0v" firstAttribute="top" secondItem="Tln-Ch-B5c" secondAttribute="top" constant="8" id="lBf-sr-HQW"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="60" id="u6G-MU-dPL">
+                    <rect key="frame" x="0.0" y="298" width="375" height="60"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="u6G-MU-dPL" id="auw-zx-G07">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="Nvw-Uv-y4F">
+                          <rect key="frame" x="16" y="0.0" width="359" height="60"/>
+                          <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_tixing" translatesAutoresizingMaskIntoConstraints="NO" id="JPO-Kb-7YE">
+                              <rect key="frame" x="0.0" y="19" width="22" height="22"/>
+                              <constraints>
+                                <constraint firstAttribute="width" constant="22" id="XHQ-Ne-kEe"/>
+                                <constraint firstAttribute="height" constant="22" id="i2w-Kk-1a1"/>
+                              </constraints>
+                            </imageView>
+                            <pickerView tag="111" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eRL-b7-sZv">
+                              <rect key="frame" x="37" y="0.0" width="322" height="60"/>
+                              <connections>
+                                <outlet property="dataSource" destination="Vxk-45-vB1" id="X6V-QF-7cw"/>
+                                <outlet property="delegate" destination="Vxk-45-vB1" id="cI2-NL-CGH"/>
+                              </connections>
+                            </pickerView>
+                          </subviews>
+                        </stackView>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="Nvw-Uv-y4F" firstAttribute="top" secondItem="auw-zx-G07" secondAttribute="top" id="BS2-oE-3V6"/>
+                        <constraint firstAttribute="bottom" secondItem="Nvw-Uv-y4F" secondAttribute="bottom" id="S9Y-Ea-NPh"/>
+                        <constraint firstAttribute="trailing" secondItem="Nvw-Uv-y4F" secondAttribute="trailing" id="mVM-zG-UZP"/>
+                        <constraint firstItem="Nvw-Uv-y4F" firstAttribute="leading" secondItem="auw-zx-G07" secondAttribute="leading" constant="16" id="oXw-gx-pWs"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="60" id="e5P-Ds-0Jm">
+                    <rect key="frame" x="0.0" y="358" width="375" height="60"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="e5P-Ds-0Jm" id="vBL-Zg-uX0">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="o2n-Cg-nQo">
+                          <rect key="frame" x="16" y="0.0" width="359" height="60"/>
+                          <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_chongfu" translatesAutoresizingMaskIntoConstraints="NO" id="W5r-qL-MRy">
+                              <rect key="frame" x="0.0" y="19" width="22" height="22"/>
+                              <constraints>
+                                <constraint firstAttribute="height" constant="22" id="eN6-V0-CcT"/>
+                                <constraint firstAttribute="width" constant="22" id="mxs-yb-OVM"/>
+                              </constraints>
+                            </imageView>
+                            <pickerView tag="112" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fbt-RB-x4p">
+                              <rect key="frame" x="37" y="0.0" width="322" height="60"/>
+                              <connections>
+                                <outlet property="dataSource" destination="Vxk-45-vB1" id="cCT-Ga-6th"/>
+                                <outlet property="delegate" destination="Vxk-45-vB1" id="TRG-7c-mdR"/>
+                              </connections>
+                            </pickerView>
+                          </subviews>
+                          <constraints>
+                            <constraint firstAttribute="height" constant="60" id="gjT-w1-VIx"/>
+                          </constraints>
+                        </stackView>
+                        <stackView hidden="YES" opaque="NO" contentMode="scaleToFill" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="F44-6G-rM2">
+                          <rect key="frame" x="32" y="65" width="311" height="20"/>
+                          <subviews>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="截至日期:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IMf-BA-twt">
+                              <rect key="frame" x="0.0" y="3" width="64" height="14.5"/>
+                              <constraints>
+                                <constraint firstAttribute="width" constant="64" id="oup-D2-hLu"/>
+                              </constraints>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <nil key="textColor"/>
+                              <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="k6W-yh-OR2">
+                              <rect key="frame" x="79" y="0.0" width="232" height="20"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              <nil key="highlightedColor"/>
+                            </label>
+                          </subviews>
+                          <constraints>
+                            <constraint firstAttribute="height" constant="20" id="iwQ-Pk-1HS"/>
+                          </constraints>
+                        </stackView>
+                        <stackView hidden="YES" opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="vc3-qe-cTN">
+                          <rect key="frame" x="32" y="90" width="327" height="27"/>
+                          <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qy2-Ll-2FL">
+                              <rect key="frame" x="0.0" y="0.0" width="30" height="27"/>
+                              <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <state key="normal" title="周一">
+                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <color key="titleShadowColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              </state>
+                            </button>
+                            <button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hQt-nQ-yDV">
+                              <rect key="frame" x="49.5" y="0.0" width="30" height="27"/>
+                              <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <state key="normal" title="周二">
+                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              </state>
+                            </button>
+                            <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GeN-7S-V8E">
+                              <rect key="frame" x="99" y="0.0" width="30" height="27"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <state key="normal" title="周三">
+                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              </state>
+                            </button>
+                            <button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xOJ-cj-hMc">
+                              <rect key="frame" x="148.5" y="0.0" width="30" height="27"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <state key="normal" title="周四">
+                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              </state>
+                            </button>
+                            <button opaque="NO" tag="4" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Szk-bc-YOL">
+                              <rect key="frame" x="198" y="0.0" width="30" height="27"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <state key="normal" title="周五">
+                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              </state>
+                            </button>
+                            <button opaque="NO" tag="5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Qxa-Na-eLg">
+                              <rect key="frame" x="247.5" y="0.0" width="30" height="27"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <state key="normal" title="周六">
+                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              </state>
+                            </button>
+                            <button opaque="NO" tag="6" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="To9-IU-AE6">
+                              <rect key="frame" x="297" y="0.0" width="30" height="27"/>
+                              <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
+                              <state key="normal" title="周日">
+                                <color key="titleColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                              </state>
+                            </button>
+                          </subviews>
+                        </stackView>
+                      </subviews>
+                      <constraints>
+                        <constraint firstAttribute="trailingMargin" secondItem="F44-6G-rM2" secondAttribute="trailing" constant="16" id="2ZB-Co-2pB"/>
+                        <constraint firstItem="F44-6G-rM2" firstAttribute="top" secondItem="o2n-Cg-nQo" secondAttribute="bottom" constant="5" id="8pt-BZ-t3e"/>
+                        <constraint firstAttribute="trailingMargin" secondItem="vc3-qe-cTN" secondAttribute="trailing" id="F4z-Sg-29S"/>
+                        <constraint firstItem="vc3-qe-cTN" firstAttribute="top" secondItem="F44-6G-rM2" secondAttribute="bottom" constant="5" id="SS2-2g-5NJ"/>
+                        <constraint firstItem="vc3-qe-cTN" firstAttribute="leading" secondItem="vBL-Zg-uX0" secondAttribute="leadingMargin" constant="16" id="XMb-c7-8LK"/>
+                        <constraint firstItem="o2n-Cg-nQo" firstAttribute="leading" secondItem="vBL-Zg-uX0" secondAttribute="leading" constant="16" id="eqQ-It-Ump"/>
+                        <constraint firstAttribute="trailing" secondItem="o2n-Cg-nQo" secondAttribute="trailing" id="oxH-8z-faW"/>
+                        <constraint firstItem="F44-6G-rM2" firstAttribute="leading" secondItem="vBL-Zg-uX0" secondAttribute="leadingMargin" constant="16" id="qc8-ft-bgf"/>
+                        <constraint firstItem="o2n-Cg-nQo" firstAttribute="top" secondItem="vBL-Zg-uX0" secondAttribute="top" id="xMp-X8-TEi"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="206" id="mRu-Km-9dY">
+                    <rect key="frame" x="0.0" y="418" width="375" height="206"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="mRu-Km-9dY" id="HFU-yb-U6N">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="206"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OMA-Fp-nFl">
+                          <rect key="frame" x="16" y="148" width="343" height="40"/>
+                          <color key="backgroundColor" red="0.98431372549019602" green="0.27843137254901962" blue="0.27843137254901962" alpha="1" colorSpace="calibratedRGB"/>
+                          <constraints>
+                            <constraint firstAttribute="height" constant="40" id="z38-hq-zd6"/>
+                          </constraints>
+                          <state key="normal" title="删   除">
+                            <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                          </state>
+                          <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                              <real key="value" value="5"/>
+                            </userDefinedRuntimeAttribute>
+                          </userDefinedRuntimeAttributes>
+                          <connections>
+                            <action selector="tapDeleteBtn:" destination="Vxk-45-vB1" eventType="touchUpInside" id="d3V-gw-XoF"/>
+                          </connections>
+                        </button>
+                        <webView contentMode="scaleToFill" scalesPageToFit="YES" translatesAutoresizingMaskIntoConstraints="NO" id="S5p-a6-Tlk">
+                          <rect key="frame" x="16" y="11" width="343" height="90"/>
+                          <color key="backgroundColor" red="0.36078431370000003" green="0.38823529410000002" blue="0.4039215686" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        </webView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pZL-hd-WYm">
+                          <rect key="frame" x="16" y="109" width="62" height="30"/>
+                          <state key="normal" title="编辑内容"/>
+                          <connections>
+                            <segue destination="LoN-sU-f4i" kind="presentation" id="HaO-ws-b1o"/>
+                          </connections>
+                        </button>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="S5p-a6-Tlk" firstAttribute="trailing" secondItem="OMA-Fp-nFl" secondAttribute="trailing" id="7E1-je-yNn"/>
+                        <constraint firstItem="pZL-hd-WYm" firstAttribute="top" secondItem="S5p-a6-Tlk" secondAttribute="bottom" constant="8" id="9Z2-Ml-EPm"/>
+                        <constraint firstItem="OMA-Fp-nFl" firstAttribute="top" secondItem="pZL-hd-WYm" secondAttribute="bottom" constant="9" id="Olk-nI-9EA"/>
+                        <constraint firstItem="S5p-a6-Tlk" firstAttribute="leading" secondItem="pZL-hd-WYm" secondAttribute="leading" id="PLd-73-1r0"/>
+                        <constraint firstItem="pZL-hd-WYm" firstAttribute="leading" secondItem="OMA-Fp-nFl" secondAttribute="leading" id="XmT-aR-1oc"/>
+                        <constraint firstItem="OMA-Fp-nFl" firstAttribute="leading" secondItem="HFU-yb-U6N" secondAttribute="leading" constant="16" id="aya-2K-2Jr"/>
+                        <constraint firstAttribute="bottomMargin" secondItem="OMA-Fp-nFl" secondAttribute="bottom" constant="7" id="h7A-3s-Y55"/>
+                        <constraint firstItem="S5p-a6-Tlk" firstAttribute="top" secondItem="HFU-yb-U6N" secondAttribute="topMargin" id="q12-WJ-gjX"/>
+                        <constraint firstItem="S5p-a6-Tlk" firstAttribute="trailing" secondItem="HFU-yb-U6N" secondAttribute="trailingMargin" id="qjj-Vg-Thi"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                </cells>
+              </tableViewSection>
+            </sections>
+            <connections>
+              <outlet property="dataSource" destination="Vxk-45-vB1" id="XpN-cu-Ay8"/>
+              <outlet property="delegate" destination="Vxk-45-vB1" id="18X-HM-sWl"/>
+            </connections>
+          </tableView>
+          <connections>
+            <outlet property="calendarPickerView" destination="pyF-R2-ql8" id="ff9-q3-kSd"/>
+            <outlet property="deleteBtn" destination="OMA-Fp-nFl" id="TGm-RG-0hj"/>
+            <outlet property="evenEndTimeStackView" destination="lNF-vK-WbX" id="Ad5-xH-qU5"/>
+            <outlet property="eventAllDaySwitch" destination="PwN-cV-5Cp" id="2NZ-HE-72x"/>
+            <outlet property="eventColorStackView" destination="i8o-dB-E0v" id="cbm-j1-pSM"/>
+            <outlet property="eventEndTime" destination="Rqe-Vw-UzF" id="TET-gY-0on"/>
+            <outlet property="eventStartTime" destination="Dub-8d-dx7" id="9np-fO-mk8"/>
+            <outlet property="eventStartTimeStackView" destination="HqM-sQ-xhn" id="kkn-0i-smN"/>
+            <outlet property="eventTitle" destination="gaP-Lw-V7E" id="7V2-hB-clk"/>
+            <outlet property="remindPickerView" destination="eRL-b7-sZv" id="XWt-3h-5tg"/>
+            <outlet property="repeatPickerView" destination="fbt-RB-x4p" id="hTZ-eo-mYS"/>
+            <outlet property="repeatTableViewCell" destination="e5P-Ds-0Jm" id="vbx-6i-wdG"/>
+            <outlet property="untilDateLabel" destination="k6W-yh-OR2" id="Z4N-tW-TwM"/>
+            <outlet property="untilDateStackView" destination="F44-6G-rM2" id="od1-Zb-XkP"/>
+            <outlet property="webRemark" destination="S5p-a6-Tlk" id="RgQ-ZK-Iis"/>
+            <outlet property="weekDaysStackView" destination="vc3-qe-cTN" id="D73-xs-enz"/>
+          </connections>
+        </tableViewController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="UiU-q1-2zR" userLabel="First Responder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="1816.8" y="-694.00299850074964"/>
+    </scene>
+    <!--Navigation Controller-->
+    <scene sceneID="Uen-X6-xyC">
+      <objects>
+        <navigationController automaticallyAdjustsScrollViewInsets="NO" id="tKt-3P-uQz" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+          <toolbarItems/>
+          <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="tBY-YA-bTM">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+            <autoresizingMask key="autoresizingMask"/>
+          </navigationBar>
+          <nil name="viewControllers"/>
+          <connections>
+            <segue destination="xYY-yG-JGa" kind="relationship" relationship="rootViewController" id="1nR-FI-RTb"/>
+          </connections>
+        </navigationController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="Ia6-rz-Icf" userLabel="First Responder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="-90.400000000000006" y="-694.00299850074964"/>
+    </scene>
+    <!--Calendar Left Menu Controller-->
+    <scene sceneID="3By-VB-pei">
+      <objects>
+        <tableViewController id="L5W-fh-UuH" customClass="OOCalendarLeftMenuController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+          <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="FSW-kR-JAk">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <containerView key="tableHeaderView" opaque="NO" contentMode="scaleToFill" id="KcX-qQ-DIF">
+              <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
+              <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
+              <connections>
+                <segue destination="xFe-Nw-gR2" kind="embed" id="JrC-H1-NOw"/>
+              </connections>
+            </containerView>
+            <prototypes>
+              <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="calendarTableCell" id="hIV-F8-hEt" customClass="CalendarTableViewCell" customModule="O2Platform" customModuleProvider="target">
+                <rect key="frame" x="0.0" y="78" width="375" height="43.5"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hIV-F8-hEt" id="vcr-nc-qYD">
+                  <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
+                  <autoresizingMask key="autoresizingMask"/>
+                  <subviews>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nUr-LS-pfg">
+                      <rect key="frame" x="24" y="13" width="18" height="18"/>
+                      <color key="backgroundColor" red="0.29803921570000003" green="0.68627450980000004" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
+                      <constraints>
+                        <constraint firstAttribute="width" constant="18" id="5lB-4A-bhs"/>
+                        <constraint firstAttribute="height" constant="18" id="GBp-du-Gru"/>
+                      </constraints>
+                      <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                          <real key="value" value="9"/>
+                        </userDefinedRuntimeAttribute>
+                      </userDefinedRuntimeAttributes>
                     </view>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="6Z9-K4-mSY" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="711" y="-114"/>
-        </scene>
-        <!--Calendar View Controller-->
-        <scene sceneID="k3n-BF-rgt">
-            <objects>
-                <tableViewController id="6hI-Zf-Dol" customClass="OOCalendarViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
-                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="m9A-UR-VmU">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <sections>
-                            <tableViewSection id="Mag-aW-ELK">
-                                <cells>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="ky5-3M-po5">
-                                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ky5-3M-po5" id="ey7-OW-MZr">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="例如:我的日历" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="E1I-tu-3OF">
-                                                    <rect key="frame" x="16" y="10" width="349" height="23.5"/>
-                                                    <nil key="textColor"/>
-                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                                                    <textInputTraits key="textInputTraits"/>
-                                                </textField>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstAttribute="trailing" secondItem="E1I-tu-3OF" secondAttribute="trailing" constant="10" id="0zd-rU-i9l"/>
-                                                <constraint firstAttribute="bottom" secondItem="E1I-tu-3OF" secondAttribute="bottom" constant="10" id="1Ai-iW-Gr4"/>
-                                                <constraint firstItem="E1I-tu-3OF" firstAttribute="leading" secondItem="ey7-OW-MZr" secondAttribute="leading" constant="16" id="ug4-Pk-Lb7"/>
-                                                <constraint firstItem="E1I-tu-3OF" firstAttribute="top" secondItem="ey7-OW-MZr" secondAttribute="top" constant="10" id="xW5-Or-ZFH"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="imH-Dp-MJa">
-                                        <rect key="frame" x="0.0" y="44" width="375" height="44"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="imH-Dp-MJa" id="Pnd-27-RRL">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="fl8-ZU-9Cp">
-                                                    <rect key="frame" x="16" y="8" width="50" height="27.5"/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="width" constant="48" id="GYo-gg-b9Y"/>
-                                                    </constraints>
-                                                    <connections>
-                                                        <action selector="tapAllDaySwitch:" destination="Vxk-45-vB1" eventType="valueChanged" id="uyw-pR-SBK"/>
-                                                    </connections>
-                                                </switch>
-                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="是否公开" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="915-R7-0Ph">
-                                                    <rect key="frame" x="74" y="8" width="70" height="27.5"/>
-                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                                    <nil key="textColor"/>
-                                                    <nil key="highlightedColor"/>
-                                                </label>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstItem="915-R7-0Ph" firstAttribute="leading" secondItem="fl8-ZU-9Cp" secondAttribute="trailing" constant="10" id="6LP-5t-yu6"/>
-                                                <constraint firstItem="fl8-ZU-9Cp" firstAttribute="top" secondItem="Pnd-27-RRL" secondAttribute="top" constant="8" id="m1N-gR-9GW"/>
-                                                <constraint firstItem="915-R7-0Ph" firstAttribute="top" secondItem="Pnd-27-RRL" secondAttribute="top" constant="8" id="o5r-2x-ZWm"/>
-                                                <constraint firstItem="fl8-ZU-9Cp" firstAttribute="leading" secondItem="Pnd-27-RRL" secondAttribute="leading" constant="16" id="od7-nI-vWr"/>
-                                                <constraint firstAttribute="bottom" secondItem="fl8-ZU-9Cp" secondAttribute="bottom" constant="8" id="pVF-nh-QnE"/>
-                                                <constraint firstAttribute="bottom" secondItem="915-R7-0Ph" secondAttribute="bottom" constant="8" id="rjx-tf-iGC"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="afV-IA-a4y">
-                                        <rect key="frame" x="0.0" y="88" width="375" height="44"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="afV-IA-a4y" id="4vX-Ja-OcF">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="sc4-ds-up5">
-                                                    <rect key="frame" x="16" y="8" width="349" height="27.5"/>
-                                                    <subviews>
-                                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZZL-hY-6YY" userLabel="blue">
-                                                            <rect key="frame" x="0.0" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="4Zq-Ya-Cty">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="Fcw-yJ-iVq"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="LGR-Zl-j45"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.25882352939999997" green="0.56078431370000004" blue="0.98823529409999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="height" constant="24" id="X2E-o7-Hl7"/>
-                                                                <constraint firstItem="4Zq-Ya-Cty" firstAttribute="centerY" secondItem="ZZL-hY-6YY" secondAttribute="centerY" id="bvj-V3-vbS"/>
-                                                                <constraint firstItem="4Zq-Ya-Cty" firstAttribute="centerX" secondItem="ZZL-hY-6YY" secondAttribute="centerX" id="c7f-RH-KRl"/>
-                                                                <constraint firstAttribute="width" constant="24" id="eSi-ds-FcL"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                        <view tag="1" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NYD-3q-2cV" userLabel="green">
-                                                            <rect key="frame" x="46.5" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="HeG-XU-b83">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="width" constant="18" id="Idk-aY-FpI"/>
-                                                                        <constraint firstAttribute="height" constant="18" id="w2Y-0G-V64"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.35686274509999999" green="0.80000000000000004" blue="0.3803921569" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="HeG-XU-b83" firstAttribute="centerY" secondItem="NYD-3q-2cV" secondAttribute="centerY" id="6Iz-zC-yuG"/>
-                                                                <constraint firstAttribute="height" constant="24" id="KDu-a8-a8H"/>
-                                                                <constraint firstAttribute="width" constant="24" id="OLu-AH-Xss"/>
-                                                                <constraint firstItem="HeG-XU-b83" firstAttribute="centerX" secondItem="NYD-3q-2cV" secondAttribute="centerX" id="pWl-Hi-P1L"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                        <view tag="2" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D56-uh-5fZ" userLabel="orangle">
-                                                            <rect key="frame" x="93" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="g39-3s-lMM">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="hYd-J9-VyB"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="qo5-L5-4b2"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.97647058819999999" green="0.74901960779999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="g39-3s-lMM" firstAttribute="centerX" secondItem="D56-uh-5fZ" secondAttribute="centerX" id="SAm-8O-8Qy"/>
-                                                                <constraint firstAttribute="height" constant="24" id="TQc-uS-y6T"/>
-                                                                <constraint firstItem="g39-3s-lMM" firstAttribute="centerY" secondItem="D56-uh-5fZ" secondAttribute="centerY" id="cr8-sO-DAu"/>
-                                                                <constraint firstAttribute="width" constant="24" id="o7H-Zp-ELR"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                        <view tag="3" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="woZ-Gb-d4P" userLabel="crimson">
-                                                            <rect key="frame" x="139.5" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="4kU-pE-6cc">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="7Gi-fy-FPq"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="H4Q-Xw-YFg"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.96862745100000003" green="0.37254901959999998" blue="0.34901960780000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="4kU-pE-6cc" firstAttribute="centerX" secondItem="woZ-Gb-d4P" secondAttribute="centerX" id="ATO-bL-qRR"/>
-                                                                <constraint firstAttribute="width" constant="24" id="FnE-PG-2ma"/>
-                                                                <constraint firstItem="4kU-pE-6cc" firstAttribute="centerY" secondItem="woZ-Gb-d4P" secondAttribute="centerY" id="TCZ-Eb-eja"/>
-                                                                <constraint firstAttribute="height" constant="24" id="Xlk-td-GPN"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                        <view tag="4" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yqn-YF-8O7" userLabel="lightpurple">
-                                                            <rect key="frame" x="185.5" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="s1R-I4-hnF">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="fUV-fB-nwm"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="uAF-QS-bqm"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.94509803920000002" green="0.50196078430000002" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="height" constant="24" id="B2G-ZS-kx2"/>
-                                                                <constraint firstItem="s1R-I4-hnF" firstAttribute="centerY" secondItem="yqn-YF-8O7" secondAttribute="centerY" id="F6f-lB-X3R"/>
-                                                                <constraint firstItem="s1R-I4-hnF" firstAttribute="centerX" secondItem="yqn-YF-8O7" secondAttribute="centerX" id="PUB-qH-aE6"/>
-                                                                <constraint firstAttribute="width" constant="24" id="S0L-3x-4x2"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                        <view tag="5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JiP-uY-CBd" userLabel="purple">
-                                                            <rect key="frame" x="232" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="29t-6S-Hlb">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="width" constant="18" id="JBI-jM-OBE"/>
-                                                                        <constraint firstAttribute="height" constant="18" id="ilL-Cn-r8J"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.56470588239999997" green="0.44705882349999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstItem="29t-6S-Hlb" firstAttribute="centerX" secondItem="JiP-uY-CBd" secondAttribute="centerX" id="BVU-WV-f1d"/>
-                                                                <constraint firstAttribute="width" constant="24" id="FYA-DA-JpN"/>
-                                                                <constraint firstAttribute="height" constant="24" id="Q9u-5Y-iYr"/>
-                                                                <constraint firstItem="29t-6S-Hlb" firstAttribute="centerY" secondItem="JiP-uY-CBd" secondAttribute="centerY" id="g7A-xs-AxP"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                        <view tag="6" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rKC-SP-A0D" userLabel="gray">
-                                                            <rect key="frame" x="278.5" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="li5-KM-yd4">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="Sd2-xX-C2A"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="bQi-Yf-rGw"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.56470588239999997" green="0.56470588239999997" blue="0.56470588239999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="width" constant="24" id="06B-K1-xFi"/>
-                                                                <constraint firstItem="li5-KM-yd4" firstAttribute="centerX" secondItem="rKC-SP-A0D" secondAttribute="centerX" id="esH-dd-mLK"/>
-                                                                <constraint firstAttribute="height" constant="24" id="xye-1s-JaE"/>
-                                                                <constraint firstItem="li5-KM-yd4" firstAttribute="centerY" secondItem="rKC-SP-A0D" secondAttribute="centerY" id="yDt-LZ-FMl"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                        <view tag="7" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="T4I-Zn-V9w" userLabel="cyanine">
-                                                            <rect key="frame" x="325" y="2" width="24" height="24"/>
-                                                            <subviews>
-                                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="nx0-x2-HnL">
-                                                                    <rect key="frame" x="3" y="3" width="18" height="18"/>
-                                                                    <constraints>
-                                                                        <constraint firstAttribute="height" constant="18" id="ZZD-of-lra"/>
-                                                                        <constraint firstAttribute="width" constant="18" id="zM0-w1-q9Q"/>
-                                                                    </constraints>
-                                                                </imageView>
-                                                            </subviews>
-                                                            <color key="backgroundColor" red="0.078431372550000003" green="0.38431372549999998" blue="0.74509803919999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                                            <constraints>
-                                                                <constraint firstAttribute="height" constant="24" id="342-MO-tsM"/>
-                                                                <constraint firstItem="nx0-x2-HnL" firstAttribute="centerX" secondItem="T4I-Zn-V9w" secondAttribute="centerX" id="Laq-Vq-kDh"/>
-                                                                <constraint firstItem="nx0-x2-HnL" firstAttribute="centerY" secondItem="T4I-Zn-V9w" secondAttribute="centerY" id="RCd-Hw-gdu"/>
-                                                                <constraint firstAttribute="width" constant="24" id="cEt-IQ-FHo"/>
-                                                            </constraints>
-                                                            <userDefinedRuntimeAttributes>
-                                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                                    <real key="value" value="12"/>
-                                                                </userDefinedRuntimeAttribute>
-                                                            </userDefinedRuntimeAttributes>
-                                                        </view>
-                                                    </subviews>
-                                                </stackView>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstAttribute="bottom" secondItem="sc4-ds-up5" secondAttribute="bottom" constant="8" id="BJ9-sN-hUK"/>
-                                                <constraint firstAttribute="trailing" secondItem="sc4-ds-up5" secondAttribute="trailing" constant="10" id="QYU-vK-aEh"/>
-                                                <constraint firstItem="sc4-ds-up5" firstAttribute="leading" secondItem="4vX-Ja-OcF" secondAttribute="leading" constant="16" id="meC-wG-0Ge"/>
-                                                <constraint firstItem="sc4-ds-up5" firstAttribute="top" secondItem="4vX-Ja-OcF" secondAttribute="top" constant="8" id="q1X-8e-Shr"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="100" id="w3N-VO-khd">
-                                        <rect key="frame" x="0.0" y="132" width="375" height="100"/>
-                                        <autoresizingMask key="autoresizingMask"/>
-                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="w3N-VO-khd" id="HdW-WP-zq7">
-                                            <rect key="frame" x="0.0" y="0.0" width="375" height="99.5"/>
-                                            <autoresizingMask key="autoresizingMask"/>
-                                            <subviews>
-                                                <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" placeholder="添加说明" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="0zU-2p-l4e">
-                                                    <rect key="frame" x="16" y="8" width="349" height="40"/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="height" constant="40" id="Ryd-Gz-Ta1"/>
-                                                    </constraints>
-                                                    <nil key="textColor"/>
-                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                                                    <textInputTraits key="textInputTraits"/>
-                                                </textField>
-                                                <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fPK-4K-uqx">
-                                                    <rect key="frame" x="16" y="56" width="343" height="40"/>
-                                                    <color key="backgroundColor" red="0.98431372549999996" green="0.2784313725" blue="0.2784313725" alpha="1" colorSpace="calibratedRGB"/>
-                                                    <constraints>
-                                                        <constraint firstAttribute="height" constant="40" id="ar9-84-HBP"/>
-                                                    </constraints>
-                                                    <state key="normal" title="删   除">
-                                                        <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                    </state>
-                                                    <userDefinedRuntimeAttributes>
-                                                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                            <real key="value" value="5"/>
-                                                        </userDefinedRuntimeAttribute>
-                                                    </userDefinedRuntimeAttributes>
-                                                    <connections>
-                                                        <action selector="deleteBtnTap:" destination="6hI-Zf-Dol" eventType="touchUpInside" id="aPc-91-RY3"/>
-                                                        <action selector="tapDeleteBtn:" destination="Vxk-45-vB1" eventType="touchUpInside" id="Ct1-ny-L2j"/>
-                                                    </connections>
-                                                </button>
-                                            </subviews>
-                                            <constraints>
-                                                <constraint firstItem="0zU-2p-l4e" firstAttribute="top" secondItem="HdW-WP-zq7" secondAttribute="top" constant="8" id="GIN-dS-e04"/>
-                                                <constraint firstAttribute="trailing" secondItem="fPK-4K-uqx" secondAttribute="trailing" constant="16" id="dDp-3m-eQV"/>
-                                                <constraint firstItem="fPK-4K-uqx" firstAttribute="top" secondItem="0zU-2p-l4e" secondAttribute="bottom" constant="8" id="gaf-NU-3Jr"/>
-                                                <constraint firstAttribute="trailing" secondItem="0zU-2p-l4e" secondAttribute="trailing" constant="10" id="hS1-Op-3lS"/>
-                                                <constraint firstItem="0zU-2p-l4e" firstAttribute="leading" secondItem="HdW-WP-zq7" secondAttribute="leading" constant="16" id="jEy-xu-Vbz"/>
-                                                <constraint firstItem="fPK-4K-uqx" firstAttribute="leading" secondItem="HdW-WP-zq7" secondAttribute="leading" constant="16" id="w4C-Ao-SJv"/>
-                                            </constraints>
-                                        </tableViewCellContentView>
-                                    </tableViewCell>
-                                </cells>
-                            </tableViewSection>
-                        </sections>
-                        <connections>
-                            <outlet property="dataSource" destination="6hI-Zf-Dol" id="q6S-ea-AMu"/>
-                            <outlet property="delegate" destination="6hI-Zf-Dol" id="ugR-8t-BpE"/>
-                        </connections>
-                    </tableView>
-                    <connections>
-                        <outlet property="calendarColorStackView" destination="sc4-ds-up5" id="M83-qQ-5Dg"/>
-                        <outlet property="calendarDeleteBtn" destination="fPK-4K-uqx" id="ph2-Fe-3lA"/>
-                        <outlet property="calendarIsOpenSwitch" destination="fl8-ZU-9Cp" id="B0z-eA-yDa"/>
-                        <outlet property="calendarNameField" destination="E1I-tu-3OF" id="43n-JC-CE2"/>
-                        <outlet property="calendarRemarkField" destination="0zU-2p-l4e" id="ia9-f3-lRI"/>
-                    </connections>
-                </tableViewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="Kl7-oF-Qbs" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="1650" y="98"/>
-        </scene>
-    </scenes>
-    <resources>
-        <image name="check" width="23" height="20"/>
-        <image name="icon_arrow" width="22" height="22"/>
-        <image name="icon_chongfu" width="22" height="22"/>
-        <image name="icon_hdjr" width="22" height="22"/>
-        <image name="icon_shijian" width="22" height="22"/>
-        <image name="icon_tixing" width="22" height="22"/>
-        <image name="icon_zengjia" width="22" height="22"/>
-    </resources>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="我的日历" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="onv-WL-BxB">
+                      <rect key="frame" x="52" y="11.5" width="263" height="20.5"/>
+                      <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                      <nil key="textColor"/>
+                      <nil key="highlightedColor"/>
+                    </label>
+                    <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BTT-cO-3bH">
+                      <rect key="frame" x="325" y="10" width="34" height="24"/>
+                      <constraints>
+                        <constraint firstAttribute="height" constant="24" id="vBm-Id-XQ9"/>
+                        <constraint firstAttribute="width" constant="32" id="ySg-20-HOz"/>
+                      </constraints>
+                      <connections>
+                        <action selector="calendarSwitchTap:" destination="hIV-F8-hEt" eventType="valueChanged" id="cgk-KU-AwN"/>
+                      </connections>
+                    </switch>
+                  </subviews>
+                  <constraints>
+                    <constraint firstItem="nUr-LS-pfg" firstAttribute="centerY" secondItem="vcr-nc-qYD" secondAttribute="centerY" id="0fm-s1-CUn"/>
+                    <constraint firstItem="BTT-cO-3bH" firstAttribute="centerY" secondItem="vcr-nc-qYD" secondAttribute="centerY" id="JcJ-17-Hw0"/>
+                    <constraint firstItem="onv-WL-BxB" firstAttribute="centerY" secondItem="vcr-nc-qYD" secondAttribute="centerY" id="MiO-8E-It5"/>
+                    <constraint firstItem="BTT-cO-3bH" firstAttribute="leading" secondItem="onv-WL-BxB" secondAttribute="trailing" constant="10" id="ZWp-uB-5KZ"/>
+                    <constraint firstItem="onv-WL-BxB" firstAttribute="leading" secondItem="nUr-LS-pfg" secondAttribute="trailing" constant="10" id="bbS-0Q-jnE"/>
+                    <constraint firstAttribute="trailing" secondItem="BTT-cO-3bH" secondAttribute="trailing" constant="18" id="kUb-UW-eTW"/>
+                    <constraint firstItem="nUr-LS-pfg" firstAttribute="leading" secondItem="vcr-nc-qYD" secondAttribute="leading" constant="24" id="sih-O1-7td"/>
+                  </constraints>
+                </tableViewCellContentView>
+                <connections>
+                  <outlet property="calendarColorView" destination="nUr-LS-pfg" id="OOL-1P-0oF"/>
+                  <outlet property="calendarNameView" destination="onv-WL-BxB" id="QCD-H7-VUE"/>
+                  <outlet property="calendarSwitch" destination="BTT-cO-3bH" id="dFh-ng-dUj"/>
+                </connections>
+              </tableViewCell>
+            </prototypes>
+            <sections/>
+            <connections>
+              <outlet property="dataSource" destination="L5W-fh-UuH" id="Sjl-ck-xz3"/>
+              <outlet property="delegate" destination="L5W-fh-UuH" id="Hl3-Fp-5PQ"/>
+            </connections>
+          </tableView>
+          <connections>
+            <outlet property="addCalendarBtnView" destination="KcX-qQ-DIF" id="kAk-es-Ig5"/>
+            <segue destination="6hI-Zf-Dol" kind="show" identifier="showCalendarSegue" id="dTl-zx-3mn"/>
+          </connections>
+        </tableViewController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="ffa-JI-hF2" userLabel="First Responder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="-90" y="139"/>
+    </scene>
+    <!--View Controller-->
+    <scene sceneID="EQw-x0-gJd">
+      <objects>
+        <viewController id="xFe-Nw-gR2" sceneMemberID="viewController">
+          <view key="view" contentMode="scaleToFill" id="lIW-wy-yeL">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+              <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="9kE-CW-qbe">
+                <rect key="frame" x="32" y="0.0" width="311" height="50"/>
+                <subviews>
+                  <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_zengjia" translatesAutoresizingMaskIntoConstraints="NO" id="fce-xE-dhf">
+                    <rect key="frame" x="0.0" y="14" width="22" height="22"/>
+                    <constraints>
+                      <constraint firstAttribute="height" constant="22" id="nfU-kQ-Cuu"/>
+                      <constraint firstAttribute="width" constant="22" id="sK8-rN-1yv"/>
+                    </constraints>
+                  </imageView>
+                  <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="新增日历" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lgr-ZD-kXw">
+                    <rect key="frame" x="38" y="15" width="273" height="20.5"/>
+                    <gestureRecognizers/>
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                  </label>
+                </subviews>
+              </stackView>
+            </subviews>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+              <constraint firstItem="9kE-CW-qbe" firstAttribute="leading" secondItem="lIW-wy-yeL" secondAttribute="leadingMargin" constant="16" id="5rg-Vk-iwb"/>
+              <constraint firstAttribute="trailingMargin" secondItem="9kE-CW-qbe" secondAttribute="trailing" constant="16" id="Bjh-rF-QQo"/>
+              <constraint firstItem="9kE-CW-qbe" firstAttribute="top" secondItem="lIW-wy-yeL" secondAttribute="topMargin" id="DIn-lL-K5V"/>
+              <constraint firstAttribute="bottomMargin" secondItem="9kE-CW-qbe" secondAttribute="bottom" id="vQB-at-qUU"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="VP9-5C-v7b"/>
+          </view>
+        </viewController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="6Z9-K4-mSY" userLabel="First Responder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="709.60000000000002" y="-114.24287856071965"/>
+    </scene>
+    <!--Calendar View Controller-->
+    <scene sceneID="k3n-BF-rgt">
+      <objects>
+        <tableViewController id="6hI-Zf-Dol" customClass="OOCalendarViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+          <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="m9A-UR-VmU">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <sections>
+              <tableViewSection id="Mag-aW-ELK">
+                <cells>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="ky5-3M-po5">
+                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ky5-3M-po5" id="ey7-OW-MZr">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="例如:我的日历" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="E1I-tu-3OF">
+                          <rect key="frame" x="16" y="10" width="349" height="24"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                      </subviews>
+                      <constraints>
+                        <constraint firstAttribute="trailing" secondItem="E1I-tu-3OF" secondAttribute="trailing" constant="10" id="0zd-rU-i9l"/>
+                        <constraint firstAttribute="bottom" secondItem="E1I-tu-3OF" secondAttribute="bottom" constant="10" id="1Ai-iW-Gr4"/>
+                        <constraint firstItem="E1I-tu-3OF" firstAttribute="leading" secondItem="ey7-OW-MZr" secondAttribute="leading" constant="16" id="ug4-Pk-Lb7"/>
+                        <constraint firstItem="E1I-tu-3OF" firstAttribute="top" secondItem="ey7-OW-MZr" secondAttribute="top" constant="10" id="xW5-Or-ZFH"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="tk5-Hl-mbm">
+                    <rect key="frame" x="0.0" y="72" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="tk5-Hl-mbm" id="EZA-d2-7f1">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请选择类型" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="6Nq-Qx-KK4">
+                          <rect key="frame" x="16" y="5" width="213" height="34"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <accessibility key="accessibilityConfiguration" identifier="calendarType"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                        <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GjW-u2-fg5">
+                          <rect key="frame" x="297" y="6" width="31" height="30"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <state key="normal" title="选择"/>
+                          <connections>
+                            <action selector="selectType:" destination="6hI-Zf-Dol" eventType="touchUpInside" id="e5v-uq-r9b"/>
+                          </connections>
+                        </button>
+                      </subviews>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="imH-Dp-MJa">
+                    <rect key="frame" x="0.0" y="116" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="imH-Dp-MJa" id="Pnd-27-RRL">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="fl8-ZU-9Cp">
+                          <rect key="frame" x="16" y="8" width="50" height="28"/>
+                          <constraints>
+                            <constraint firstAttribute="width" constant="48" id="GYo-gg-b9Y"/>
+                          </constraints>
+                          <connections>
+                            <action selector="tapAllDaySwitch:" destination="Vxk-45-vB1" eventType="valueChanged" id="uyw-pR-SBK"/>
+                          </connections>
+                        </switch>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="是否公开" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="915-R7-0Ph">
+                          <rect key="frame" x="74" y="8" width="70" height="28"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                          <nil key="textColor"/>
+                          <nil key="highlightedColor"/>
+                        </label>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="915-R7-0Ph" firstAttribute="leading" secondItem="fl8-ZU-9Cp" secondAttribute="trailing" constant="10" id="6LP-5t-yu6"/>
+                        <constraint firstItem="fl8-ZU-9Cp" firstAttribute="top" secondItem="Pnd-27-RRL" secondAttribute="top" constant="8" id="m1N-gR-9GW"/>
+                        <constraint firstItem="915-R7-0Ph" firstAttribute="top" secondItem="Pnd-27-RRL" secondAttribute="top" constant="8" id="o5r-2x-ZWm"/>
+                        <constraint firstItem="fl8-ZU-9Cp" firstAttribute="leading" secondItem="Pnd-27-RRL" secondAttribute="leading" constant="16" id="od7-nI-vWr"/>
+                        <constraint firstAttribute="bottom" secondItem="fl8-ZU-9Cp" secondAttribute="bottom" constant="8" id="pVF-nh-QnE"/>
+                        <constraint firstAttribute="bottom" secondItem="915-R7-0Ph" secondAttribute="bottom" constant="8" id="rjx-tf-iGC"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="afV-IA-a4y">
+                    <rect key="frame" x="0.0" y="160" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="afV-IA-a4y" id="4vX-Ja-OcF">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="sc4-ds-up5">
+                          <rect key="frame" x="16" y="8" width="349" height="27.5"/>
+                          <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZZL-hY-6YY" userLabel="blue">
+                              <rect key="frame" x="0.0" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="4Zq-Ya-Cty">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="Fcw-yJ-iVq"/>
+                                    <constraint firstAttribute="width" constant="18" id="LGR-Zl-j45"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.25882352939999997" green="0.56078431370000004" blue="0.98823529409999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstAttribute="height" constant="24" id="X2E-o7-Hl7"/>
+                                <constraint firstItem="4Zq-Ya-Cty" firstAttribute="centerY" secondItem="ZZL-hY-6YY" secondAttribute="centerY" id="bvj-V3-vbS"/>
+                                <constraint firstItem="4Zq-Ya-Cty" firstAttribute="centerX" secondItem="ZZL-hY-6YY" secondAttribute="centerX" id="c7f-RH-KRl"/>
+                                <constraint firstAttribute="width" constant="24" id="eSi-ds-FcL"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                            <view tag="1" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NYD-3q-2cV" userLabel="green">
+                              <rect key="frame" x="46.5" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="HeG-XU-b83">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="width" constant="18" id="Idk-aY-FpI"/>
+                                    <constraint firstAttribute="height" constant="18" id="w2Y-0G-V64"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.35686274509999999" green="0.80000000000000004" blue="0.3803921569" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="HeG-XU-b83" firstAttribute="centerY" secondItem="NYD-3q-2cV" secondAttribute="centerY" id="6Iz-zC-yuG"/>
+                                <constraint firstAttribute="height" constant="24" id="KDu-a8-a8H"/>
+                                <constraint firstAttribute="width" constant="24" id="OLu-AH-Xss"/>
+                                <constraint firstItem="HeG-XU-b83" firstAttribute="centerX" secondItem="NYD-3q-2cV" secondAttribute="centerX" id="pWl-Hi-P1L"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                            <view tag="2" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D56-uh-5fZ" userLabel="orangle">
+                              <rect key="frame" x="93" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="g39-3s-lMM">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="hYd-J9-VyB"/>
+                                    <constraint firstAttribute="width" constant="18" id="qo5-L5-4b2"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.97647058819999999" green="0.74901960779999999" blue="0.14117647059999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="g39-3s-lMM" firstAttribute="centerX" secondItem="D56-uh-5fZ" secondAttribute="centerX" id="SAm-8O-8Qy"/>
+                                <constraint firstAttribute="height" constant="24" id="TQc-uS-y6T"/>
+                                <constraint firstItem="g39-3s-lMM" firstAttribute="centerY" secondItem="D56-uh-5fZ" secondAttribute="centerY" id="cr8-sO-DAu"/>
+                                <constraint firstAttribute="width" constant="24" id="o7H-Zp-ELR"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                            <view tag="3" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="woZ-Gb-d4P" userLabel="crimson">
+                              <rect key="frame" x="139.5" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="4kU-pE-6cc">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="7Gi-fy-FPq"/>
+                                    <constraint firstAttribute="width" constant="18" id="H4Q-Xw-YFg"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.96862745100000003" green="0.37254901959999998" blue="0.34901960780000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="4kU-pE-6cc" firstAttribute="centerX" secondItem="woZ-Gb-d4P" secondAttribute="centerX" id="ATO-bL-qRR"/>
+                                <constraint firstAttribute="width" constant="24" id="FnE-PG-2ma"/>
+                                <constraint firstItem="4kU-pE-6cc" firstAttribute="centerY" secondItem="woZ-Gb-d4P" secondAttribute="centerY" id="TCZ-Eb-eja"/>
+                                <constraint firstAttribute="height" constant="24" id="Xlk-td-GPN"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                            <view tag="4" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yqn-YF-8O7" userLabel="lightpurple">
+                              <rect key="frame" x="185.5" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="s1R-I4-hnF">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="fUV-fB-nwm"/>
+                                    <constraint firstAttribute="width" constant="18" id="uAF-QS-bqm"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.94509803920000002" green="0.50196078430000002" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstAttribute="height" constant="24" id="B2G-ZS-kx2"/>
+                                <constraint firstItem="s1R-I4-hnF" firstAttribute="centerY" secondItem="yqn-YF-8O7" secondAttribute="centerY" id="F6f-lB-X3R"/>
+                                <constraint firstItem="s1R-I4-hnF" firstAttribute="centerX" secondItem="yqn-YF-8O7" secondAttribute="centerX" id="PUB-qH-aE6"/>
+                                <constraint firstAttribute="width" constant="24" id="S0L-3x-4x2"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                            <view tag="5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JiP-uY-CBd" userLabel="purple">
+                              <rect key="frame" x="232" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="29t-6S-Hlb">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="width" constant="18" id="JBI-jM-OBE"/>
+                                    <constraint firstAttribute="height" constant="18" id="ilL-Cn-r8J"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.56470588239999997" green="0.44705882349999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstItem="29t-6S-Hlb" firstAttribute="centerX" secondItem="JiP-uY-CBd" secondAttribute="centerX" id="BVU-WV-f1d"/>
+                                <constraint firstAttribute="width" constant="24" id="FYA-DA-JpN"/>
+                                <constraint firstAttribute="height" constant="24" id="Q9u-5Y-iYr"/>
+                                <constraint firstItem="29t-6S-Hlb" firstAttribute="centerY" secondItem="JiP-uY-CBd" secondAttribute="centerY" id="g7A-xs-AxP"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                            <view tag="6" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rKC-SP-A0D" userLabel="gray">
+                              <rect key="frame" x="278.5" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="li5-KM-yd4">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="Sd2-xX-C2A"/>
+                                    <constraint firstAttribute="width" constant="18" id="bQi-Yf-rGw"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.56470588239999997" green="0.56470588239999997" blue="0.56470588239999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstAttribute="width" constant="24" id="06B-K1-xFi"/>
+                                <constraint firstItem="li5-KM-yd4" firstAttribute="centerX" secondItem="rKC-SP-A0D" secondAttribute="centerX" id="esH-dd-mLK"/>
+                                <constraint firstAttribute="height" constant="24" id="xye-1s-JaE"/>
+                                <constraint firstItem="li5-KM-yd4" firstAttribute="centerY" secondItem="rKC-SP-A0D" secondAttribute="centerY" id="yDt-LZ-FMl"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                            <view tag="7" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="T4I-Zn-V9w" userLabel="cyanine">
+                              <rect key="frame" x="325" y="2" width="24" height="24"/>
+                              <subviews>
+                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="check" translatesAutoresizingMaskIntoConstraints="NO" id="nx0-x2-HnL">
+                                  <rect key="frame" x="3" y="3" width="18" height="18"/>
+                                  <constraints>
+                                    <constraint firstAttribute="height" constant="18" id="ZZD-of-lra"/>
+                                    <constraint firstAttribute="width" constant="18" id="zM0-w1-q9Q"/>
+                                  </constraints>
+                                </imageView>
+                              </subviews>
+                              <color key="backgroundColor" red="0.078431372550000003" green="0.38431372549999998" blue="0.74509803919999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                              <constraints>
+                                <constraint firstAttribute="height" constant="24" id="342-MO-tsM"/>
+                                <constraint firstItem="nx0-x2-HnL" firstAttribute="centerX" secondItem="T4I-Zn-V9w" secondAttribute="centerX" id="Laq-Vq-kDh"/>
+                                <constraint firstItem="nx0-x2-HnL" firstAttribute="centerY" secondItem="T4I-Zn-V9w" secondAttribute="centerY" id="RCd-Hw-gdu"/>
+                                <constraint firstAttribute="width" constant="24" id="cEt-IQ-FHo"/>
+                              </constraints>
+                              <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                  <real key="value" value="12"/>
+                                </userDefinedRuntimeAttribute>
+                              </userDefinedRuntimeAttributes>
+                            </view>
+                          </subviews>
+                        </stackView>
+                      </subviews>
+                      <constraints>
+                        <constraint firstAttribute="bottom" secondItem="sc4-ds-up5" secondAttribute="bottom" constant="8" id="BJ9-sN-hUK"/>
+                        <constraint firstAttribute="trailing" secondItem="sc4-ds-up5" secondAttribute="trailing" constant="10" id="QYU-vK-aEh"/>
+                        <constraint firstItem="sc4-ds-up5" firstAttribute="leading" secondItem="4vX-Ja-OcF" secondAttribute="leading" constant="16" id="meC-wG-0Ge"/>
+                        <constraint firstItem="sc4-ds-up5" firstAttribute="top" secondItem="4vX-Ja-OcF" secondAttribute="top" constant="8" id="q1X-8e-Shr"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="100" id="w3N-VO-khd">
+                    <rect key="frame" x="0.0" y="204" width="375" height="100"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="w3N-VO-khd" id="HdW-WP-zq7">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="100"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" placeholder="添加说明" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="0zU-2p-l4e">
+                          <rect key="frame" x="16" y="8" width="349" height="54"/>
+                          <constraints>
+                            <constraint firstAttribute="height" constant="40" id="Ryd-Gz-Ta1"/>
+                          </constraints>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                      </subviews>
+                      <constraints>
+                        <constraint firstItem="0zU-2p-l4e" firstAttribute="top" secondItem="HdW-WP-zq7" secondAttribute="top" constant="8" id="GIN-dS-e04"/>
+                        <constraint firstAttribute="trailing" secondItem="0zU-2p-l4e" secondAttribute="trailing" constant="10" id="hS1-Op-3lS"/>
+                        <constraint firstItem="0zU-2p-l4e" firstAttribute="leading" secondItem="HdW-WP-zq7" secondAttribute="leading" constant="16" id="jEy-xu-Vbz"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                </cells>
+              </tableViewSection>
+              <tableViewSection id="j8W-2y-K1h">
+                <cells>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="b9Z-Ey-cMh">
+                    <rect key="frame" x="0.0" y="360" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="b9Z-Ey-cMh" id="SSH-zn-oXh">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="选择所属组织" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vpF-O7-lvf">
+                          <rect key="frame" x="16" y="5" width="213" height="34"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <accessibility key="accessibilityConfiguration" identifier="calendarType"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                        <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kae-RP-FyB">
+                          <rect key="frame" x="297" y="6" width="31" height="30"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <state key="normal" title="选择"/>
+                          <connections>
+                            <action selector="selectOrg:" destination="6hI-Zf-Dol" eventType="touchUpInside" id="ZXk-NJ-BD5"/>
+                          </connections>
+                        </button>
+                      </subviews>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="sb3-wz-V5h">
+                    <rect key="frame" x="0.0" y="404" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="sb3-wz-V5h" id="iOf-91-Mpo">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="选择管理者" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="bIB-vr-JmD">
+                          <rect key="frame" x="16" y="5" width="213" height="34"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <accessibility key="accessibilityConfiguration" identifier="calendarType"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                        <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="m4R-gF-vOd">
+                          <rect key="frame" x="297" y="6" width="35" height="30"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <state key="normal" title="选择"/>
+                          <connections>
+                            <action selector="selectManager:" destination="6hI-Zf-Dol" eventType="touchUpInside" id="YIp-nK-zaa"/>
+                          </connections>
+                        </button>
+                      </subviews>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="xjH-ft-A13">
+                    <rect key="frame" x="0.0" y="448" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xjH-ft-A13" id="08M-eV-Wtw">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="选择可见范围" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="5RB-dp-23j">
+                          <rect key="frame" x="16" y="5" width="213" height="34"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <accessibility key="accessibilityConfiguration" identifier="calendarType"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                        <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yrc-Ws-oZH">
+                          <rect key="frame" x="297" y="6" width="31" height="30"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <state key="normal" title="选择"/>
+                          <connections>
+                            <action selector="selectScope:" destination="6hI-Zf-Dol" eventType="touchUpInside" id="5LG-bo-Jk1"/>
+                          </connections>
+                        </button>
+                      </subviews>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="bqR-JX-7Hn">
+                    <rect key="frame" x="0.0" y="492" width="375" height="44"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="bqR-JX-7Hn" id="uYh-KG-FIU">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="选择可新建范围" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="HYK-cG-NOj">
+                          <rect key="frame" x="16" y="5" width="213" height="34"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <accessibility key="accessibilityConfiguration" identifier="calendarType"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                          <textInputTraits key="textInputTraits"/>
+                        </textField>
+                        <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ueU-we-edj">
+                          <rect key="frame" x="297" y="6" width="31" height="30"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <state key="normal" title="选择"/>
+                          <connections>
+                            <action selector="selectNewScope:" destination="6hI-Zf-Dol" eventType="touchUpInside" id="yAx-yD-Esr"/>
+                          </connections>
+                        </button>
+                      </subviews>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                </cells>
+              </tableViewSection>
+              <tableViewSection id="kqD-jf-4p2">
+                <cells>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="49" id="M17-7p-CgG">
+                    <rect key="frame" x="0.0" y="592" width="375" height="49"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="M17-7p-CgG" id="W0o-2J-yuQ">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="49"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="是否启用" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qf3-2G-kRZ">
+                          <rect key="frame" x="64" y="14" width="70" height="21"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                          <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                          <nil key="textColor"/>
+                          <nil key="highlightedColor"/>
+                        </label>
+                        <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GTC-NP-gGg">
+                          <rect key="frame" x="9" y="9" width="49" height="31"/>
+                          <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        </switch>
+                      </subviews>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                  <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="113" id="8mT-v2-Qx8">
+                    <rect key="frame" x="0.0" y="641" width="375" height="113"/>
+                    <autoresizingMask key="autoresizingMask"/>
+                    <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="8mT-v2-Qx8" id="87S-Cm-kNa">
+                      <rect key="frame" x="0.0" y="0.0" width="375" height="113"/>
+                      <autoresizingMask key="autoresizingMask"/>
+                      <subviews>
+                        <button hidden="YES" opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ceC-iW-RJC">
+                          <rect key="frame" x="10" y="30" width="343" height="40"/>
+                          <color key="backgroundColor" red="0.98431372549999996" green="0.2784313725" blue="0.2784313725" alpha="1" colorSpace="calibratedRGB"/>
+                          <constraints>
+                            <constraint firstAttribute="height" constant="40" id="hsv-E0-CNX"/>
+                          </constraints>
+                          <state key="normal" title="删   除">
+                            <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                          </state>
+                          <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                              <real key="value" value="5"/>
+                            </userDefinedRuntimeAttribute>
+                          </userDefinedRuntimeAttributes>
+                          <connections>
+                            <action selector="deleteBtnTap:" destination="6hI-Zf-Dol" eventType="touchUpInside" id="Xes-eC-VfF"/>
+                            <action selector="tapDeleteBtn:" destination="Vxk-45-vB1" eventType="touchUpInside" id="IFP-6l-1ZD"/>
+                          </connections>
+                        </button>
+                      </subviews>
+                      <constraints>
+                        <constraint firstAttribute="trailing" secondItem="ceC-iW-RJC" secondAttribute="trailing" constant="16" id="Hrn-eU-isu"/>
+                        <constraint firstItem="ceC-iW-RJC" firstAttribute="leading" secondItem="87S-Cm-kNa" secondAttribute="leading" constant="16" id="clh-qU-E5h"/>
+                        <constraint firstItem="ceC-iW-RJC" firstAttribute="centerY" secondItem="87S-Cm-kNa" secondAttribute="centerY" id="eix-O3-ypw"/>
+                      </constraints>
+                    </tableViewCellContentView>
+                  </tableViewCell>
+                </cells>
+              </tableViewSection>
+            </sections>
+            <connections>
+              <outlet property="dataSource" destination="6hI-Zf-Dol" id="q6S-ea-AMu"/>
+              <outlet property="delegate" destination="6hI-Zf-Dol" id="ugR-8t-BpE"/>
+            </connections>
+          </tableView>
+          <connections>
+            <outlet property="calendarColorStackView" destination="sc4-ds-up5" id="M83-qQ-5Dg"/>
+            <outlet property="calendarDeleteBtn" destination="ceC-iW-RJC" id="hSl-e9-yib"/>
+            <outlet property="calendarIsOpenBtn" destination="GjW-u2-fg5" id="qt3-Vs-Ni9"/>
+            <outlet property="calendarIsOpenSwitch" destination="fl8-ZU-9Cp" id="B0z-eA-yDa"/>
+            <outlet property="calendarManagerField" destination="bIB-vr-JmD" id="vj2-pN-AIk"/>
+            <outlet property="calendarNameField" destination="E1I-tu-3OF" id="43n-JC-CE2"/>
+            <outlet property="calendarNewScopeField" destination="HYK-cG-NOj" id="fM2-GR-Qdc"/>
+            <outlet property="calendarOrgField" destination="vpF-O7-lvf" id="ZMu-T3-6gU"/>
+            <outlet property="calendarRemarkField" destination="0zU-2p-l4e" id="ia9-f3-lRI"/>
+            <outlet property="calendarScopeField" destination="5RB-dp-23j" id="NOM-Ib-Knt"/>
+            <outlet property="calendarStatusSwitch" destination="GTC-NP-gGg" id="AON-0O-FAD"/>
+            <outlet property="calendarTypeField" destination="6Nq-Qx-KK4" id="ONT-gF-LlR"/>
+          </connections>
+        </tableViewController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="Kl7-oF-Qbs" userLabel="First Responder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="1648.8" y="97.601199400299862"/>
+    </scene>
+    <!--编辑内容-->
+    <scene sceneID="d6n-Ns-IYR">
+      <objects>
+        <viewController id="ADR-Nz-B0R" customClass="OOCalendarEditRemarkViewController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+          <view key="view" contentMode="scaleToFill" id="uZ4-K3-7u9">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+            <viewLayoutGuide key="safeArea" id="x7Q-Xj-laR"/>
+          </view>
+          <navigationItem key="navigationItem" title="编辑内容" id="8m9-cj-hJa">
+            <barButtonItem key="leftBarButtonItem" title="取消" landscapeImage="icon_off_grey" id="Nbx-21-hlf">
+              <connections>
+                <action selector="cancel:" destination="ADR-Nz-B0R" id="xBm-rt-txj"/>
+              </connections>
+            </barButtonItem>
+            <barButtonItem key="rightBarButtonItem" title="保存" id="LXv-Cs-Ybf">
+              <connections>
+                <action selector="save:" destination="ADR-Nz-B0R" id="Y1a-tK-EiQ"/>
+              </connections>
+            </barButtonItem>
+          </navigationItem>
+        </viewController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="KZu-Ft-RRO" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="3342" y="-716"/>
+    </scene>
+    <!--Navigation Controller-->
+    <scene sceneID="NvP-o5-zSv">
+      <objects>
+        <navigationController automaticallyAdjustsScrollViewInsets="NO" id="LoN-sU-f4i" customClass="ZLNavigationController" customModule="O2Platform" customModuleProvider="target" sceneMemberID="viewController">
+          <toolbarItems/>
+          <navigationItem key="navigationItem" id="57p-JL-s0t"/>
+          <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Pux-od-ZUE">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
+            <autoresizingMask key="autoresizingMask"/>
+          </navigationBar>
+          <nil name="viewControllers"/>
+          <connections>
+            <segue destination="ADR-Nz-B0R" kind="relationship" relationship="rootViewController" id="c9K-2a-rzE"/>
+          </connections>
+        </navigationController>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="irf-LL-qwe" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+      </objects>
+      <point key="canvasLocation" x="2622" y="-703"/>
+    </scene>
+  </scenes>
+  <resources>
+    <image name="check" width="23" height="20"/>
+    <image name="icon_arrow" width="22" height="22"/>
+    <image name="icon_chongfu" width="22" height="22"/>
+    <image name="icon_hdjr" width="22" height="22"/>
+    <image name="icon_off_grey" width="22" height="22"/>
+    <image name="icon_shijian" width="22" height="22"/>
+    <image name="icon_tixing" width="22" height="22"/>
+    <image name="icon_zengjia" width="22" height="22"/>
+  </resources>
 </document>

+ 4 - 6
o2ios/O2Platform/App/Cms-内容管理/c/CMSItemDetailViewController.swift

@@ -306,9 +306,8 @@ extension CMSItemDetailViewController: O2WKScriptMessageHandlerImplement {
         self.uploadAttachment(site, uploadURL: updloadURL!)
     }
     private func uploadAttachment(_ site:String,uploadURL url:String){
-        let vc = FileBSImagePickerViewController()
-        bs_presentImagePickerController(vc, animated: true,
-                                        select: { (asset: PHAsset) -> Void in
+        let vc = FileBSImagePickerViewController().bsImagePicker()
+        presentImagePicker(vc, select: { (asset: PHAsset) -> Void in
                                             // User selected an asset.
                                             // Do something with it, start upload perhaps?
         }, deselect: { (asset: PHAsset) -> Void in
@@ -509,9 +508,8 @@ extension CMSItemDetailViewController: O2WKScriptMessageHandlerImplement {
     
     
     private func replaceAttachment(_ site:String,_ attachmentId:String,replaceURL url:String){
-        let vc = FileBSImagePickerViewController()
-        bs_presentImagePickerController(vc, animated: true,
-                                        select: { (asset: PHAsset) -> Void in
+        let vc = FileBSImagePickerViewController().bsImagePicker()
+        presentImagePicker(vc, select: { (asset: PHAsset) -> Void in
                                             // User selected an asset.
                                             // Do something with it, start upload perhaps?
         }, deselect: { (asset: PHAsset) -> Void in

+ 47 - 28
o2ios/O2Platform/App/File-云盘/c/FileBSImagePickerViewController.swift

@@ -9,34 +9,53 @@
 import UIKit
 import BSImagePicker
 
-class FileBSImagePickerViewController: BSImagePickerViewController {
- 
-    var defaultmaxNumberOfSelections = 1
-    var defaultTakePhotos = true
-    override func viewDidLoad() {
-        super.viewDidLoad()
-        self.navigationBar.isTranslucent = false
-        self.navigationBar.barTintColor = navbar_barTint_color
-        self.navigationBar.tintColor = navbar_tint_color
-        self.navigationBar.titleTextAttributes = [NSAttributedString.Key.font:navbar_text_font,NSAttributedString.Key.foregroundColor:navbar_tint_color]
-        self.albumButton.setTitleColor(navbar_tint_color, for: .normal)
-        self.settings.maxNumberOfSelections = defaultmaxNumberOfSelections
-        self.settings.takePhotos = defaultTakePhotos
-        
-        
-        //隐藏返回按钮文字
-        let barItem = UIBarButtonItem.appearance()
-        let offset = UIOffset(horizontal: -200, vertical: 0)
-        barItem.setBackButtonTitlePositionAdjustment(offset, for: .default)
-        barItem.setTitleTextAttributes([NSAttributedString.Key.font:navbar_item_font,NSAttributedString.Key.foregroundColor:navbar_tint_color], for:UIControl.State())
-
-        // Do any additional setup after loading the view.
-    }
+struct FileBSImagePickerViewController {
     
-    override var preferredStatusBarStyle : UIStatusBarStyle {
-        return .lightContent
+    func bsImagePicker() -> BSImagePicker.ImagePickerController {
+        let picker = BSImagePicker.ImagePickerController()
+        picker.albumButton.setTitleColor(navbar_tint_color, for: .normal)
+        picker.settings.selection.max = 1
+        picker.settings.theme.selectionStyle = .checked
+        picker.settings.selection.unselectOnReachingMax = true
+        picker.navigationBar.isTranslucent = false
+        picker.navigationBar.barTintColor = navbar_barTint_color
+        picker.navigationBar.tintColor = navbar_tint_color
+        picker.navigationBar.titleTextAttributes = [NSAttributedString.Key.font:navbar_text_font,NSAttributedString.Key.foregroundColor:navbar_tint_color]
+        
+        return picker
     }
-    
-    
-
 }
+
+//class FileBSImagePickerViewController: BSImagePicker.ImagePickerController {
+//
+//    var defaultmaxNumberOfSelections = 1
+//    var defaultTakePhotos = true
+//    override func viewDidLoad() {
+//        super.viewDidLoad()
+//        self.navigationBar.isTranslucent = false
+//        self.navigationBar.barTintColor = navbar_barTint_color
+//        self.navigationBar.tintColor = navbar_tint_color
+//        self.navigationBar.titleTextAttributes = [NSAttributedString.Key.font:navbar_text_font,NSAttributedString.Key.foregroundColor:navbar_tint_color]
+//
+////        self.albumButton.setTitleColor(navbar_tint_color, for: .normal)
+////        self.settings.maxNumberOfSelections = defaultmaxNumberOfSelections
+////        self.settings.takePhotos = defaultTakePhotos
+//
+//
+//
+//        //隐藏返回按钮文字
+//        let barItem = UIBarButtonItem.appearance()
+//        let offset = UIOffset(horizontal: -200, vertical: 0)
+//        barItem.setBackButtonTitlePositionAdjustment(offset, for: .default)
+//        barItem.setTitleTextAttributes([NSAttributedString.Key.font:navbar_item_font,NSAttributedString.Key.foregroundColor:navbar_tint_color], for:UIControl.State())
+//
+//        // Do any additional setup after loading the view.
+//    }
+//
+//    override var preferredStatusBarStyle : UIStatusBarStyle {
+//        return .lightContent
+//    }
+//
+//
+//
+//}

+ 2 - 3
o2ios/O2Platform/App/File-云盘/c/MainFileViewController.swift

@@ -285,7 +285,6 @@ class MainFileViewController: UIViewController {
     }
     
     func uploadFile(){
-        let vc = FileBSImagePickerViewController()
         var url = ""
         if self.folderQueue.count == 0 {
             url = AppDelegate.o2Collect.generateURLWithAppContextKey(FileContext.fileContextKey, query: FileContext.fileUploadTopQuery, parameter: nil,coverted: true)!
@@ -293,8 +292,8 @@ class MainFileViewController: UIViewController {
             url = AppDelegate.o2Collect.generateURLWithAppContextKey(FileContext.fileContextKey, query: FileContext.fileUploadSubQuery, parameter: ["##id##":(self.folderQueue.last?.id!)! as AnyObject],coverted: true)!
         }
         url = url.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)!
-        bs_presentImagePickerController(vc, animated: true,
-                                        select: { (asset: PHAsset) -> Void in
+        let vc = FileBSImagePickerViewController().bsImagePicker()
+        presentImagePicker(vc, select: { (asset: PHAsset) -> Void in
                                             // User selected an asset.
                                             // Do something with it, start upload perhaps?
         }, deselect: { (asset: PHAsset) -> Void in

+ 560 - 0
o2ios/O2Platform/App/IM-聊天/IMChatViewController.swift

@@ -0,0 +1,560 @@
+//
+//  IMChatViewController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/8.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+import O2OA_Auth_SDK
+import BSImagePicker
+import Photos
+import Alamofire
+import AlamofireImage
+import SwiftyJSON
+import QuickLook
+
+class IMChatViewController: UIViewController {
+
+    // MARK: - IBOutlet
+    //消息列表
+    @IBOutlet weak var tableView: UITableView!
+    //消息输入框
+    @IBOutlet weak var messageInputView: UITextField!
+    //底部工具栏的高度约束
+    @IBOutlet weak var bottomBarHeightConstraint: NSLayoutConstraint!
+    //底部工具栏
+    @IBOutlet weak var bottomBar: UIView!
+
+    private let emojiBarHeight = 196
+    //表情窗口
+    private lazy var emojiBar: 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
+    }()
+    //语音录制按钮
+    private lazy var audioBtnView: IMChatAudioView = {
+        let view = Bundle.main.loadNibNamed("IMChatAudioView", owner: self, options: nil)?.first as! IMChatAudioView
+        view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: emojiBarHeight.toCGFloat)
+        view.delegate = self
+        return view
+    }()
+    //预览文件
+    private lazy var previewVC: CloudFilePreviewController = {
+        return CloudFilePreviewController()
+    }()
+
+    private lazy var viewModel: IMViewModel = {
+        return IMViewModel()
+    }()
+
+    // MARK: - properties
+    var conversation: IMConversationInfo? = nil
+    private var chatMessageList: [IMMessageInfo] = []
+    private var page = 1
+    private var isShowEmoji = false
+    private var isShowAudioView = false
+    private var bottomBarHeight = 64 //底部输入框 表情按钮 的高度
+    private let bottomToolbarHeight = 46 //底部工具栏 麦克风 相册 相机等按钮的位置
+
+
+    // MARK: - functions
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.tableView.delegate = self
+        self.tableView.dataSource = self
+        self.tableView.register(UINib(nibName: "IMChatMessageViewCell", bundle: nil), forCellReuseIdentifier: "IMChatMessageViewCell")
+        self.tableView.register(UINib(nibName: "IMChatMessageSendViewCell", bundle: nil), forCellReuseIdentifier: "IMChatMessageSendViewCell")
+        self.tableView.separatorStyle = .none
+        self.tableView.rowHeight = UITableView.automaticDimension
+        self.tableView.estimatedRowHeight = 144
+        self.messageInputView.delegate = self
+
+        //底部安全距离 老机型没有
+        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
+
+        //标题
+        if self.conversation?.type == o2_im_conversation_type_single {
+            if let c = self.conversation {
+                var person = ""
+                c.personList?.forEach({ (p) in
+                    if p != O2AuthSDK.shared.myInfo()?.distinguishedName {
+                        person = p
+                    }
+                })
+                if !person.isEmpty {
+                    self.title = person.split("@").first ?? ""
+                }
+            }
+        } else {
+            self.title = self.conversation?.title
+        }
+        //获取聊天数据
+        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)
+            }
+        }
+    }
+
+    //获取消息
+    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: "参数错误!!!")
+        }
+    }
+    //刷新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 sendLocationMessage(loc: O2LocationData) {
+        let body = IMMessageBodyInfo()
+        body.type = o2_im_msg_type_location
+        body.body = o2_im_msg_body_location
+        body.address = loc.address
+        body.addressDetail = loc.addressDetail
+        body.longitude = loc.longitude
+        body.latitude = loc.latitude
+        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()
+        //发送消息到服务器
+        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 chooseImage() {
+        let vc = FileBSImagePickerViewController().bsImagePicker()
+        vc.settings.fetch.assets.supportedMediaTypes = [.image]
+
+        presentImagePicker(vc, 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.uploadFileAndSendMsg(messageId: msgId, data: newData, fileName: fileName, type: o2_im_msg_type_image)
+                        }
+                        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
+    }
+
+    //发送消息前 先载入界面
+    private func prepareForSendFileMsg(tempMessage: IMMessageBodyInfo) -> String {
+        let message = IMMessageInfo()
+        let msgId = UUID().uuidString
+        message.body = tempMessage.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
+    }
+
+     
+
+    //上传图片 音频 等文件到服务器并发送消息
+    private func uploadFileAndSendMsg(messageId: String, data: Data, fileName: String, type: String) {
+        guard let cId = self.conversation?.id else {
+            return
+        }
+        self.viewModel.uploadFile(conversationId: cId, type: type, fileName: fileName, file: data).then { back in
+            DDLogDebug("上传文件成功")
+            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 = back.id
+            body?.fileExtension = back.fileExtension
+            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 {
+            //audio view 先关闭
+            self.isShowAudioView = false
+            self.audioBtnView.removeFromSuperview()
+            //开始添加emojiBar
+            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.isShowAudioView.toggle()
+        self.view.endEditing(true)
+        if self.isShowAudioView {
+            //emoji view 先关闭
+            self.isShowEmoji = false
+            self.emojiBar.removeFromSuperview()
+            //开始添加emojiBar
+            self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat + self.emojiBarHeight.toCGFloat
+            self.audioBtnView.translatesAutoresizingMaskIntoConstraints = false
+            self.bottomBar.addSubview(self.audioBtnView)
+            let top = NSLayoutConstraint(item: self.audioBtnView, attribute: .top, relatedBy: .equal, toItem: self.audioBtnView.superview!, attribute: .top, multiplier: 1, constant: CGFloat(self.bottomBarHeight))
+            let width = NSLayoutConstraint(item: self.audioBtnView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: SCREEN_WIDTH)
+            let height = NSLayoutConstraint(item: self.audioBtnView, 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.audioBtnView.removeFromSuperview()
+        }
+        self.view.layoutIfNeeded()
+    }
+
+    @IBAction func imgBtnClick(_ sender: UIButton) {
+        DDLogDebug("点击了图片按钮")
+        self.chooseImage()
+    }
+    @IBAction func cameraBtnClick(_ sender: UIButton) {
+        DDLogDebug("点击了相机按钮")
+        self.takePhoto(delegate: self)
+    }
+    @IBAction func locationBtnClick(_ sender: UIButton) {
+        DDLogDebug("点击了位置按钮")
+        let vc = IMLocationChooseController.openChooseLocation { (data) in
+            self.sendLocationMessage(loc: data)
+        }
+        self.navigationController?.pushViewController(vc, animated: false)
+    }
+
+
+}
+
+// MARK: - 录音delegate
+extension IMChatViewController: IMChatAudioViewDelegate {
+    func sendVoice(path: String, voice: Data, duration: String) {
+        let msg = IMMessageBodyInfo()
+        msg.fileTempPath = path
+        msg.body = o2_im_msg_body_audio
+        msg.type = o2_im_msg_type_audio
+        msg.audioDuration = duration
+        let msgId = self.prepareForSendFileMsg(tempMessage: msg)
+        let fileName = path.split("/").last ?? "MySound.ilbc"
+        DDLogDebug("音频文件:\(fileName)")
+        self.uploadFileAndSendMsg(messageId: msgId, data: voice, fileName: fileName, type: o2_im_msg_type_audio)
+    }
+}
+
+// MARK: - 拍照delegate
+extension IMChatViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
+
+    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
+        if let image = info[.editedImage] as? UIImage {
+            let fileName = "\(UUID().uuidString).png"
+            let newData = image.pngData()!
+            let localFilePath = self.storageLocalImage(imageData: newData, fileName: fileName)
+            let msgId = self.prepareForSendImageMsg(filePath: localFilePath)
+            self.uploadFileAndSendMsg(messageId: msgId, data: newData, fileName: fileName, type: o2_im_msg_type_image)
+        } else {
+            DDLogError("没有选择到图片!")
+        }
+        picker.dismiss(animated: true, completion: nil)
+//        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"
+//        }
+    }
+
+}
+
+// MARK: - 图片消息点击 delegate
+extension IMChatViewController: IMChatMessageDelegate {
+    
+    func openLocatinMap(info: IMMessageBodyInfo) {
+        let map = IMShowLocationViewController()
+        map.address = info.address
+        map.addressDetail = info.addressDetail
+        map.latitude = info.latitude
+        map.longitude = info.longitude
+        self.navigationController?.pushViewController(map, animated: false)
+    }
+    
+    func clickImageMessage(info: IMMessageBodyInfo) {
+        if let id = info.fileId {
+            self.showLoading()
+            var ext = info.fileExtension ?? "png"
+            if ext.isEmpty {
+                ext = "png"
+            }
+            O2IMFileManager.shared
+                .getFileLocalUrl(fileId: id, fileExtension: ext)
+                .always {
+                    self.hideLoading()
+                }.then { (path) in
+                    let currentURL = NSURL(fileURLWithPath: path.path)
+                    DDLogDebug(currentURL.description)
+                    DDLogDebug(path.path)
+                    if QLPreviewController.canPreview(currentURL) {
+                        self.previewVC.currentFileURLS.removeAll()
+                        self.previewVC.currentFileURLS.append(currentURL)
+                        self.previewVC.reloadData()
+                        self.pushVC(self.previewVC)
+                    } else {
+                        self.showError(title: "当前文件类型不支持预览!")
+                    }
+                }
+                .catch { (error) in
+                    DDLogError(error.localizedDescription)
+                    self.showError(title: "获取文件异常!")
+            }
+        } else if let temp = info.fileTempPath {
+            let currentURL = NSURL(fileURLWithPath: temp)
+            DDLogDebug(currentURL.description)
+            DDLogDebug(temp)
+            if QLPreviewController.canPreview(currentURL) {
+                self.previewVC.currentFileURLS.removeAll()
+                self.previewVC.currentFileURLS.append(currentURL)
+                self.previewVC.reloadData()
+                self.pushVC(self.previewVC)
+            } else {
+                self.showError(title: "当前文件类型不支持预览!")
+            }
+        }
+    }
+}
+
+// MARK: - 表情点击 delegate
+extension IMChatViewController: IMChatEmojiBarClickDelegate {
+    func clickEmoji(emoji: String) {
+        DDLogDebug("发送表情消息 \(emoji)")
+        self.sendEmojiMessage(emoji: emoji)
+    }
+}
+
+// MARK: - tableview delegate
+extension IMChatViewController: UITableViewDelegate, UITableViewDataSource {
+
+    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])
+                cell.delegate = self
+                return cell
+            }
+        } else {
+            if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageViewCell", for: indexPath) as? IMChatMessageViewCell {
+                cell.setContent(item: self.chatMessageList[indexPath.row])
+                cell.delegate = self
+                return cell
+            }
+        }
+        return UITableViewCell()
+    }
+
+    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("准备开始输入......")
+        closeOtherView()
+        return true
+    }
+
+    private func closeOtherView() {
+        self.isShowEmoji = false
+        self.isShowAudioView = false
+        self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
+        self.view.layoutIfNeeded()
+    }
+
+    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+        DDLogDebug("回车。。。。")
+        self.sendTextMessage()
+        return true
+    }
+}

+ 136 - 0
o2ios/O2Platform/App/IM-聊天/IMChatViewController.xib

@@ -0,0 +1,136 @@
+<?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" customClass="IMChatViewController" customModule="O2Platform" customModuleProvider="target">
+            <connections>
+                <outlet property="bottomBar" destination="sDg-us-Ed9" id="J1d-XZ-5Rt"/>
+                <outlet property="bottomBarHeightConstraint" destination="qiu-7O-AwO" id="LWR-Ov-DMW"/>
+                <outlet property="messageInputView" destination="8BW-XG-rBx" id="A8J-9I-MjT"/>
+                <outlet property="tableView" destination="ZIb-3p-hnq" id="heR-v3-iUh"/>
+                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sDg-us-Ed9">
+                    <rect key="frame" x="0.0" y="798" width="414" height="98"/>
+                    <subviews>
+                        <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="请输入消息..." textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8BW-XG-rBx">
+                            <rect key="frame" x="14" y="12" width="328" height="36"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="36" id="qe1-5v-UaD"/>
+                            </constraints>
+                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                            <textInputTraits key="textInputTraits" returnKeyType="send"/>
+                        </textField>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oTD-nU-xkE">
+                            <rect key="frame" x="366" y="12" width="36" height="36"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="36" id="AzT-Gm-fHl"/>
+                                <constraint firstAttribute="height" constant="36" id="PqN-1z-eCd"/>
+                            </constraints>
+                            <state key="normal" image="chat_emoji"/>
+                            <connections>
+                                <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="icon_yuyin"/>
+                                    <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="icon_tupian"/>
+                                    <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="icon_xiangji"/>
+                                    <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="icon_ditu"/>
+                                    <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>
+                <constraint firstItem="ZIb-3p-hnq" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="7kr-oh-NvU"/>
+                <constraint firstAttribute="trailing" secondItem="sDg-us-Ed9" secondAttribute="trailing" id="SXj-Vg-GIC"/>
+                <constraint firstAttribute="bottom" secondItem="sDg-us-Ed9" secondAttribute="bottom" id="ZjF-u3-yyV"/>
+                <constraint firstItem="ZIb-3p-hnq" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="d3C-Up-hv7"/>
+                <constraint firstItem="ZIb-3p-hnq" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="igh-CL-C1S"/>
+                <constraint firstItem="sDg-us-Ed9" firstAttribute="top" secondItem="ZIb-3p-hnq" secondAttribute="bottom" id="rTN-Zh-8i6"/>
+                <constraint firstItem="sDg-us-Ed9" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="rqK-P9-wyk"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
+            <point key="canvasLocation" x="131.8840579710145" y="138.61607142857142"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="chat_emoji" width="24" height="24"/>
+        <image name="icon_ditu" width="22" height="22"/>
+        <image name="icon_tupian" width="22" height="22"/>
+        <image name="icon_xiangji" width="22" height="22"/>
+        <image name="icon_yuyin" width="22" height="22"/>
+    </resources>
+</document>

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

@@ -0,0 +1,240 @@
+//
+//  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 - TAB_BAR_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] = []
+    private var instantMsgList: [InstantMessage] = []
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        self.navigationItem.rightBarButtonItems = [UIBarButtonItem(image: UIImage(named: "add"), style: .plain, target: self, action: #selector(addConversation))]
+        
+        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) {
+        getInstantMsgList()
+    }
+    
+    func getInstantMsgList() {
+        viewModel.getInstantMsgList().then { (list) in
+            self.instantMsgList = list
+            self.getConversationList()
+        }
+    }
+
+    func getConversationList() {
+        viewModel.myConversationList().then { (list) in
+            self.conversationList = list
+            var n = 0
+            if !self.conversationList.isEmpty {
+                for item in self.conversationList {
+                    if let number = item.unreadNumber {
+                        n += number
+                    }
+                }
+            }
+            DispatchQueue.main.async {
+                if self.conversationList.count > 0 || self.instantMsgList.count > 0{
+                    self.emptyView.isHidden = true
+                } else {
+                    self.emptyView.isHidden = false
+                }
+                self.tableview.reloadData()
+                self.refreshRedPoint(number: n)
+            }
+
+        }.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.getInstantMsgList()
+            }
+        } else {
+            DDLogError("不正确的消息类型。。。")
+        }
+    }
+
+
+    private func refreshRedPoint(number: Int) {
+        if number > 0 && number < 100 {
+            self.navigationController?.tabBarItem.badgeValue = "\(number)"
+        } else if number >= 100 {
+            self.navigationController?.tabBarItem.badgeValue = "99.."
+        }else {
+            self.navigationController?.tabBarItem.badgeValue = nil
+        }
+    }
+    
+    
+    @objc private func addConversation() {
+        self.showSheetAction(title: nil, message: nil, actions: [
+            UIAlertAction(title: "创建单聊", style: .default, handler: { (action) in
+                self.createSingleConversation()
+            }),
+            UIAlertAction(title: "创建群聊", style: .default, handler: { (action) in
+                self.createGroupConversation()
+            })
+        ])
+    }
+
+    private func createSingleConversation() {
+        self.showContactPicker(modes: [.person], callback: { (result) in
+            if let users = result.users, users.count > 0 {
+                self.viewModel.createConversation(type: o2_im_conversation_type_single, users: [users[0].distinguishedName!]).then { (con) in
+                    self.createConversationSuccess(conv: con)
+                }.catch { (err) in
+                    self.showError(title: "创建单聊失败, \(err.localizedDescription)")
+                }
+                
+            }
+        }, multiple: false)
+    }
+    
+    private func createGroupConversation() {
+        self.showContactPicker(modes: [.person], callback: { (result) in
+            if let users = result.users, users.count > 0 {
+                let array = users.map { (item) -> String in
+                    item.distinguishedName!
+                }
+                self.viewModel.createConversation(type: o2_im_conversation_type_group, users: array).then { (conv) in
+                    self.createConversationSuccess(conv: conv)
+                }.catch { (err) in
+                    self.showError(title: "创建群聊失败, \(err.localizedDescription)")
+                }
+            }
+        })
+    }
+    
+    //创建会话成功 打开聊天界面
+    private func createConversationSuccess(conv: IMConversationInfo) {
+        if !self.conversationList.contains(where: { (info) -> Bool in
+            return info.id == conv.id
+        }) {
+            self.conversationList.append(conv)
+            DispatchQueue.main.async {
+                self.tableview.reloadData()
+            }
+        }
+        let chatView = IMChatViewController()
+        chatView.conversation = conv
+        self.navigationController?.pushViewController(chatView, animated: true)
+    }
+
+}
+
+// MARK: - tableview delegate
+extension IMConversationListViewController: UITableViewDelegate, UITableViewDataSource {
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        if self.instantMsgList.count > 0 {
+            return self.conversationList.count + 1
+        }
+        return self.conversationList.count
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        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 {
+                cell.bindConversation(conversation: self.conversationList[indexPath.row])
+            }
+            return cell
+        }
+        return UITableViewCell()
+    }
+
+    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        return 64
+    }
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        DDLogDebug("点击了 row \(indexPath.row)")
+        if self.instantMsgList.count > 0 {
+            if indexPath.row == 0 {
+                let instantView = IMInstantMessageViewController()
+                instantView.instantMsgList = self.instantMsgList
+                self.navigationController?.pushViewController(instantView, animated: true)
+            }else {
+                gotoChatView(row: indexPath.row-1)
+            }
+        }else {
+            gotoChatView(row: indexPath.row)
+        }
+    }
+    
+    private func gotoChatView(row: Int) {
+        let chatView = IMChatViewController()
+        chatView.conversation = self.conversationList[row]
+        self.navigationController?.pushViewController(chatView, animated: true)
+    }
+
+}

+ 64 - 0
o2ios/O2Platform/App/IM-聊天/IMInstantMessageViewController.swift

@@ -0,0 +1,64 @@
+//
+//  IMInstantMessageViewController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/12.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+
+class IMInstantMessageViewController: UITableViewController {
+        
+    private lazy var viewModel: IMViewModel = {
+           return IMViewModel()
+       }()
+    
+    var instantMsgList: [InstantMessage] = []
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.title = "通知消息"
+        self.tableView.register(UINib(nibName: "IMChatMessageViewCell", bundle: nil), forCellReuseIdentifier: "IMChatMessageViewCell")
+        self.tableView.separatorStyle = .none
+        self.tableView.rowHeight = UITableView.automaticDimension
+        self.tableView.estimatedRowHeight = 144
+        self.tableView.backgroundColor = UIColor(hex: "#f3f3f3")
+       
+    }
+    
+    override func viewDidAppear(_ animated: Bool) {
+        self.scrollMessageToBottom()
+    }
+    
+    //刷新tableview 滚动到底部
+    private func scrollMessageToBottom() {
+        DispatchQueue.main.async {
+            if self.instantMsgList.count > 0 {
+                self.tableView.scrollToRow(at: IndexPath(row: self.instantMsgList.count-1, section: 0), at: .bottom, animated: true)
+            }
+        }
+    }
+
+    // MARK: - Table view data source
+
+    override func numberOfSections(in tableView: UITableView) -> Int {
+        return 1
+    }
+
+    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        return self.instantMsgList.count
+    }
+
+    
+    
+    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageViewCell", for: indexPath) as? IMChatMessageViewCell {
+            cell.setInstantContent(item: self.instantMsgList[indexPath.row])
+            return cell
+        }
+
+        return UITableViewCell()
+    }
+    
+}

+ 30 - 0
o2ios/O2Platform/App/IM-聊天/IMInstantMessageViewController.xib

@@ -0,0 +1,30 @@
+<?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" customClass="IMInstantMessageViewController" customModule="O2Platform" customModuleProvider="target">
+            <connections>
+                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableView opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" bouncesZoom="NO" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="i5M-Pr-FkT">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+            <viewLayoutGuide key="safeArea" id="vLr-E1-eTs"/>
+            <color key="sectionIndexBackgroundColor" red="0.95294117649999999" green="0.95294117649999999" blue="0.95294117649999999" alpha="1" colorSpace="calibratedRGB"/>
+            <connections>
+                <outlet property="dataSource" destination="-1" id="Tng-2m-Rnh"/>
+                <outlet property="delegate" destination="-1" id="9aC-8N-iBw"/>
+            </connections>
+            <point key="canvasLocation" x="132" y="123"/>
+        </tableView>
+    </objects>
+</document>

+ 141 - 0
o2ios/O2Platform/App/IM-聊天/IMLocationChooseController.swift

@@ -0,0 +1,141 @@
+//
+//  IMLocationChooseController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/18.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+
+typealias O2LocationChooseCallback = (_ result: O2LocationData) -> Void ///< 定义确认回调
+
+class IMLocationChooseController: UIViewController {
+    
+    static func openChooseLocation(callback: @escaping O2LocationChooseCallback) -> IMLocationChooseController {
+        let vc = IMLocationChooseController()
+        vc.callback = callback
+        return vc
+    }
+    
+    
+
+    @IBOutlet weak var mapContainerView: UIView!
+    @IBOutlet weak var addressLabel: UILabel!
+
+    var callback: O2LocationChooseCallback?
+
+    private var mapView: BMKMapView!
+    private var locService: BMKLocationManager!
+    private var searchAddress: BMKGeoCodeSearch!
+    private var annotation: BMKPointAnnotation!
+    private var result: O2LocationData?
+    
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.title = "选择位置"
+        self.navigationItem.backBarButtonItem = UIBarButtonItem(image: UIImage(named: "icon_fanhui"), style: .plain, target: nil, action: nil)
+        //发送按钮
+        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "发送", style: .plain, target: self, action: #selector(sendLocation))
+        self.showLoading()
+        self.addressLabel.text = "点击地图选择位置"
+        //初始化地图和定位
+        let containerFrame = self.mapContainerView.frame
+        mapView = BMKMapView(frame: CGRect(x: 0, y: 0, width: containerFrame.width, height: containerFrame.height))
+        mapView.zoomLevel = 17
+        mapView.showMapPoi = true
+        mapView.showIndoorMapPoi = true
+        self.mapContainerView.addSubview(mapView)
+        mapView.delegate = self
+        locService = BMKLocationManager()
+        locService.delegate = self
+        locService.startUpdatingLocation()
+        searchAddress = BMKGeoCodeSearch()
+        searchAddress.delegate = self
+
+
+    }
+
+    @objc private func sendLocation() {
+        guard let r =  self.result else {
+            self.showError(title: "请选择一个位置!")
+            return
+        }
+        self.callback?(r)
+        self.navigationController?.popViewController(animated: false)
+    }
+
+    deinit {
+        mapView.delegate = nil
+        locService.delegate = nil
+        locService.stopUpdatingLocation()
+        searchAddress.delegate = nil
+    }
+
+}
+
+extension IMLocationChooseController: BMKMapViewDelegate, BMKLocationManagerDelegate, BMKGeoCodeSearchDelegate {
+    //定位
+    func bmkLocationManager(_ manager: BMKLocationManager, didUpdate location: BMKLocation?, orError error: Error?) {
+        if let loc = location?.location {
+            DDLogDebug("定位到 当前位置,\(loc.coordinate.latitude),\(loc.coordinate.longitude)")
+            let user = BMKUserLocation()
+            user.location = loc
+            mapView.updateLocationData(user)
+            mapView.centerCoordinate = CLLocationCoordinate2D(latitude: loc.coordinate.latitude, longitude: loc.coordinate.longitude)
+
+            //定位完成停止定位
+            locService.stopUpdatingLocation()
+            self.hideLoading()
+        }
+    }
+
+    //位置搜索
+    func onGetReverseGeoCodeResult(_ searcher: BMKGeoCodeSearch!, result: BMKReverseGeoCodeSearchResult!, errorCode error: BMKSearchErrorCode) {
+        DDLogDebug("获取到地址: \(String(describing: result.address))")
+        self.addressLabel.text = result.address
+        //todo 地址和位置经纬度要保存起来
+        if self.result == nil {
+            self.result = O2LocationData()
+        }
+        self.result?.address = result.address
+        self.result?.addressDetail = result.sematicDescription
+        self.result?.latitude = result.location.latitude
+        self.result?.longitude = result.location.longitude
+    }
+
+    //地图
+    func mapView(_ mapView: BMKMapView!, onClickedMapPoi mapPoi: BMKMapPoi!) {
+        if annotation == nil {
+            annotation = BMKPointAnnotation()
+            annotation.coordinate = mapPoi.pt
+            mapView.addAnnotation(annotation)
+        } else {
+            annotation.coordinate = mapPoi.pt
+        }
+        //反向查询具体地址名称
+        let re = BMKReverseGeoCodeSearchOption()
+        re.location = mapPoi.pt
+        let flag = searchAddress.reverseGeoCode(re)
+        DDLogDebug("根据位置坐标,查询地址信息 \(flag)")
+    }
+
+    func mapView(_ mapView: BMKMapView!, onClickedMapBlank coordinate: CLLocationCoordinate2D) {
+        //单击
+        if annotation == nil {
+            annotation = BMKPointAnnotation()
+            annotation.coordinate = coordinate
+            mapView.addAnnotation(annotation)
+        } else {
+            annotation.coordinate = coordinate
+        }
+
+        //反向查询具体地址名称
+        let re = BMKReverseGeoCodeSearchOption()
+        re.location = coordinate
+        let flag = searchAddress.reverseGeoCode(re)
+        DDLogDebug("根据位置坐标,查询地址信息 \(flag)")
+    }
+}

+ 60 - 0
o2ios/O2Platform/App/IM-聊天/IMLocationChooseController.xib

@@ -0,0 +1,60 @@
+<?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" customClass="IMLocationChooseController" customModule="O2Platform" customModuleProvider="target">
+            <connections>
+                <outlet property="addressLabel" destination="Bse-Vb-OgC" id="t4D-if-zQn"/>
+                <outlet property="mapContainerView" destination="ov2-dx-k4M" id="Dxk-4I-raa"/>
+                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ov2-dx-k4M">
+                    <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Oab-w2-V0B">
+                    <rect key="frame" x="0.0" y="44" width="414" height="42"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bse-Vb-OgC">
+                            <rect key="frame" x="14" y="21" width="386" height="0.0"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                            <nil key="textColor"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                    </subviews>
+                    <color key="backgroundColor" white="1" alpha="0.75321061639999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="Bse-Vb-OgC" firstAttribute="leading" secondItem="Oab-w2-V0B" secondAttribute="leading" constant="14" id="UBV-MO-ane"/>
+                        <constraint firstAttribute="height" constant="42" id="Zpa-ic-A6h"/>
+                        <constraint firstAttribute="trailing" secondItem="Bse-Vb-OgC" secondAttribute="trailing" constant="14" id="qVr-Gq-nPT"/>
+                        <constraint firstItem="Bse-Vb-OgC" firstAttribute="centerY" secondItem="Oab-w2-V0B" secondAttribute="centerY" id="yT8-VV-L2g"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+            <constraints>
+                <constraint firstAttribute="bottom" secondItem="ov2-dx-k4M" secondAttribute="bottom" id="7JR-gm-naE"/>
+                <constraint firstItem="Oab-w2-V0B" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="9a1-DQ-JtV"/>
+                <constraint firstItem="ov2-dx-k4M" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="9tl-vM-Gzr"/>
+                <constraint firstItem="Oab-w2-V0B" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="VRS-7z-Ptd"/>
+                <constraint firstItem="ov2-dx-k4M" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="Wud-kq-CTF"/>
+                <constraint firstItem="Oab-w2-V0B" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="ZbU-x0-CbA"/>
+                <constraint firstItem="ov2-dx-k4M" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="d67-Y1-hbq"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
+            <point key="canvasLocation" x="124.6376811594203" y="137.94642857142856"/>
+        </view>
+    </objects>
+</document>

+ 51 - 0
o2ios/O2Platform/App/IM-聊天/IMShowLocationViewController.swift

@@ -0,0 +1,51 @@
+//
+//  IMShowLocationViewController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/18.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+
+class IMShowLocationViewController: UIViewController {
+
+    private var mapView: BMKMapView!
+    private var annotation: BMKPointAnnotation!
+    
+    var address: String?
+    var addressDetail: String?
+    var latitude: Double?
+    var longitude: Double?
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.title = address
+        mapView = BMKMapView(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH ,height: SCREEN_HEIGHT))
+        mapView.zoomLevel = 17
+        mapView.showMapPoi = true
+        mapView.showIndoorMapPoi = true
+        self.view.addSubview(mapView)
+       
+        guard let lat = latitude, let lo = longitude else {
+            self.showError(title: "没有传入正确的地址参数!")
+            return
+        }
+        //更新地图位置
+        let user = BMKUserLocation()
+        let loc = CLLocation(latitude: lat, longitude: lo)
+        user.location = loc
+        mapView.updateLocationData(user)
+        mapView.centerCoordinate = CLLocationCoordinate2D(latitude: loc.coordinate.latitude, longitude: loc.coordinate.longitude)
+        //设置位置点
+        annotation = BMKPointAnnotation()
+        annotation.coordinate = loc.coordinate
+        annotation.title = address
+        annotation.subtitle = addressDetail
+        mapView.addAnnotation(annotation)
+        
+        
+    }
+    
+ 
+}

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

@@ -0,0 +1,163 @@
+//
+//  IMViewModel.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Promises
+import CocoaLumberjack
+
+class IMViewModel: NSObject {
+    override init() {
+        super.init()
+    }
+
+
+    private let communicateAPI = OOMoyaProvider<CommunicateAPI>()
+}
+
+extension IMViewModel {
+    
+    //创建会话 @param type: single group
+    func createConversation(type: String, users: [String]) -> Promise<IMConversationInfo> {
+        let conversation = IMConversationInfo()
+        conversation.type = type
+        conversation.personList = users
+        return Promise  { fulfill, reject in
+            self.communicateAPI.request(.createConversation(conversation), completion: { result in
+                let response = OOResult<BaseModelClass<IMConversationInfo>>(result)
+                if response.isResultSuccess() {
+                    if let info = response.model?.data {
+                        fulfill(info)
+                    } else {
+                        reject(OOAppError.apiEmptyResultError)
+                    }
+                } else {
+                    reject(response.error!)
+                }
+            })
+        }
+        
+    }
+    
+    //阅读会话
+    func readConversation(conversationId: String?) {
+        guard let id = conversationId else {
+            DDLogError("阅读会话失败, 传入id为空")
+            return
+        }
+        self.communicateAPI.request(.readConversation(id), completion: {result in
+            let response = OOResult<BaseModelClass<OOCommonIdModel>>(result)
+            if response.isResultSuccess() {
+                DDLogDebug("阅读当前会话成功!")
+            }else {
+                DDLogError("阅读会话失败!")
+            }
+        })
+    }
+
+    //发送消息
+    func sendMsg(msg: IMMessageInfo) -> Promise<Bool> {
+        return Promise { fulfill, reject in
+            self.communicateAPI.request(.sendMsg(msg), completion: { result in
+                    let response = OOResult<BaseModelClass<OOCommonIdModel>>(result)
+                    if response.isResultSuccess() {
+                        if let _ = response.model?.data {
+                            fulfill(true)
+                        } else {
+                            reject(OOAppError.apiEmptyResultError)
+                        }
+                    } else {
+                        reject(response.error!)
+                    }
+                })
+        }
+    }
+    
+    //上传文件
+    func uploadFile(conversationId: String, type: String, fileName: String, file: Data) -> Promise<IMUploadBackModel> {
+       return Promise { fulfill, reject in
+           self.communicateAPI.request(.imUploadFile(conversationId, type, fileName, file), completion: { (result) in
+               let response = OOResult<BaseModelClass<IMUploadBackModel>>(result)
+               if response.isResultSuccess() {
+                   if let back = response.model?.data {
+                       fulfill(back)
+                   }else {
+                       reject(OOAppError.apiEmptyResultError)
+                   }
+               }else {
+                   reject(response.error!)
+               }
+           })
+       }
+   }
+   
+
+    //查询会话列表
+    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!)
+                }
+            })
+        }
+    }
+    //查询消息列表
+    func myMsgPageList(page: Int, conversationId: String) -> Promise<[IMMessageInfo]> {
+        return Promise { fulfill, reject in
+            self.communicateAPI.request(.msgListByPaging(page, 40, conversationId), completion: { result in
+                    let response = OOResult<BaseModelClass<[IMMessageInfo]>>(result)
+                    if response.isResultSuccess() {
+                        if let list = response.model?.data {
+                            //列表翻转
+                            let rList = list.sorted { (f, s) -> Bool in
+                                if let ft = f.createTime, let st = s.createTime {
+                                    return ft.toDate(formatter: "yyyy-MM-dd HH:mm:ss") < st.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+                                }
+                                return true
+                            }
+                            fulfill(rList)
+                        } else {
+                            reject(OOAppError.apiEmptyResultError)
+                        }
+                    } else {
+                        reject(response.error!)
+                    }
+                })
+        }
+    }
+    
+    func getInstantMsgList() -> Promise<[InstantMessage]> {
+        return Promise { fulfill, reject in
+            self.communicateAPI.request(.instantMessageList(100), completion: { result in
+                    let response = OOResult<BaseModelClass<[InstantMessage]>>(result)
+                    if response.isResultSuccess() {
+                        if let list = response.model?.data {
+                            //列表翻转
+                            let rList = list.sorted { (f, s) -> Bool in
+                                if let ft = f.createTime, let st = s.createTime {
+                                    return ft.toDate(formatter: "yyyy-MM-dd HH:mm:ss") < st.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+                                }
+                                return true
+                            }
+                            fulfill(rList)
+                        } else {
+                            reject(OOAppError.apiEmptyResultError)
+                        }
+                    } else {
+                        reject(response.error!)
+                    }
+                })
+        }
+    }
+}

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

@@ -0,0 +1,134 @@
+//
+//  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 IMMessageRequestForm: NSObject, DataModel {
+
+    @objc var conversationId: String?
+
+    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?
+    @objc var fileId: String? //文件id
+    @objc var fileExtension: String? //文件扩展
+    @objc var fileTempPath: String? //本地临时文件地址
+    @objc var audioDuration: String? // 音频文件时长
+    @objc var address: String? //type=location的时候位置信息
+    @objc var addressDetail: String?
+    var latitude: Double?//type=location的时候位置信息
+    var longitude: Double?//type=location的时候位置信息
+
+
+    required override init() { }
+
+    func mapping(mapper: HelpingMapper) {
+
+    }
+}
+
+class IMUploadBackModel: NSObject, DataModel {
+    public override var description: String {
+        return "IMUploadBackModel"
+    }
+    
+    @objc var id:String?
+    @objc var fileExtension: 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) {
+
+    }
+}
+
+//其他消息
+class InstantMessage: NSObject, DataModel {
+    @objc var id: String?
+    @objc var title: String?
+    @objc var type: String?
+    @objc var body: String?
+    @objc var consumerList: [String]?
+    @objc var person: String?
+    var consumed: Bool?
+    @objc var createTime: String?
+    @objc var updateTime: String?
+    
+    required override init() { }
+
+    func mapping(mapper: HelpingMapper) {
+
+    }
+
+}
+
+
+struct  O2LocationData {
+    var address: String?
+    var addressDetail: String?
+    var latitude: Double?
+    var longitude: Double?
+}

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

@@ -0,0 +1,102 @@
+//
+//  O2IM.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/4.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Foundation
+import Promises
+import CocoaLumberjack
+
+//心跳消息
+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"
+let o2_im_msg_type_audio = "audio"
+let o2_im_msg_type_location = "location"
+
+//消息body
+let o2_im_msg_body_image = "[图片]"
+let o2_im_msg_body_audio = "[语音]"
+let o2_im_msg_body_video = "[视频]"
+let o2_im_msg_body_location = "[位置]"
+
+
+//表情的字符串转化为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 ""
+}
+
+class O2IMFileManager {
+    static let shared: O2IMFileManager = {
+        return O2IMFileManager()
+    }()
+
+    private let communicateAPI = {
+        return OOMoyaProvider<CommunicateAPI>()
+    }()
+
+    private init() { }
+    //根据id下载文件,并返回文件的本地url
+    func getFileLocalUrl(fileId: String, fileExtension: String) -> Promise<URL> {
+        return Promise { fulfill, reject in
+            let url = self.localFilePath(fileId: fileId, ext: fileExtension)
+            if FileUtil.share.fileExist(filePath: url.path) {
+                fulfill(url)
+            } else {
+                self.communicateAPI.request(.imDownloadFullFile(fileId, fileExtension), completion: { result in
+                        switch result {
+                        case .success(_):
+                            DDLogError("下载成功。。。。。\(fileId)")
+                            fulfill(url)
+                            break
+                        case .failure(let err):
+                            DDLogError(err.localizedDescription)
+                            reject(err)
+                            break
+                        }
+                    })
+            }
+        }
+
+    }
+
+    func localFilePath(fileId: String, ext: String) -> URL {
+        return FileUtil.share.cacheDir().appendingPathComponent("\(fileId).\(ext)")
+    }
+    
+    //音频文件存储地址
+    func getRecorderPath(type: RecordType) -> String {
+        var recorderPath = FileUtil.share.cacheDir()
+        recorderPath.appendPathComponent("o2im")
+        //目录不存在就创建
+        DDLogDebug("开始创建目录\(recorderPath.path)")
+        FileUtil.share.createDirectory(path: recorderPath.path)
+        let now:Date = Date()
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "yyyy-MM-dd-hh-mm-ss"
+        let fileName = (type == RecordType.Caf) ? "\(dateFormatter.string(from: now))-MySound.caf" : "\(dateFormatter.string(from: now))-MySound.mp3"
+        recorderPath.appendPathComponent(fileName)
+        return recorderPath.path
+    }
+    
+}
+
+
+enum RecordType :String {
+    case Caf = "caf"
+    case MP3 = "mp3"
+}

+ 26 - 0
o2ios/O2Platform/App/IM-聊天/View/IMAudioView.swift

@@ -0,0 +1,26 @@
+//
+//  IMAudioView.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/17.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+
+class IMAudioView: UIView {
+    
+    static let IMAudioView_width: CGFloat = 92
+    static let IMAudioView_height: CGFloat = 36
+    
+    @IBOutlet weak var playImageView: UIImageView!
+    @IBOutlet weak var durationLabel: UILabel!
+    
+    
+    override func awakeFromNib() { }
+    
+    
+    func setDuration(duration: String) {
+        self.durationLabel.text = "\(duration)\""
+    }
+}

+ 57 - 0
o2ios/O2Platform/App/IM-聊天/View/IMAudioView.xib

@@ -0,0 +1,57 @@
+<?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"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="IMAudioView" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="92" height="36"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_audio_play_Normal" translatesAutoresizingMaskIntoConstraints="NO" id="a6h-yn-SMe">
+                    <rect key="frame" x="5" y="4" width="28" height="28"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="28" id="jsR-4F-M7B"/>
+                        <constraint firstAttribute="width" constant="28" id="kKV-bU-3mr"/>
+                    </constraints>
+                </imageView>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="60“" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Pe3-7R-eCP">
+                    <rect key="frame" x="53" y="9.5" width="29" height="17"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                    <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="Pe3-7R-eCP" firstAttribute="leading" secondItem="a6h-yn-SMe" secondAttribute="trailing" constant="20" id="6nk-nX-y34"/>
+                <constraint firstItem="a6h-yn-SMe" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="5" id="A7P-7Y-jsE"/>
+                <constraint firstItem="Pe3-7R-eCP" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="f3M-cW-QZa"/>
+                <constraint firstAttribute="trailing" secondItem="Pe3-7R-eCP" secondAttribute="trailing" constant="10" id="oO3-qw-7Xl"/>
+                <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="a6h-yn-SMe" secondAttribute="bottom" constant="4" id="qjF-vI-47S"/>
+                <constraint firstItem="a6h-yn-SMe" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="4" id="r1h-0b-1er"/>
+            </constraints>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <userDefinedRuntimeAttributes>
+                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                    <real key="value" value="5"/>
+                </userDefinedRuntimeAttribute>
+            </userDefinedRuntimeAttributes>
+            <connections>
+                <outlet property="durationLabel" destination="Pe3-7R-eCP" id="9pj-ZS-n3s"/>
+                <outlet property="playImageView" destination="a6h-yn-SMe" id="6N0-qd-tPk"/>
+            </connections>
+            <point key="canvasLocation" x="131.8840579710145" y="233.70535714285714"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="chat_audio_play_Normal" width="18" height="18"/>
+    </resources>
+</document>

+ 96 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatAudioView.swift

@@ -0,0 +1,96 @@
+//
+//  IMChatAudioView.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/17.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+
+
+protocol IMChatAudioViewDelegate {
+    func sendVoice(path: String, voice: Data, duration: String)
+}
+class IMChatAudioView: UIView {
+    
+    @IBOutlet weak var audioViewTitle: UILabel!
+    @IBOutlet weak var audioRecordBtn: UIButton!
+    
+    private var isCancel = false
+    
+    private lazy var recordManager: O2RecordVoiceManager = {
+        let rm = O2RecordVoiceManager()
+        rm.delegate = self
+       return rm
+    }()
+    
+    var delegate: IMChatAudioViewDelegate?
+    
+    override func awakeFromNib() {
+        audioRecordBtn.addTarget(self, action: #selector(startRecord), for: .touchDown)
+        audioRecordBtn.addTarget(self, action: #selector(cancelRecord), for: .touchDragExit)
+        audioRecordBtn.addTarget(self, action: #selector(finishRecord), for: .touchUpInside)
+    }
+     
+    
+    @objc private func startRecord() {
+        DDLogError("startRecord record...................")
+        self.isCancel = false
+        self.audioViewTitle.text = "上滑取消发送"
+        //开始录音
+        recordManager.stopRecordCompletion = {
+            DDLogDebug("结束录音!!")
+        }
+        recordManager.cancelledDeleteCompletion = {
+            DDLogDebug("取消录音!")
+        }
+        recordManager.startRecordingWithPath(O2IMFileManager.shared.getRecorderPath(type: .Caf)) {
+            DDLogDebug("开始录音!!!")
+        }
+    }
+    
+    @objc private func cancelRecord() {
+        DDLogError("cancelRecord record...................")
+        self.audioViewTitle.text = "按住说话"
+        self.isCancel = true
+        //取消录音
+        recordManager.cancelledDeleteWithCompletion()
+    }
+    @objc private func finishRecord() {
+        DDLogError("finish record...................")
+        self.audioViewTitle.text = "按住说话"
+        if !self.isCancel {
+            //录音结束
+            recordManager.finishRecordingCompletion()
+            if (recordManager.recordDuration! as NSString).floatValue < 1 {
+                DispatchQueue.main.async {
+                    self.chrysan.show(.error, message: "说话时间太短", hideDelay: 1)
+                }
+                return
+            }
+            let filePath = O2IMFileManager.shared.getRecorderPath(type: .MP3)
+            recordManager.convertCafToMp3(cafPath: recordManager.recordPath!, mp3Path: filePath)
+            let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
+            delegate?.sendVoice(path: filePath, voice: data, duration: recordManager.recordDuration!)
+        }
+    }
+}
+
+extension IMChatAudioView: O2RecordVoiceDelegate {
+    func beyondLimit(_ time: TimeInterval) {
+        //录音结束
+        recordManager.finishRecordingCompletion()
+        if (recordManager.recordDuration! as NSString).floatValue < 1 {
+            DispatchQueue.main.async {
+                self.chrysan.show(.error, message: "说话时间太短", hideDelay: 1)
+            }
+            return
+        }
+        let filePath = O2IMFileManager.shared.getRecorderPath(type: .MP3)
+        recordManager.convertCafToMp3(cafPath: recordManager.recordPath!, mp3Path: filePath)
+        let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
+        delegate?.sendVoice(path: filePath, voice: data, duration: recordManager.recordDuration!)
+    }
+}

+ 57 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatAudioView.xib

@@ -0,0 +1,57 @@
+<?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"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="IMChatAudioView" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="196"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wVh-0l-AFu">
+                    <rect key="frame" x="158" y="49" width="98" height="98"/>
+                    <color key="backgroundColor" red="0.95294117649999999" green="0.95294117649999999" blue="0.95294117649999999" alpha="1" colorSpace="calibratedRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="98" id="4e9-hO-ccV"/>
+                        <constraint firstAttribute="height" constant="98" id="wuH-tw-j4k"/>
+                    </constraints>
+                    <state key="normal" image="chat_mic"/>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                            <real key="value" value="49"/>
+                        </userDefinedRuntimeAttribute>
+                    </userDefinedRuntimeAttributes>
+                </button>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="按住说话" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ofc-kF-lNX">
+                    <rect key="frame" x="182" y="14" width="50" height="15"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                    <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+            <constraints>
+                <constraint firstItem="wVh-0l-AFu" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="6cB-Al-ASy"/>
+                <constraint firstItem="Ofc-kF-lNX" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="SHl-b2-znG"/>
+                <constraint firstItem="wVh-0l-AFu" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="tyc-Iy-wZR"/>
+                <constraint firstItem="Ofc-kF-lNX" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="14" id="wVW-4b-Vj0"/>
+            </constraints>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <connections>
+                <outlet property="audioRecordBtn" destination="wVh-0l-AFu" id="85j-KR-mnf"/>
+                <outlet property="audioViewTitle" destination="Ofc-kF-lNX" id="K6i-qG-CmP"/>
+            </connections>
+            <point key="canvasLocation" x="-113" y="-1"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="chat_mic" width="32" height="32"/>
+    </resources>
+</document>

+ 68 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiBarView.swift

@@ -0,0 +1,68 @@
+//
+//  IMChatEmojiBarView.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/11.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+
+protocol IMChatEmojiBarClickDelegate {
+    func clickEmoji(emoji: String)
+}
+
+class IMChatEmojiBarView: UIView {
+    
+    @IBOutlet weak var collectionView: UICollectionView!
+    
+    private let emojiList: [String] = {
+        var list: [String] = []
+        for i in 1...87 {
+            if i < 10 {
+                list.append("[0\(i)]")
+            }else {
+                list.append("[\(i)]")
+            }
+        }
+        return list
+    }()
+    
+    var delegate: IMChatEmojiBarClickDelegate? = nil
+    
+    override func awakeFromNib() {
+        collectionView.register(UINib(nibName: "IMChatEmojiItemCell", bundle: nil), forCellWithReuseIdentifier: "IMChatEmojiItemCell")
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        DDLogDebug("list size \(emojiList.count)")
+        
+    }
+}
+
+extension IMChatEmojiBarView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
+    
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return emojiList.count
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
+        return CGSize(width:SCREEN_WIDTH / 10, height: 42)
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        if let cell =  collectionView.dequeueReusableCell(withReuseIdentifier: "IMChatEmojiItemCell", for: indexPath) as? IMChatEmojiItemCell {
+            cell.setEmoji(emoji: self.emojiList[indexPath.row])
+            return cell
+        }
+        return UICollectionViewCell()
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        if delegate != nil {
+            delegate?.clickEmoji(emoji: self.emojiList[indexPath.row])
+        }
+        collectionView.deselectItem(at: indexPath, animated: false)
+    }
+    
+}

+ 43 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiBarView.xib

@@ -0,0 +1,43 @@
+<?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"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="IMChatEmojiBarView" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="256"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="Ard-Nz-Tlw">
+                    <rect key="frame" x="0.0" y="0.0" width="414" height="256"/>
+                    <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                    <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="9JR-h1-hg9">
+                        <size key="itemSize" width="128" height="128"/>
+                        <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                        <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                        <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                    </collectionViewFlowLayout>
+                </collectionView>
+            </subviews>
+            <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+            <constraints>
+                <constraint firstItem="Ard-Nz-Tlw" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="CAd-rq-tVD"/>
+                <constraint firstItem="Ard-Nz-Tlw" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="CaO-m5-kmB"/>
+                <constraint firstItem="Ard-Nz-Tlw" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="sfG-sX-ZzB"/>
+                <constraint firstItem="Ard-Nz-Tlw" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="wmb-YF-ekq"/>
+            </constraints>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <connections>
+                <outlet property="collectionView" destination="Ard-Nz-Tlw" id="8ST-jl-atl"/>
+            </connections>
+            <point key="canvasLocation" x="100.00000000000001" y="-9.375"/>
+        </view>
+    </objects>
+</document>

+ 25 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiItemCell.swift

@@ -0,0 +1,25 @@
+//
+//  IMChatEmojiItemCell.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/11.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+
+class IMChatEmojiItemCell: UICollectionViewCell {
+    @IBOutlet weak var emojiImage: UIImageView!
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        // Initialization code
+    }
+    
+    func setEmoji(emoji: String) {
+        let bundle = Bundle().o2EmojiBundle(anyClass: IMChatEmojiItemCell.self)
+        let path = o2ImEmojiPath(emojiBody: emoji)
+        self.emojiImage.image = UIImage(named: path, in: bundle, compatibleWith: nil)
+    }
+
+}

+ 41 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatEmojiItemCell.xib

@@ -0,0 +1,41 @@
+<?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"/>
+        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="IMChatEmojiItemCell" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="52" height="52"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                <rect key="frame" x="0.0" y="0.0" width="52" height="52"/>
+                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                <subviews>
+                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="JXV-Hl-6Xb">
+                        <rect key="frame" x="10" y="10" width="32" height="32"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="32" id="i41-s0-3eR"/>
+                            <constraint firstAttribute="width" constant="32" id="x6M-1W-tyM"/>
+                        </constraints>
+                    </imageView>
+                </subviews>
+            </view>
+            <constraints>
+                <constraint firstItem="JXV-Hl-6Xb" firstAttribute="centerX" secondItem="gTV-IL-0wX" secondAttribute="centerX" id="i60-Uy-DQL"/>
+                <constraint firstItem="JXV-Hl-6Xb" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="ssV-XP-TUi"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
+            <size key="customSize" width="52" height="62"/>
+            <connections>
+                <outlet property="emojiImage" destination="JXV-Hl-6Xb" id="b2g-I1-yjf"/>
+            </connections>
+            <point key="canvasLocation" x="146.37681159420291" y="156.02678571428569"/>
+        </collectionViewCell>
+    </objects>
+</document>

+ 243 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatMessageSendViewCell.swift

@@ -0,0 +1,243 @@
+//
+//  IMChatMessageSendViewCell.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/10.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+
+class IMChatMessageSendViewCell: UITableViewCell {
+    @IBOutlet weak var timeLabel: UILabel!
+    @IBOutlet weak var avatarImageView: UIImageView!
+    @IBOutlet weak var nameLabel: UILabel!
+    @IBOutlet weak var messageBackgroundView: UIView!
+    @IBOutlet weak var messageBgWidth: NSLayoutConstraint!
+    @IBOutlet weak var messageBgHeight: NSLayoutConstraint!
+    
+    //音频消息 主体view
+    private lazy var audioView: IMAudioView = {
+        let view = Bundle.main.loadNibNamed("IMAudioView", owner: self, options: nil)?.first as! IMAudioView
+        view.frame = CGRect(x: 0, y: 0, width: IMAudioView.IMAudioView_width, height: IMAudioView.IMAudioView_height)
+        return view
+    }()
+    
+    //位置消息 主体view
+    private lazy var locationView: IMLocationView = {
+        let view = Bundle.main.loadNibNamed("IMLocationView", owner: self, options: nil)?.first as! IMLocationView
+        view.frame = CGRect(x: 0, y: 0, width: IMLocationView.IMLocationViewWidth, height: IMLocationView.IMLocationViewHeight)
+        return view
+    }()
+    
+    var delegate: IMChatMessageDelegate?
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+    }
+
+    override func setSelected(_ selected: Bool, animated: Bool) {
+        super.setSelected(selected, animated: animated)
+    }
+    
+    func setContent(item: IMMessageInfo) {
+        //time
+        if let time = item.createTime {
+            let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            self.timeLabel.text = date.friendlyTime()
+        }
+        //name avatart
+        if let person = item.createPerson {
+            let urlstr = AppDelegate.o2Collect.generateURLWithAppContextKey(ContactContext.contactsContextKeyV2, query: ContactContext.personIconByNameQueryV2, parameter: ["##name##":person as AnyObject], generateTime: false)
+            if let u = URL(string: urlstr!) {
+                self.avatarImageView.hnk_setImageFromURL(u)
+            }else {
+                self.avatarImageView.image = UIImage(named: "icon_men")
+            }
+            //姓名
+            self.nameLabel.text = person.split("@").first ?? ""
+        }else {
+            self.avatarImageView.image = UIImage(named: "icon_men")
+            self.nameLabel.text = ""
+        }
+        self.messageBackgroundView.removeSubviews()
+        if let jsonBody = item.body, let body = parseJson(msg: jsonBody) {
+            if o2_im_msg_type_emoji == body.type {
+                emojiMsgRender(emoji: body.body!)
+            }else if o2_im_msg_type_image == body.type {
+                imageMsgRender(info: body)
+            }else if o2_im_msg_type_audio == body.type {
+                audioMsgRender(info: body)
+            } else if o2_im_msg_type_location == body.type {
+                locationMsgRender(info: body)
+            }  else {
+                textMsgRender(msg: body.body!)
+            }
+        }
+    }
+    
+    //位置消息
+    private func locationMsgRender(info: IMMessageBodyInfo) {
+        self.messageBgWidth.constant = IMLocationView.IMLocationViewWidth + 20
+        self.messageBgHeight.constant = IMLocationView.IMLocationViewHeight + 20
+        self.locationView.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(self.locationView)
+        self.locationView.setLocationAddress(address: info.address ?? "")
+        //点击打开地址
+        self.locationView.addTapGesture { (tap) in
+            //open map view//open map view
+            self.delegate?.openLocatinMap(info: info)
+        }
+        self.constraintWithContent(contentView: self.locationView)
+    }
+    
+    //音频消息
+    private func audioMsgRender(info: IMMessageBodyInfo) {
+        self.messageBgWidth.constant = IMAudioView.IMAudioView_width + 20
+        self.messageBgHeight.constant = IMAudioView.IMAudioView_height + 20
+        self.audioView.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(self.audioView)
+        self.audioView.setDuration(duration: info.audioDuration ?? "0")
+        self.audioView.addTapGesture { (tap) in
+            self.playAudio(info: info)
+        }
+        self.constraintWithContent(contentView: self.audioView)
+    }
+    
+    private func playAudio(info: IMMessageBodyInfo) {
+        if let fileId = info.fileId {
+            var ext = info.fileExtension ?? "mp3"
+            if ext.isEmpty {
+                ext = "mp3"
+            }
+            O2IMFileManager.shared.getFileLocalUrl(fileId: fileId, fileExtension: ext)
+                .then { (url) in
+                    do {
+                        let data = try Data(contentsOf: url)
+                        AudioPlayerManager.shared.managerAudioWithData(data, toplay: true)
+                    } catch {
+                        DDLogError(error.localizedDescription)
+                    }
+            }.catch { (e) in
+                DDLogError(e.localizedDescription)
+            }
+        } else if let filePath = info.fileTempPath {
+            do {
+                let data = try Data(contentsOf: URL(fileURLWithPath: filePath))
+                AudioPlayerManager.shared.managerAudioWithData(data, toplay: true)
+            } catch {
+                DDLogError(error.localizedDescription)
+            }
+        }
+    }
+    
+    private func constraintWithContent(contentView: UIView) {
+        let top = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: contentView.superview!, attribute: .top, multiplier: 1, constant: 10)
+        let bottom = NSLayoutConstraint(item: contentView.superview!, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: 10)
+        let left = NSLayoutConstraint(item: contentView, attribute: .leading, relatedBy: .equal, toItem: contentView.superview!, attribute: .leading, multiplier: 1, constant: 10)
+        let right = NSLayoutConstraint(item: contentView.superview!, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 10)
+        NSLayoutConstraint.activate([top, bottom, left, right])
+    }
+    
+    //图片消息
+    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)
+        imageView.addTapGesture { (tap) in
+            self.delegate?.clickImageMessage(info: info)
+        }
+        self.constraintWithContent(contentView: imageView)
+    }
+    
+    private func emojiMsgRender(emoji: String) {
+        let emojiSize = 36
+        let width = CGFloat(emojiSize + 20)
+        let height = CGFloat(emojiSize + 20)
+        self.messageBgWidth.constant = width
+        self.messageBgHeight.constant = height
+        //背景图片
+        let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
+        let insets = UIEdgeInsets(top: 28, left: 5, bottom: 5, right: 10); // 上、左、下、右
+        var bubble = UIImage(named: "chat_bubble_outgoing")
+        bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
+        bgImg.image = bubble
+        self.messageBackgroundView.addSubview(bgImg)
+        //表情图
+        let emojiImage = UIImageView(frame: CGRect(x: 0, y: 0, width: emojiSize, height: emojiSize))
+        let bundle = Bundle().o2EmojiBundle(anyClass: IMChatMessageSendViewCell.self)
+        let path = o2ImEmojiPath(emojiBody: emoji)
+        emojiImage.image = UIImage(named: path, in: bundle, compatibleWith: nil)
+        emojiImage.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(emojiImage)
+        self.constraintWithContent(contentView: emojiImage)
+    }
+    
+    private func textMsgRender(msg: String) {
+        let size = calTextSize(str: msg)
+        self.messageBgWidth.constant = size.width + 20
+        self.messageBgHeight.constant = size.height + 20
+        //背景图片
+        let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: size.width + 20, height: size.height + 20))
+        let insets = UIEdgeInsets(top: 28, left: 5, bottom: 5, right: 10); // 上、左、下、右
+        var bubble = UIImage(named: "chat_bubble_outgoing")
+        bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
+        bgImg.image = bubble
+        self.messageBackgroundView.addSubview(bgImg)
+        //文字
+        let label = generateMessagelabel(str: msg, size: size)
+        label.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(label)
+        let top = NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: label.superview!, attribute: .top, multiplier: 1, constant: 10)
+        let left = NSLayoutConstraint(item: label, attribute: .leading, relatedBy: .equal, toItem: label.superview!, attribute: .leading, multiplier: 1, constant: 10)
+        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
+        label.font = UIFont.systemFont(ofSize: 16)
+        label.numberOfLines = 0
+        label.lineBreakMode = .byCharWrapping
+        label.preferredMaxLayoutWidth = size.width
+        return label
+    }
+    
+    
+    private func calTextSize(str: String) -> CGSize {
+        let size = CGSize(width: 176, 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)
+    }
+    
+}

+ 84 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatMessageSendViewCell.xib

@@ -0,0 +1,84 @@
+<?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="129" id="KGk-i7-Jjw" customClass="IMChatMessageSendViewCell" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="129"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" ambiguous="YES" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="129"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="06-09 13:02" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="k0L-ig-bhB">
+                        <rect key="frame" x="14" y="5" width="292" height="18"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="18" id="MJ9-1n-RP4"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dRS-Ex-V2s">
+                        <rect key="frame" x="258" y="31" width="48" height="48"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="48" id="ALp-AJ-k89"/>
+                            <constraint firstAttribute="height" constant="48" id="U0b-CA-lXO"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="24"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </imageView>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="姓名" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="O0d-aO-DEf">
+                        <rect key="frame" x="219" y="31" width="29" height="24"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="24" id="hV4-hf-Q8a"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <nil key="textColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="73U-Yu-hhb">
+                        <rect key="frame" x="72" y="63" width="176" height="42"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="42" id="9m9-a5-elu"/>
+                            <constraint firstAttribute="width" constant="176" id="B2b-ep-gRb"/>
+                        </constraints>
+                    </view>
+                </subviews>
+                <color key="backgroundColor" red="0.95294117649999999" green="0.95294117649999999" blue="0.95294117649999999" alpha="1" colorSpace="calibratedRGB"/>
+                <constraints>
+                    <constraint firstItem="k0L-ig-bhB" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="5" id="59J-ml-PYh"/>
+                    <constraint firstItem="73U-Yu-hhb" firstAttribute="top" secondItem="O0d-aO-DEf" secondAttribute="bottom" constant="8" id="6MU-oN-E2m"/>
+                    <constraint firstItem="k0L-ig-bhB" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="6QF-aq-QM6"/>
+                    <constraint firstItem="dRS-Ex-V2s" firstAttribute="top" secondItem="k0L-ig-bhB" secondAttribute="bottom" constant="8" id="JfT-ce-huE"/>
+                    <constraint firstItem="dRS-Ex-V2s" firstAttribute="leading" secondItem="73U-Yu-hhb" secondAttribute="trailing" constant="10" id="Njy-Bc-KtC"/>
+                    <constraint firstItem="O0d-aO-DEf" firstAttribute="top" secondItem="k0L-ig-bhB" secondAttribute="bottom" constant="8" id="VFs-xs-kta"/>
+                    <constraint firstAttribute="trailing" secondItem="dRS-Ex-V2s" secondAttribute="trailing" constant="14" id="gmx-Y3-81p"/>
+                    <constraint firstAttribute="bottomMargin" secondItem="73U-Yu-hhb" secondAttribute="bottom" constant="10" id="j9W-5A-2om"/>
+                    <constraint firstItem="dRS-Ex-V2s" firstAttribute="leading" secondItem="O0d-aO-DEf" secondAttribute="trailing" constant="10" id="ngR-6P-5QW"/>
+                    <constraint firstAttribute="trailing" secondItem="k0L-ig-bhB" secondAttribute="trailing" constant="14" id="y21-uR-MhX"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
+            <connections>
+                <outlet property="avatarImageView" destination="dRS-Ex-V2s" id="Els-ei-27g"/>
+                <outlet property="messageBackgroundView" destination="73U-Yu-hhb" id="JOP-eY-itl"/>
+                <outlet property="messageBgHeight" destination="9m9-a5-elu" id="8Ly-ju-XTf"/>
+                <outlet property="messageBgWidth" destination="B2b-ep-gRb" id="FSo-Zq-jds"/>
+                <outlet property="nameLabel" destination="O0d-aO-DEf" id="Mqt-5X-zmf"/>
+                <outlet property="timeLabel" destination="k0L-ig-bhB" id="ZJg-EA-Jw1"/>
+            </connections>
+            <point key="canvasLocation" x="57.971014492753625" y="111.49553571428571"/>
+        </tableViewCell>
+    </objects>
+</document>

+ 302 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatMessageViewCell.swift

@@ -0,0 +1,302 @@
+//
+//  IMChatMessageViewCell.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/8.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+
+protocol IMChatMessageDelegate {
+    func clickImageMessage(info: IMMessageBodyInfo)
+    func openLocatinMap(info: IMMessageBodyInfo)
+}
+
+class IMChatMessageViewCell: UITableViewCell {
+
+    @IBOutlet weak var avatarImage: UIImageView!
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var timeLabel: UILabel!
+    @IBOutlet weak var messageBackgroundView: UIView!
+    @IBOutlet weak var messageBackgroundWidth: NSLayoutConstraint!
+    @IBOutlet weak var messageBackgroundHeight: NSLayoutConstraint!
+    private let messageWidth = 176
+
+    private lazy var audioView: IMAudioView = {
+        let view = Bundle.main.loadNibNamed("IMAudioView", owner: self, options: nil)?.first as! IMAudioView
+        view.frame = CGRect(x: 0, y: 0, width: IMAudioView.IMAudioView_width, height: IMAudioView.IMAudioView_height)
+        return view
+    }()
+
+    //位置消息 主体view
+    private lazy var locationView: IMLocationView = {
+        let view = Bundle.main.loadNibNamed("IMLocationView", owner: self, options: nil)?.first as! IMLocationView
+        view.frame = CGRect(x: 0, y: 0, width: IMLocationView.IMLocationViewWidth, height: IMLocationView.IMLocationViewHeight)
+        return view
+    }()
+
+    var delegate: IMChatMessageDelegate?
+
+    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 {
+            let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            self.timeLabel.text = date.friendlyTime()
+        }
+        self.messageBackgroundView.removeSubviews()
+        if let msg = item.title {
+            textMsgRender(msg: msg)
+        }
+        if let type = item.type {
+            if type.starts(with: "task_") {
+                self.avatarImage.image = UIImage(named: "icon_daiban")
+                self.titleLabel.text = "待办消息"
+            } else if type.starts(with: "taskCompleted_") {
+                self.avatarImage.image = UIImage(named: "icon_taskcompleted")
+                self.titleLabel.text = "已办消息"
+            } else if type.starts(with: "read_") {
+                self.avatarImage.image = UIImage(named: "icon_read")
+                self.titleLabel.text = "待阅消息"
+            } 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_") {
+                self.avatarImage.image = UIImage(named: "icon_daiban")
+                self.titleLabel.text = "工作消息"
+            } else if type.starts(with: "meeting_") {
+                self.avatarImage.image = UIImage(named: "icon_meeting")
+                self.titleLabel.text = "会议消息"
+            } else if type.starts(with: "attachment_") {
+                self.avatarImage.image = UIImage(named: "icon_yunpan")
+                self.titleLabel.text = "云盘消息"
+            } else if type.starts(with: "calendar_") {
+                self.avatarImage.image = UIImage(named: "icon_calendar")
+                self.titleLabel.text = "日历消息"
+            } else if type.starts(with: "cms_") {
+                self.avatarImage.image = UIImage(named: "icon_cms")
+                self.titleLabel.text = "信息中心消息"
+            } else if type.starts(with: "bbs_") {
+                self.avatarImage.image = UIImage(named: "icon_bbs")
+                self.titleLabel.text = "论坛消息"
+            } else if type.starts(with: "mind_") {
+                self.avatarImage.image = UIImage(named: "icon_mindMap")
+                self.titleLabel.text = "脑图消息"
+            } else {
+                self.avatarImage.image = UIImage(named: "icon_email")
+                self.titleLabel.text = "其他消息"
+            }
+        }
+    }
+
+    //聊天消息
+    func setContent(item: IMMessageInfo) {
+        //time
+        if let time = item.createTime {
+            let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            self.timeLabel.text = date.friendlyTime()
+        }
+        //name avatart
+        if let person = item.createPerson {
+            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 {
+                self.avatarImage.image = UIImage(named: "icon_men")
+            }
+            //姓名
+            self.titleLabel.text = person.split("@").first ?? ""
+        } else {
+            self.avatarImage.image = UIImage(named: "icon_men")
+            self.titleLabel.text = ""
+        }
+        self.messageBackgroundView.removeSubviews()
+        if let jsonBody = item.body, let body = parseJson(msg: jsonBody) {
+            if body.type == o2_im_msg_type_emoji {
+                emojiMsgRender(emoji: body.body!)
+            } else if body.type == o2_im_msg_type_image {
+                imageMsgRender(info: body)
+            } else if o2_im_msg_type_audio == body.type {
+                audioMsgRender(info: body)
+            } else if o2_im_msg_type_location == body.type {
+                locationMsgRender(info: body)
+            } else {
+                textMsgRender(msg: body.body!)
+            }
+        }
+    }
+
+    //位置消息
+    private func locationMsgRender(info: IMMessageBodyInfo) {
+        self.messageBackgroundWidth.constant = IMLocationView.IMLocationViewWidth + 20
+        self.messageBackgroundHeight.constant = IMLocationView.IMLocationViewHeight + 20
+        self.locationView.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(self.locationView)
+        self.locationView.setLocationAddress(address: info.address ?? "")
+        //点击打开地址
+        self.locationView.addTapGesture { (tap) in
+            //open map view
+            self.delegate?.openLocatinMap(info: info)
+        }
+        self.constraintWithContent(contentView: self.locationView)
+    }
+
+    //音频消息
+    private func audioMsgRender(info: IMMessageBodyInfo) {
+        self.messageBackgroundWidth.constant = IMAudioView.IMAudioView_width + 20
+        self.messageBackgroundHeight.constant = IMAudioView.IMAudioView_height + 20
+        self.audioView.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(self.audioView)
+        self.audioView.setDuration(duration: info.audioDuration ?? "0")
+        self.audioView.addTapGesture { (tap) in
+            self.playAudio(info: info)
+        }
+        self.constraintWithContent(contentView: self.audioView)
+    }
+
+    private func playAudio(info: IMMessageBodyInfo) {
+        if let fileId = info.fileId {
+            var ext = info.fileExtension ?? "mp3"
+            if ext.isEmpty {
+                ext = "mp3"
+            }
+            O2IMFileManager.shared.getFileLocalUrl(fileId: fileId, fileExtension: ext)
+                .then { (url) in
+                    do {
+                        let data = try Data(contentsOf: url)
+                        AudioPlayerManager.shared.managerAudioWithData(data, toplay: true)
+                    } catch {
+                        DDLogError(error.localizedDescription)
+                    }
+                }.catch { (e) in
+                    DDLogError(e.localizedDescription)
+            }
+        } else if let filePath = info.fileTempPath {
+            do {
+                let data = try Data(contentsOf: URL(fileURLWithPath: filePath))
+                AudioPlayerManager.shared.managerAudioWithData(data, toplay: true)
+            } catch {
+                DDLogError(error.localizedDescription)
+            }
+        }
+    }
+
+    private func constraintWithContent(contentView: UIView) {
+        let top = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: contentView.superview!, attribute: .top, multiplier: 1, constant: 10)
+        let bottom = NSLayoutConstraint(item: contentView.superview!, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: 10)
+        let left = NSLayoutConstraint(item: contentView, attribute: .leading, relatedBy: .equal, toItem: contentView.superview!, attribute: .leading, multiplier: 1, constant: 10)
+        let right = NSLayoutConstraint(item: contentView.superview!, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 10)
+        NSLayoutConstraint.activate([top, bottom, left, right])
+    }
+
+    //图片消息
+    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)
+        imageView.addTapGesture { (tap) in
+            self.delegate?.clickImageMessage(info: info)
+        }
+        self.constraintWithContent(contentView: imageView)
+
+    }
+
+    private func emojiMsgRender(emoji: String) {
+        let emojiSize = 36
+        let width = CGFloat(emojiSize + 20)
+        let height = CGFloat(emojiSize + 20)
+        self.messageBackgroundWidth.constant = width
+        self.messageBackgroundHeight.constant = height
+        //背景图片
+        let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
+        let insets = UIEdgeInsets(top: 28, left: 10, bottom: 5, right: 5); // 上、左、下、右
+        var bubble = UIImage(named: "chat_bubble_incomming")
+        bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
+        bgImg.image = bubble
+        self.messageBackgroundView.addSubview(bgImg)
+        //表情图
+        let emojiImage = UIImageView(frame: CGRect(x: 0, y: 0, width: emojiSize, height: emojiSize))
+        let bundle = Bundle().o2EmojiBundle(anyClass: IMChatMessageViewCell.self)
+        let path = o2ImEmojiPath(emojiBody: emoji)
+        emojiImage.image = UIImage(named: path, in: bundle, compatibleWith: nil)
+        emojiImage.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(emojiImage)
+        self.constraintWithContent(contentView: emojiImage)
+    }
+
+    private func textMsgRender(msg: String) {
+        let size = calTextSize(str: msg)
+        self.messageBackgroundWidth.constant = size.width + 20
+        self.messageBackgroundHeight.constant = size.height + 20
+        //背景图片
+        let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: size.width + 20, height: size.height + 20))
+        let insets = UIEdgeInsets(top: 28, left: 10, bottom: 5, right: 5); // 上、左、下、右
+        var bubble = UIImage(named: "chat_bubble_incomming")
+        bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
+        bgImg.image = bubble
+        self.messageBackgroundView.addSubview(bgImg)
+        //文字
+        let label = generateMessagelabel(str: msg, size: size)
+        label.translatesAutoresizingMaskIntoConstraints = false
+        self.messageBackgroundView.addSubview(label)
+        let top = NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: label.superview!, attribute: .top, multiplier: 1, constant: 10)
+        let left = NSLayoutConstraint(item: label, attribute: .leading, relatedBy: .equal, toItem: label.superview!, attribute: .leading, multiplier: 1, constant: 10)
+        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
+        label.font = UIFont.systemFont(ofSize: 16)
+        label.numberOfLines = 0
+        label.lineBreakMode = .byCharWrapping
+        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)
+    }
+}

+ 84 - 0
o2ios/O2Platform/App/IM-聊天/View/IMChatMessageViewCell.xib

@@ -0,0 +1,84 @@
+<?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="132" id="KGk-i7-Jjw" customClass="IMChatMessageViewCell" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="132"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" ambiguous="YES" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="132"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Mov-YP-dlA">
+                        <rect key="frame" x="14" y="31" width="48" height="48"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="48" id="gOa-23-wjh"/>
+                            <constraint firstAttribute="width" constant="48" id="hMb-yE-x70"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="24"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </imageView>
+                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="06-09 13:02" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fy3-Pu-FHB">
+                        <rect key="frame" x="14" y="5" width="292" height="18"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="18" id="c57-b5-RQY"/>
+                        </constraints>
+                        <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="2r2-Sl-HFm">
+                        <rect key="frame" x="72" y="31" width="29" height="24"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="24" id="4T7-qw-JEB"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                        <nil key="textColor"/>
+                        <nil key="highlightedColor"/>
+                    </label>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jxc-0S-MrS">
+                        <rect key="frame" x="72" y="63" width="176" height="42"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="176" id="0aZ-iT-9wn"/>
+                            <constraint firstAttribute="height" constant="42" id="ah6-qa-1tp"/>
+                        </constraints>
+                    </view>
+                </subviews>
+                <color key="backgroundColor" red="0.95294117649999999" green="0.95294117649999999" blue="0.95294117649999999" alpha="1" colorSpace="calibratedRGB"/>
+                <constraints>
+                    <constraint firstItem="Mov-YP-dlA" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="0dz-GG-NKV"/>
+                    <constraint firstItem="fy3-Pu-FHB" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="14" id="33C-sl-5B1"/>
+                    <constraint firstItem="jxc-0S-MrS" firstAttribute="leading" secondItem="Mov-YP-dlA" secondAttribute="trailing" constant="10" id="3AB-04-3Ot"/>
+                    <constraint firstAttribute="trailing" secondItem="fy3-Pu-FHB" secondAttribute="trailing" constant="14" id="AQO-Yx-K4D"/>
+                    <constraint firstItem="Mov-YP-dlA" firstAttribute="top" secondItem="fy3-Pu-FHB" secondAttribute="bottom" constant="8" id="Faw-qG-7Fy"/>
+                    <constraint firstItem="2r2-Sl-HFm" firstAttribute="top" secondItem="fy3-Pu-FHB" secondAttribute="bottom" constant="8" id="GtC-yx-sjT"/>
+                    <constraint firstItem="2r2-Sl-HFm" firstAttribute="leading" secondItem="Mov-YP-dlA" secondAttribute="trailing" constant="10" id="JYE-0i-s5S"/>
+                    <constraint firstAttribute="bottomMargin" secondItem="jxc-0S-MrS" secondAttribute="bottom" constant="10" id="Tpo-I1-lKY"/>
+                    <constraint firstItem="fy3-Pu-FHB" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="5" id="VVF-dB-vnY"/>
+                    <constraint firstItem="jxc-0S-MrS" firstAttribute="top" secondItem="2r2-Sl-HFm" secondAttribute="bottom" constant="8" id="gYS-LW-7T4"/>
+                </constraints>
+            </tableViewCellContentView>
+            <viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
+            <connections>
+                <outlet property="avatarImage" destination="Mov-YP-dlA" id="6a1-n4-fXG"/>
+                <outlet property="messageBackgroundHeight" destination="ah6-qa-1tp" id="hJ4-Xt-3Op"/>
+                <outlet property="messageBackgroundView" destination="jxc-0S-MrS" id="qTW-TG-fpN"/>
+                <outlet property="messageBackgroundWidth" destination="0aZ-iT-9wn" id="5UI-71-ADV"/>
+                <outlet property="timeLabel" destination="fy3-Pu-FHB" id="gvR-ts-fTh"/>
+                <outlet property="titleLabel" destination="2r2-Sl-HFm" id="kIP-0d-kYX"/>
+            </connections>
+            <point key="canvasLocation" x="131.8840579710145" y="94.419642857142847"/>
+        </tableViewCell>
+    </objects>
+</document>

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

@@ -0,0 +1,118 @@
+//
+//  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 unreadNumberLabel: UILabel!
+    @IBOutlet weak var emojiImg: UIImageView!
+    
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+    }
+
+    override func setSelected(_ selected: Bool, animated: Bool) {
+        super.setSelected(selected, animated: animated)
+    }
+    
+    
+    func setInstantContent(item: InstantMessage) {
+        self.avatarImg.image = UIImage(named: "icon_email")
+        self.nameLabel.text = "通知消息"
+        self.messageLabel.isHidden = false
+        self.messageLabel.text = item.title
+        if let time = item.createTime {
+            let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            self.timeLabel.text = date.friendlyTime()
+        }
+        self.emojiImg.isHidden = true
+        self.unreadNumberLabel.isHidden = true
+    }
+
+    
+    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)
+                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
+            self.avatarImg.image = UIImage(named: "group_default")
+        }
+        //time
+        if let time = conversation.lastMessage?.createTime {
+            let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
+            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 || body.type == o2_im_msg_type_image
+                || body.type == o2_im_msg_type_audio || body.type == o2_im_msg_type_location {
+                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
+                let bundle = Bundle().o2EmojiBundle(anyClass: IMConversationItemCell.self)
+                let path = o2ImEmojiPath(emojiBody: body.body!)
+                self.emojiImg.image = UIImage(named: path, in: bundle, compatibleWith: nil)
+            } else {
+                self.messageLabel.isHidden = true
+                self.emojiImg.isHidden = true
+            }
+        }
+        //unread number
+        let number = conversation.unreadNumber ?? 0
+        if number > 0 && number < 100 {
+            self.unreadNumberLabel.text = "\(number)"
+            self.unreadNumberLabel.isHidden = false
+        }else if number >= 100 {
+            self.unreadNumberLabel.text = "99.."
+            self.unreadNumberLabel.isHidden = false
+        }else {
+            self.unreadNumberLabel.isHidden = true
+        }
+        
+    }
+    
+    private func parseJson(msg: String) -> IMMessageBodyInfo? {
+        return IMMessageBodyInfo.deserialize(from: msg)
+    }
+    
+    
+    
+}

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

@@ -0,0 +1,117 @@
+<?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" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bOp-mm-qCN">
+                        <rect key="frame" x="66" y="10" width="153" height="0.0"/>
+                        <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="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URQ-HD-MDc">
+                        <rect key="frame" x="231" y="10" width="84" height="0.0"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="84" id="jM2-ye-nzP"/>
+                        </constraints>
+                        <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">
+                        <rect key="frame" x="70" y="54" width="245" height="0.0"/>
+                        <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>
+                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="99.." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9Ff-Wo-dWM">
+                        <rect key="frame" x="34" y="10" width="20" height="20"/>
+                        <color key="backgroundColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="20" id="XU3-CN-tXR"/>
+                            <constraint firstAttribute="height" constant="20" id="Yfh-b5-N7U"/>
+                        </constraints>
+                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="11"/>
+                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <nil key="highlightedColor"/>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="10"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </label>
+                </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="9Ff-Wo-dWM" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="Frj-Mc-oGy"/>
+                    <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 firstAttribute="trailing" secondItem="I3j-lM-VtV" secondAttribute="trailing" constant="5" id="PJD-Jd-y3N"/>
+                    <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="9Ff-Wo-dWM" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="34" id="cM0-LZ-1iA"/>
+                    <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="URQ-HD-MDc" firstAttribute="leading" secondItem="bOp-mm-qCN" secondAttribute="trailing" constant="12" id="obm-on-urU"/>
+                    <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"/>
+                <outlet property="unreadNumberLabel" destination="9Ff-Wo-dWM" id="z3x-wN-Bfv"/>
+            </connections>
+            <point key="canvasLocation" x="-65.217391304347828" y="-31.473214285714285"/>
+        </tableViewCell>
+    </objects>
+</document>

+ 26 - 0
o2ios/O2Platform/App/IM-聊天/View/IMLocationView.swift

@@ -0,0 +1,26 @@
+//
+//  IMLocationView.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/18.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+
+class IMLocationView: UIView {
+    
+    static let IMLocationViewWidth: CGFloat = 175
+    static let IMLocationViewHeight: CGFloat = 100
+    
+    @IBOutlet weak var locationLabel: UILabel!
+    
+    
+    override func awakeFromNib() {
+    }
+    
+    func setLocationAddress(address: String) {
+        self.locationLabel.text = address
+    }
+    
+}

+ 59 - 0
o2ios/O2Platform/App/IM-聊天/View/IMLocationView.xib

@@ -0,0 +1,59 @@
+<?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"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="IMLocationView" customModule="O2Platform" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="175" height="100"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_list_poi_background" translatesAutoresizingMaskIntoConstraints="NO" id="Wnb-9p-mB9">
+                    <rect key="frame" x="0.0" y="0.0" width="175" height="100"/>
+                </imageView>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RFx-ki-VdW">
+                    <rect key="frame" x="0.0" y="0.0" width="175" height="32"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zrA-xl-ZpU">
+                            <rect key="frame" x="5" y="16" width="165" height="0.0"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                    </subviews>
+                    <color key="backgroundColor" white="1" alpha="0.75321061639999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="zrA-xl-ZpU" firstAttribute="centerY" secondItem="RFx-ki-VdW" secondAttribute="centerY" id="PjU-x3-Yhs"/>
+                        <constraint firstItem="zrA-xl-ZpU" firstAttribute="leading" secondItem="RFx-ki-VdW" secondAttribute="leading" constant="5" id="drp-9P-liN"/>
+                        <constraint firstAttribute="trailing" secondItem="zrA-xl-ZpU" secondAttribute="trailing" constant="5" id="qg0-WC-PDN"/>
+                        <constraint firstAttribute="height" constant="32" id="yQb-fr-wUS"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+            <constraints>
+                <constraint firstItem="RFx-ki-VdW" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="0at-tV-wNL"/>
+                <constraint firstAttribute="trailing" secondItem="RFx-ki-VdW" secondAttribute="trailing" id="6IR-GH-3bN"/>
+                <constraint firstItem="Wnb-9p-mB9" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="6hd-WP-j5N"/>
+                <constraint firstItem="RFx-ki-VdW" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="ChW-2V-vNZ"/>
+                <constraint firstItem="Wnb-9p-mB9" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="Lll-Wv-407"/>
+                <constraint firstItem="Wnb-9p-mB9" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="gq9-Ps-ERI"/>
+                <constraint firstItem="Wnb-9p-mB9" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="lGa-tf-rGe"/>
+            </constraints>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <connections>
+                <outlet property="locationLabel" destination="zrA-xl-ZpU" id="oQZ-ub-EBW"/>
+            </connections>
+            <point key="canvasLocation" x="131.15942028985509" y="195.53571428571428"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="chat_list_poi_background" width="225" height="130"/>
+    </resources>
+</document>

+ 1 - 1
o2ios/O2Platform/App/Login-绑定登录/c/OOLoginViewController.swift

@@ -148,7 +148,7 @@ class OOLoginViewController: OOBaseViewController {
     }
     
     @IBAction func btnReBindNodeAction(_ sender: UIButton) {
-        self.showSystemAlert(title: "重新绑定", message: "重新绑定到新的服务节点,原节点信息将被清空,确认吗?") { (action) in
+        self.showDefaultConfirm(title: "重新绑定", message: "重新绑定到新的服务节点,原节点信息将被清空,确认吗?") { (action) in
             O2AuthSDK.shared.clearAllInformationBeforeReBind(callback: { (result, msg) in
                 DDLogInfo("清空登录和绑定信息,result:\(result), msg:\(msg ?? "")")
                 DBManager.shared.removeAll()

+ 69 - 44
o2ios/O2Platform/App/NewAttance-考勤打卡/c/OOAttanceCheckInController.swift

@@ -19,7 +19,8 @@ class OOAttanceCheckInController: UITableViewController {
     
     var checkinForm:OOAttandanceMobileCheckinForm = OOAttandanceMobileCheckinForm()
     
-    var myButton:UIButton!
+    var myButton:UIButton?
+    var feature : OOAttandanceFeature?
     
     private lazy var headerView:OOAttanceHeaderView = {
        let view = Bundle.main.loadNibNamed("OOAttanceHeaderView", owner: self, options: nil)?.first as! OOAttanceHeaderView
@@ -38,7 +39,7 @@ class OOAttanceCheckInController: UITableViewController {
         headerView.startBMKMapViewService()
         NotificationCenter.default.addObserver(self, selector: #selector(locationReceive(_:)), name: OONotification.location.notificationName, object: nil)
         if myButton != nil {
-            myButton.isHidden = false
+            myButton?.isHidden = false
         }
     }
     
@@ -47,53 +48,52 @@ class OOAttanceCheckInController: UITableViewController {
         headerView.stopBMKMapViewService()
         NotificationCenter.default.removeObserver(self)
         if myButton != nil {
-            myButton.isHidden = true
+            myButton?.isHidden = true
         }
     }
     
     
     override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
-        getWorkPlace()
+        
     }
     
 
    
     override func viewDidLoad() {
         super.viewDidLoad()
-//        title = "打卡"
-        
-//        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "关闭", style: .plain, target: self, action: #selector(closeWindow))
-        //tableView.tableHeaderView = headerView
-        //tableView.contentInset = UIEdgeInsets(top: 230, left: 0, bottom: 0, right: 0)
-        //register Cell
         tableView.register(UINib.init(nibName: "OOAttanceItemCell", bundle: nil), forCellReuseIdentifier: "OOAttanceItemCell")
         
         getCurrentCheckinList()
+        getMyRecords()
         self.perform(#selector(createButton), with: nil, afterDelay: 0)
+        
+        getWorkPlace()
     }
     
     
-    @objc func closeWindow() {
-        self.tabBarController?.navigationController?.dismiss(animated: true, completion: nil)
-    }
-    
+    //创建打卡按钮
     @objc private func createButton() {
         let window = UIApplication.shared.windows[0]
         myButton = UIButton(type: .custom)
-        myButton.frame = CGRect(x: kScreenW - 90, y: kScreenH - 150, width: 70, height: 70)
-        myButton.setTitle("打卡", for: .normal)
-        myButton.setTitle("打卡", for: .disabled)
-        myButton.titleLabel?.font = UIFont(name: "PingFangSC-Medium", size: 18.0)!
-        myButton.theme_backgroundColor = ThemeColorPicker(keyPath: "Base.base_color")
-        myButton.setBackgroundColor(UIColor.gray, forState: .disabled)
-        myButton.isEnabled = false
-        myButton.layer.cornerRadius = 35
-        myButton.layer.masksToBounds = true
-        myButton.addTarget(self, action: #selector(postCheckinButton(_:)), for: .touchUpInside)
-        window.addSubview(myButton)
-        let pan = UIPanGestureRecognizer(target: self, action: #selector(changePostion(_:)))
-        myButton.addGestureRecognizer(pan)
+        myButton?.frame = CGRect(x: kScreenW - 90, y: kScreenH - 150, width: 70, height: 70)
+        myButton?.setTitle("打卡", for: .normal)
+        myButton?.setTitle("打卡", for: .disabled)
+        myButton?.titleLabel?.font = UIFont(name: "PingFangSC-Medium", size: 14.0)!
+        myButton?.theme_backgroundColor = ThemeColorPicker(keyPath: "Base.base_color")
+        myButton?.setBackgroundColor(UIColor.gray, forState: .disabled)
+        myButton?.isEnabled = false
+        myButton?.layer.cornerRadius = 35
+        myButton?.layer.masksToBounds = true
+        myButton?.addTarget(self, action: #selector(postCheckinButton(_:)), for: .touchUpInside)
+        window.addSubview(myButton!)
+    }
+    //删除打卡按钮
+    private func removeButton() {
+        if myButton != nil {
+            myButton?.removeFromSuperview()
+            myButton = nil
+        }
     }
     
     @objc private func locationReceive(_ notification:Notification){
@@ -102,27 +102,34 @@ class OOAttanceCheckInController: UITableViewController {
             checkinForm.desc = result.sematicDescription
             checkinForm.longitude = String(result.location.longitude)
             checkinForm.latitude = String(result.location.latitude)
-            
             checkinForm.empNo = O2AuthSDK.shared.myInfo()?.employee
             checkinForm.empName = O2AuthSDK.shared.myInfo()?.name
             let currenDate = Date()
             checkinForm.recordDateString = currenDate.toString("yyyy-MM-dd")
             checkinForm.signTime = currenDate.toString("HH:mm:ss")
-            
-            checkinForm.optMachineType = UIDevice.deviceModel()
+            checkinForm.optMachineType = UIDevice.deviceModelReadable()
             checkinForm.optSystemName = "\(UIDevice.systemName()) \(UIDevice.systemVersion())"
-            // button enable
-            myButton.isEnabled = true
+            // 打卡按钮启用
+            myButton?.isEnabled = true
             headerView.addSubview(promptView)
             DDLogDebug("checkForm set completed")
         }else{
-            myButton.isEnabled = false
-            promptView.removeSubviews()
+            //打卡按钮禁用
+            myButton?.isEnabled = false
+            promptView.removeFromSuperview()
         }
     }
     
     @objc private func postCheckinButton(_ sender:UIButton){
+        if self.feature != nil {
+            if self.feature?.signSeq ?? -1 < 1 {
+                self.showError(title: "当前不需要打卡!")
+                return
+            }
+        }
+        
         MBProgressHUD_JChat.showMessage(message: "打卡中...", toView: self.view)
+        checkinForm.checkin_type = self.feature?.checkinType ?? ""
         viewModel.postMyCheckin(checkinForm) { (result) in
             MBProgressHUD_JChat.hide(forView: self.view, animated: true)
             switch result {
@@ -130,6 +137,7 @@ class OOAttanceCheckInController: UITableViewController {
                 DispatchQueue.main.async {
                     MBProgressHUD_JChat.show(text:"打卡成功", view: self.view)
                     self.getCurrentCheckinList()
+                    self.getMyRecords()
                 }
                 break
             case .fail(let errorMessage):
@@ -143,21 +151,40 @@ class OOAttanceCheckInController: UITableViewController {
         }
     }
     
-    @objc private func changePostion(_ pan:UIPanGestureRecognizer){
-        
-    }
+//    @objc private func changePostion(_ pan:UIPanGestureRecognizer){
+//
+//    }
     
     func getWorkPlace() {
         viewModel.getLocationWorkPlace { (myResult) in
             switch myResult {
             case .ok(let result):
+                DDLogDebug("有打卡位置了。。。。。。")
                 let model = result as? [OOAttandanceWorkPlace]
                 DispatchQueue.main.async {
                    self.headerView.workPlaces = model
                 }
                 break
             case .fail(let s):
-                MBProgressHUD_JChat.show(text: "错误:\n\(s)", view: self.view, 2)
+                self.showError(title: "错误:\n\(s)")
+                break
+            default:
+                break
+            }
+        }
+    }
+    
+    func getMyRecords() {
+        viewModel.listMyRecords { (result) in
+            switch result {
+            case .ok(let record):
+                let model = record as? OOMyAttandanceRecords
+                if let feature = model?.feature {
+                    self.feature = feature
+                }
+                break
+            case .fail(let err):
+                DDLogError(err)
                 break
             default:
                 break
@@ -194,9 +221,7 @@ class OOAttanceCheckInController: UITableViewController {
         }
     }
     
-    func postCheckIn() {
-        
-    }
+     
 
     override func didReceiveMemoryWarning() {
         super.didReceiveMemoryWarning()
@@ -252,7 +277,7 @@ class OOAttanceCheckInController: UITableViewController {
     }
     
     
-//    deinit {
-//         headerView.stopBMKMapViewService()
-//    }
+    deinit {
+         DDLogDebug("deinit 这里是checkin controller 。。。。。。。。。")
+    }
 }

+ 1 - 9
o2ios/O2Platform/App/NewAttance-考勤打卡/c/OOAttanceSettingController.swift

@@ -258,15 +258,7 @@ extension OOAttanceSettingController:BMKGeoCodeSearchDelegate {
     func onGetReverseGeoCodeResult(_ searcher: BMKGeoCodeSearch!, result: BMKReverseGeoCodeSearchResult!, errorCode error: BMKSearchErrorCode) {
         dataView.workPlaceNameTextField.text = result.address
         dataView.workAliasNameTextField.text = result.sematicDescription
-//        for item in result.poiList {
-//            let m = item as! BMKPoiInfo
-//            print(m.name)            ///<POI名称
-//            print(m.uid)
-//            print(m.address)      ///<POI地址
-//            print(m.city)        ///<POI所在城市
-//            print(m.phone)        ///<POI电话号码
-//            print(m.pt.longitude,m.pt.latitude)    ///<POI坐标
-//        }
+
         //设置settingBean
         settingBean.placeName = result.address
         settingBean.placeAlias = result.sematicDescription

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно