Parcourir la source

Merge branch 'feature/async_form' into 'fix/form_return_resolve'

# Conflicts:
#   o2web/source/x_component_process_Xform/DatagridMobile.js
#   o2web/source/x_component_process_Xform/Documenteditor.js
胡起 il y a 5 ans
Parent
commit
9d8121e736
100 fichiers modifiés avec 2360 ajouts et 897 suppressions
  1. 0 408
      ChangeLog.md
  2. 205 107
      README.md
  3. 66 66
      build.xml
  4. 2 1
      o2android/app/src/main/AndroidManifest.xml
  5. 2 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseMVPActivity.kt
  6. 2 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2Activity.kt
  7. 2 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2BindActivity.kt
  8. 3 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2InstantMessageActivity.kt
  9. 17 13
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/launch/LaunchActivity.kt
  10. 153 16
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginActivity.kt
  11. 26 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginContract.kt
  12. 85 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginPresenter.kt
  13. 2 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexFragment.kt
  14. 4 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexPortalFragment.kt
  15. 8 8
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MyAppPresenter.kt
  16. 1 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityActivity.kt
  17. 5 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityContract.kt
  18. 42 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityPresenter.kt
  19. 151 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/AntiHijackingUtil.java
  20. 200 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CheckRoot.java
  21. 41 0
      o2android/app/src/main/res/layout/activity_login.xml
  22. 4 0
      o2android/app/src/main/res/values/strings.xml
  23. 2 2
      o2android/gradle.properties
  24. 2 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2.kt
  25. 11 1
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2SDKManager.kt
  26. 30 3
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssembleAuthenticationService.kt
  27. 1 1
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssemblePersonalService.kt
  28. 12 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/CaptchaImgData.kt
  29. 14 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/LoginModeData.kt
  30. 14 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/LoginWithCaptchaForm.kt
  31. 11 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/RSAPublicKeyData.kt
  32. 2 1
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/main/person/PersonPwdForm.kt
  33. 53 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CryptRSA.java
  34. 8 4
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/SharedPreferencesHelper.kt
  35. 10 3
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/extension/Ext.kt
  36. 147 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/security/EncryptUtil.java
  37. 130 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/security/SecurityEditor.java
  38. 170 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/security/SecuritySharedPreference.java
  39. 12 0
      o2ios/O2Platform.xcodeproj/project.pbxproj
  40. 28 36
      o2ios/O2Platform/App/Applications/v/O2CollectionViewCell.swift
  41. 83 11
      o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarLeftMenuController.swift
  42. 19 2
      o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarMainMonthViewController.swift
  43. 90 0
      o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarStoreViewController.swift
  44. 61 0
      o2ios/O2Platform/App/Calendar-日程管理/View/CalendarStoreTableViewCell.swift
  45. 8 1
      o2ios/O2Platform/App/Calendar-日程管理/View/CalendarTableViewCell.swift
  46. 144 40
      o2ios/O2Platform/App/Calendar-日程管理/calendar.storyboard
  47. 77 72
      o2ios/O2Platform/App/Login-绑定登录/c/LoginViewController.swift
  48. 8 6
      o2ios/O2Platform/App/Login-绑定登录/c/OOBindNodeViewController.swift
  49. 25 0
      o2ios/O2Platform/App/Login-绑定登录/c/OOLoginViewController.swift
  50. 39 13
      o2ios/O2Platform/App/Login-绑定登录/login.storyboard
  51. 4 0
      o2ios/O2Platform/Extension/Notification+Extension.swift
  52. 8 4
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Headers/O2OA_Auth_SDK-Swift.h
  53. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Info.plist
  54. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/arm.swiftsourceinfo
  55. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo
  56. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/arm64.swiftsourceinfo
  57. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/armv7-apple-ios.swiftsourceinfo
  58. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/armv7.swiftsourceinfo
  59. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/i386-apple-ios-simulator.swiftsourceinfo
  60. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/i386.swiftsourceinfo
  61. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo
  62. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/x86_64.swiftsourceinfo
  63. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm.swiftdoc
  64. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm.swiftmodule
  65. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64-apple-ios.swiftdoc
  66. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64-apple-ios.swiftmodule
  67. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64.swiftdoc
  68. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64.swiftmodule
  69. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7-apple-ios.swiftdoc
  70. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7-apple-ios.swiftmodule
  71. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7.swiftdoc
  72. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7.swiftmodule
  73. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386-apple-ios-simulator.swiftdoc
  74. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386-apple-ios-simulator.swiftmodule
  75. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386.swiftdoc
  76. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386.swiftmodule
  77. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
  78. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule
  79. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64.swiftdoc
  80. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64.swiftmodule
  81. BIN
      o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/O2OA_Auth_SDK
  82. 5 0
      o2ios/O2Platform/Framework/Utils/ZonePermissions.swift
  83. 2 0
      o2ios/O2Platform/Framework/scan/LBXPermissions.swift
  84. 1 1
      o2ios/O2Platform/Info.plist
  85. 44 0
      o2ios/O2Platform/Manager/SecurityCheckManager.swift
  86. 1 7
      o2ios/O2Platform/UI/ZLCollectionView.swift
  87. 1 1
      o2ios/Podfile
  88. 5 5
      o2ios/Podfile.lock
  89. 3 1
      o2server/configSample/centerServer.json
  90. 10 20
      o2server/configSample/components.json
  91. 4 1
      o2server/configSample/dumpRestoreData.json
  92. 7 3
      o2server/configSample/node_127.0.0.1.json
  93. 2 0
      o2server/configSample/person.json
  94. 5 3
      o2server/configSample/processPlatform.json
  95. 1 0
      o2server/console_mips.sh
  96. 0 1
      o2server/console_raspberrypi.sh
  97. 1 0
      o2server/console_raspi.sh
  98. 0 1
      o2server/console_risc.sh
  99. 0 7
      o2server/pom.xml
  100. 24 24
      o2server/start_aix.sh

+ 0 - 408
ChangeLog.md

@@ -1,408 +0,0 @@
-## v4 build 1921\:
-
-[2019-06-18]新增功能:[流程引擎]新增通过配置设置是否要删除无内容的空草稿。
-
-[2019-06-18]新增功能:[流程引擎]新增获取我创建的工作数据接口。
-
-[2019-06-18]新增功能:[流程引擎]新增获取我创建工作数据接口。
-
-[2019-06-18]新增功能:[流程引擎]流程记录新增按活动、意见组、部门分组支持。
-
-[2019-06-18]新增功能:[流程引擎]流程里增加驳回功能,流程结束后可以恢复到流转状态。
-
-[2019-06-18]新增功能:[流程引擎]流程附件增加查看、下载、编辑权限的设置。
-
-[2019-06-18]新增功能:[流程引擎]支持流程根据工作日志进行指定回滚。
-
-[2019-06-18]新增功能:[流程引擎]新增自动删除草稿相关配置。
-
-[2019-06-18]新增功能:[流程引擎]流程时效管理新增催办功能。
-
-[2019-06-18]新增功能:[流程引擎]添加增加分支、流程回溯功能。
-
-[2019-06-18]新增功能:[流程引擎]增加中抢办功能。
-
-[2019-06-18]新增功能:[流程表单]流程表单增加新的皮肤样式。
-
-[2019-06-18]新增功能:[流程表单]表单和页面创建、赋值、拖动组件时按Ctrl进行精确定位。
-
-[2019-06-18]新增功能:[组织管理]增加委托授权相关设置。
-
-[2019-06-18]新增功能:[内容管理]支持根据用户是否阅读查询发布的文档列表。
-
-[2019-06-18]新增功能:[内容管理]支持根据文档ID列表判断后返回未读文档ID列表。
-
-[2019-06-18]新增功能:[内容管理]添加文档访问次数,支持视图查询访问次数 viewCount,添加最后内容修改时间 modifyTime。
-
-[2019-06-18]新增功能:[消息提醒]新增加模块x_message_core_entity,x_message_assemble_communicate"
-
-[2019-06-18]新增功能:[图片识别]增加图片识别文本修改功能。
-
-[2019-06-18]新增功能:[操作系统]支持中标麒麟操作系统:中标麒麟高级服务器操作系统软件(龙芯64位)。
-
-[2019-06-18]新增功能:[数据库连接]支持国产人大金仓KingbaseES8数据库。
-
-[2019-06-18]新增功能:[移动办公]AndroidH端新增H5网页文件选择能力的支持。
-
-[2019-06-18]新增功能:[移动办公]IOS端新增蓝色主题。
-
-[2019-06-18]新增功能:[移动办公]移动端支持表单控件图片编辑器。
-
-[2019-06-18]新增功能:[移动办公]移动端工作界面支持可扩展操作按钮。
-
-[2019-06-18]新增功能:[移动办公]移动端新增常用设备管理。
-
-[2019-06-18]新增功能:[移动办公]新增O2OA移动端JSAPI,通知模块、日期,日历选择模块、导航栏工具模块、设备信息模块。
-
-[2019-06-18]新增功能:[平台版本]新增中标麒麟龙芯版本。
-
-[2019-06-18]系统优化:[服务器控制台]修改图片识别默认设置。
-
-[2019-06-18]系统优化:[流程引擎]自动过滤第一条提醒消息。
-
-[2019-06-18]系统优化:[流程引擎]更新通过API获取workContext中的待办排序,保持与前台一致。
-
-[2019-06-18]系统优化:[流程引擎]work增加当前处理人的显示字段manualTaskIdentityText。
-
-[2019-06-18]系统优化:[流程引擎]workLog增加group字段。
-
-[2019-06-18]系统优化:[流程引擎]workLog增加opinionGroup字段。
-
-[2019-06-18]系统优化:[数据库支持]增加人大金仓V8的支持。
-
-[2019-06-18]系统优化:[数据库连接]由应用管理连接池改为jndi管理resource连接池,连接数需求大幅下降。
-
-[2019-06-18]系统优化:[消息提醒]废弃模块x_collaboration_assemble_websocket,x_collaboration_service_message,x_collaboration_core_entity,x_collaboration_core_message"
-
-[2019-06-18]系统优化:[内容管理]优化源码调exception目录结构。
-
-[2019-06-18]系统优化:[内容管理]支持栏目和分类别名修改。
-
-[2019-06-18]系统优化:[内容管理]优化栏目和分类更名处理逻辑,使用队列提升处理性能。
-
-[2019-06-18]系统优化:[内容管理]优化删除文档过程,降低内存占用。
-
-[2019-06-18]系统优化:[内容管理]优化平台启动过程,大幅提高平台启动速度。
-
-[2019-06-18]问题修复:[流程引擎]召回时会删除办理时间。
-
-[2019-06-18]问题修复:[神经网络]修正神经网络无法删除的bug。
-
-[2019-06-18]问题修复:[数据统计]视图中选择'周'无效。
-
-[2019-06-18]问题修复:[数据库支持]人大金仓ES8数据库boolean读取错误的bug。
-
-[2019-06-18]问题修复:[用户管理]修复管理员被锁定的bug。
-
-[2019-06-18]问题修复:[内容管理]修复栏目更名引起的内存溢出问题。
-
-[2019-06-18]问题修复:[内容管理]修复创建文档时标题超长的问题(截取70字)。
-
-[2019-06-18]问题修复:[H5移动端界面]修正H5界面展示错误。
-
-[2019-06-18]问题修复:[平台功能]其他已知问题的修复。
-
-
-
-## v4 build 1660\:
-
-[2019-04-26]新增功能:[用户认证]可以通过配置设置登录二维码的logo图片。
-
-[2019-04-26]新增功能:[流程引擎]增加可以针对多级拆分状态下的增加任意分支功能。
-
-[2019-04-26]新增功能:[用户管理]增加登录错误次数限制以及锁定时间限制。
-
-[2019-04-26]新增功能:[系统能力]增加自定义数据表和数据服务的能力。
-
-[2019-04-26]新增功能:[内容管理API]增加根据指定时间获取最新发布的信息数量和列表服务。
-
-[2019-04-26]系统优化:[流程引擎API]取得当前工作待办getTaskList(),取得当前任务待办(包括所有分支)getJobTaskList()。
-
-[2019-04-26]系统优化:[流程引擎API]取得当前工作已办getTaskCompletedList(),取得当前任务待办(包括所有分支)getJobTaskCompletedList()。
-
-[2019-04-26]系统优化:[流程引擎API]取得当前工作待阅getReadList(),取得当前任务待办(包括所有分支)getJobReadList()。
-
-[2019-04-26]系统优化:[流程引擎API]取得当前工作已阅getReadCompletedList(),取得当前任务待办(包括所有分支)getJobReadCompletedList()。
-
-[2019-04-26]系统优化:[用户管理]手机号码从默认支持大陆和香港改为默认支持大陆港澳台。
-
-[2019-04-26]系统优化:[信息管理]增加清空栏目和清空分类文档信息接口。
-
-[2019-04-26]系统优化:[表单设计]修改移动端H5提交页面样式。
-
-[2019-04-26]系统优化:[表单设计]修改移动端H5人员选择界面样式。
-
-[2019-04-26]系统优化:[表单设计]优化表单定位方法,支持在左侧结构中进行组件移动。
-
-[2019-04-26]系统优化:[系统安全]session相关优化。
-
-[2019-04-26]系统优化:[系统优化]系统页面展现效率相关优化。
-
-[2019-04-26]BUG修复:[流程引擎]自动启动的工作被误判为草稿删除的BUG。
-
-[2019-04-26]BUG修复:[流程引擎]撤回按钮设置无效的BUG。
-
-[2019-04-26]BUG修复:[组织管理]通过EXCEL导入人员重名判断为重复用户的问题。
-
-[2019-04-26]BUG修复:[表单设计]打印表单只打印第一页的问题。
-
-[2019-04-26]BUG修复:[Office编辑器]修复套红事件无法使用的问题。
-
-[2019-04-26]BUG修复:[人员选择]修复人员选择器会弹出对话框'1'的问题。
-
-[2019-04-26]BUG修复:[流程服务]修复COPY流程附件到另一个流程时没有的权限问题。
-
-
-## v4 build 12.26\:
-
-2018-12-26 新增功能:[表单设计]表单和页面增加导入功能,支持HTML、JSON格式。
-
-2018-12-26 新增功能:[表单设计]增加Word文件直接导入转换为表单。
-
-2018-12-26 新增功能:[表单设计]表单和页面增加“脚本”选项卡,可更方便的查找和编写脚本。
-
-2018-12-26 新增功能:[钉钉集成]钉钉接口从corpId变更为appKey。
-
-2018-12-26 新增功能:[数据库支持]修正达梦数据库默认schema的问题。
-
-2018-12-26 新增功能:[数据结构]增加对Map类型数据存储的功能。
-
-2018-12-26 新增功能:[文件传输]文件格式增加对xdoc(application/vnd.openxmlformats-officedocument.wordprocessingml.document)文件的支持。
-
-2018-12-26 更新优化:[表单设计]优化流程表单展现资源载入性能。
-
-2018-12-26 更新优化:[数据库支持]默认打包中的达梦数据库改为7.6版本。
-
-2018-12-26 更新优化:[WEB支持]修正了 http 请求中使用非限定头导致的chrome和firefox安全提示的问题。
-
-2018-12-26 更新优化:[会议管理]会议管理修改启动审批流程的接口方式。
-
-2018-12-26 BUG修复:[数据视图]修正视图设计中,删除列偶尔会发生异常的问题。
-
-2018-12-26 BUG修复:[文件传输]修正人员和组织设计元素中,某些属性无效的问题。
-
-2018-12-26 BUG修复:[文件传输]修正对于poi版本不一致包应用的问题。
-
-
-
-## O2OA v4.12.16 发布\:
-
-2018-12-16 新增功能:[流程平台]工作实例可以再次添加参阅人员。
-
-2018-12-16 新增功能:[流程平台]在x_processplatform_assemble_surface模块中增加读取工作日志的接口。
-
-2018-12-16 新增功能:[系统平台]接口调用增加对jaxws的支持,可以直接使用webService而不需要使用接口存根。
-
-2018-12-16 更新优化:[表单设计]优化表单控件[图片],src属性支持相对路径。
-
-2018-12-16 更新优化:[信息管理]文档列表服务增加根据创建者组织过滤条件。
-
-2018-12-16 更新优化:[组织管理]角色信息添加角色说明信息描述。
-
-2018-12-16 更新优化:[组织管理]修改对于个人属性字符限制的问题.可以使用特殊字符如()<>。
-
-2018-12-16 更新优化:[系统平台]压缩精简资源文件,系统空间占用缩小300M。
-
-2018-12-16 更新优化:[系统平台]优化升级过程中由于载入过多文件,导致的大量内存消耗的问题。
-
-2018-12-16 Bug修:[流程平台]修复已经删除的流程实例前台页面会提示权限不足。
-
-2018-12-16 Bug修:[系统平台]修复CentOS某些情况下验证码图形无法展示的问题。
-
-2018-12-16 Bug修:[云文件]修复云文件创建第3级目录报错的问题。
-
-2018-12-16 Bug修:[信息管理]修复信息管理根据path更新数据的问题。
-
-2018-12-16 Bug修:[信息管理]修复信息管理更新数据后缓存未及时更新的问题。
-
-2018-12-16 Bug修:[钉钉接入]修正钉钉接入时获取jsticket的错误。
-
-
-## O2OA v4.11.28 发布\:
-
-2018-11-28 新增功能:[流程平台]增加用群组作为待办对象。
-
-2018-11-28 新增功能:[流程平台]流程实例草稿删除功能。
-
-2018-11-28 新增功能:[流程平台]流程中可以选择群组作为待办人,如果个人存在多个身份,那么取主身份进行处理。
-
-2018-11-28 新增功能:[数据平台]视图可以使用后台列公式了,这样可以对列值进行修正。
-
-2018-11-28 更新优化:升级gson由2.8.1->2.8.5。
-
-2018-11-28 更新优化:优化根据ID查询实体对象的方法:emc.list( class, ids )。
-
-2018-11-28 更新优化:[信息平台]优化了信息管理文档权限控制支持人员身份选择。
-
-2018-11-28 更新优化:[流程平台]优化了DataGrid组织数据存储格式。
-
-2018-11-28 更新优化:[流程平台]优化了personfield和orgfield表单组件,增加了选择排除脚本。
-
-2018-11-28 更新优化:[流程平台]优化了门户和流程中,使用附件图片作为页面或表单元素的样式时的显示。
-
-2018-11-28 Bug修复:修复了通过群组获取递归成员遗漏了群组中的组织成员导致的错误。
-
-2018-11-28 Bug修复:修复了某些定时任务无法正常执行的问题。
-
-2018-11-28 Bug修复:[信息平台]修复了门户页面没有设置默认主页时访问门户报错jsonError的问题。
-
-2018-11-28 Bug修复:[信息平台]修复了数据列表文档级别权限控制的问题。
-
-2018-11-28 Bug修复:[信息平台]修复了信息管理员判断的问题。
-
-2018-11-28 Bug修复:[信息平台]修复了信息管理列表管理员数据展示的问题。
-
-2018-11-28 Bug修复:[数据平台]修复了xpath多级数据组织对象问题的修复。
-
-2018-11-28 Bug修复:[流程平台]修复了由于判断跳过相同处理人导致的并行节点处理人判断错误。
-
-2018-11-28 Bug修复:[流程平台]修复了表单格式刷刷新样式后,没有正确显示样式属性的错误。
-
-
-## O2OA V4 Build 11.13 发布\:
-
-2018-11-13 新增功能:[流程管理]自动清理未保有任何数据未流转的流程实例。
-
-2018-11-13 新增功能:[流程管理]增加可以通过设置组织来进行传阅。
-
-2018-11-13 新增功能:[流程管理]增加可以通过设置组织来进行参阅。
-
-2018-11-13 新增功能:[移动APP]移动客户端可以通过语音直接处理公文。
-
-2018-11-13 新增功能:[微信钉钉]群发微信,钉钉,企业钉钉消息功能。
-
-2018-11-13 更新优化:[用户管理]增加通过管理员重置用户密码的功能。
-
-2018-11-13 更新优化:[移动APP]支持语音流程意见。
-
-2018-11-13 更新优化:[移动APP]IM提示消息。
-
-2018-11-13 更新优化:[内容管理]信息文档权限支持身份选择。
-
-2018-11-13 Bug修复:[会议管理]修复无法选择会议申请流程的问题。
-
-2018-11-13 Bug修复:[信息管理]修复无法修改信息栏目名称的问题。
-
-2018-11-13 Bug修复:[表单组件]表单上组织控件的默认值不生效。
-
-
-## O2OA V4 Build 11.02 发布\:
-
-2018-11-02 新增功能:[内容管理]增加设计元素可以拷贝粘贴的功能。
-
-2018-11-02 新增功能:[内容管理]增加组合框、子表单等设计元素组件。
-
-2018-11-02 新增功能:[企业社区]增加导航浏览模式
-
-2018-11-02 新增功能:[服务管理]增加设计元素可以拷贝粘贴的功能。
-
-2018-11-02 更新优化:可以在配置中选择是否对office,pdf,text,image进行切词索引。
-
-2018-11-02 更新优化:2018-11-02 更新优化:优化调整切词索引中对词性的判断。
-
-2018-11-02 更新优化:优化钉钉,企业微信,政务钉钉中由于反复获取accessToken导致的页面响应缓慢的问题。
-
-2018-11-02 Bug修复:[内容管理]视图的分类标题无法保存的问题。
-
-2018-11-02 Bug修复:[内容管理]修复附件无法替换的问题。
-
-2018-11-02 Bug修复:修正office格式引起的:NoSuchMethodException: org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTPictureBaseImpl。
-
-2018-11-02 Bug修复:日志文件不会自动删除的问题。
-
-
-## O2OA V4 Build 11.01 发布\:
-
-2018-11-01 新增功能:企业微信,钉钉,政务钉钉组织同步,待办消息推送,通知消息群发,移动设备
-
-2018-11-01 新增功能:新增MS-SQLServer支持,目前可以支持一下数据库:Oracle,DB2,MySQL,Postgresql,Informix,H2(内嵌),DM(达梦国产数据库),MS-SQLServer。
-
-2018-11-01 新增功能:OAuth2客户端功能优化,支持CA,微信,QQ等其他OAuth认证服务。
-
-2018-11-01 新增功能:增加消息群发功能。
-
-2018-11-01 新增功能:ISO,AndroidApp端增加语音处理功能。
-
-2018-11-01 新增功能:ISO,AndroidApp端增加AI自动处理功能。
-
-2018-11-01 新增功能:启用新域名o2oa.net。
-
-2018-11-01 新增功能:增加登录页面定制功能,现在可以通过门户定制登录页面了。
-
-2018-11-01 新增功能:社区中增加导航模式。
-
-2018-11-01 新增功能:设计元素增加复制黏贴功能。
-
-2018-11-01 功能优化:支持金山WPS。
-
-2018-11-01 功能优化:统计中数据量导致的新能下降。
-
-2018-11-01 功能优化:群组(Group)支持组织成员,可以统一翻译成人员。
-
-2018-11-01 功能优化:增加个人的主身份设置,当不指名身份时可以自动取到主身份。
-
-2018-11-01 功能优化:用户可以自行绑定微信,通过微信扫码登录。
-
-2018-11-01 功能优化:[信息管理]对信息文档查询效率源码级优化。
-
-2018-11-01 Bug修复:会议管理字段超长导致的错误。
-
-2018-11-01 Bug修复:无标题流程消息提醒显示空字符串。
-
-2018-11-01 Bug修复:脚本编辑器在同时打开多个窗口情况无法正常保存。
-
-2018-11-01 Bug修复:修改组织同步触发机制,现在可以通过cron表达式定制运行时间。
-
-2018-11-01 Bug修复:[信息管理]修复数据字典无法复制的问题以及分类显示的错误。
-
-2018-11-01 Bug修复:Office控件集成代码修正。
-
-
-## O2OA V4 Build 09.21 发布\:
-
-2018-09-21 新增功能:增加手写签批功能,支持在线手写签批,录音。
-
-2018-09-21 新增功能:增加全文搜索功能。支持pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx内容的全文
-
-2018-09-21 新增功能:OAuth客户端功能,支持微信等其他OAuth认证服务。
-
-2018-09-21 新增功能:[汇报管理]添加手工漏发检测功能。
-
-2018-09-21 功能优化:更新统计展现功能,支持饼图,柱状图,折线图,支持行列转换。
-
-2018-09-21 功能优化:统计功能,可以源于不同试图的列进行合并统计。
-
-2018-09-21 功能优化:优化日程管理提醒不及时的问题。
-
-2018-09-21 Bug修复:流程重置处理人错误。
-
-2018-09-21 Bug修复:[信息管理]修复数据型文档类型保存不正确的问题。
-
-2018-09-21 Bug修复:[脑图]修复某些情况下脑图无法创建的问题。
-
-
-## O2OA V4 Build 09.04 发布\:
-
-2018-09-04 新增功能:电子签章支持。
-
-2018-09-04 新增功能:流程引擎增加定时节点。
-
-2018-09-04 新增功能:政务钉钉支持,可以同步政务钉钉的人员,组织。
-
-2018-09-04 新增功能:增加行政区划组件。
-
-2018-09-04 新增功能:[社区应用]添加调整主贴版块的服务。
-
-2018-09-04 功能优化:视图统计代码优化,提升统计查询效率。
-
-2018-09-04 功能优化:优化待办已办查询,TaskCompleted 增加 latest。
-
-2018-09-04 功能优化:流程引擎底层优化,修改PorcessPlatform实现的aeiObjects。
-
-2018-09-04 Bug修复:应用导入导出错误。
-
-2018-09-04 Bug修复:[信息管理]修复CMS_Review自动同步更新的问题。
-
-2018-09-04 Bug修复:2018-09-04 Bug修复:[信息管理]修复序列保存时为空的问题。
-
-2018-09-04 Bug修复:修正移动端APP信息管理会把数据类的信息读取出来的问题。

+ 205 - 107
README.md

@@ -78,25 +78,25 @@ O2OA自带的H2数据库是一个内嵌式的内存数据库,适合用于开
 另外,O2OA提供数据定期备份和恢复的能力,建议您开启正式环境的数据定期备份的功能,以确保数据库异常时可以进行数据恢复。
 
 
-# 最新版本服务器安装包下载[o2server_V5.1.1]\:
+# 最新版本服务器安装包下载[o2server_V5.2.1]\:
 
-windows 64Bit : http://download.o2oa.net/download/o2server-5.1.1-windows.zip
+windows 64Bit : http://download.o2oa.net/download/o2server-5.2.1-windows.zip
 
-Linux 64Bit : http://download.o2oa.net/download/o2server-5.1.1-linux.zip
+Linux 64Bit : http://download.o2oa.net/download/o2server-5.2.1-linux-x86.zip
 
-MacOS : http://download.o2oa.net/download/o2server-5.1.1-macos.zip
+MacOS : http://download.o2oa.net/download/o2server-5.2.1-macos.zip
 
-AIX : http://download.o2oa.net/download/o2server-5.1.1-aix.zip
+AIX : http://download.o2oa.net/download/o2server-5.2.1-aix.zip
 
-raspberrypi(树莓派):http://download.o2oa.net/download/o2server-5.1.1-raspberrypi.zip
+raspberrypi(树莓派):http://download.o2oa.net/download/o2server-5.2.1-raspi.zip
 
 ARM[深度Linux(deepin),优麒麟(Ubuntu),中标麒麟(NeoKylin),威科乐恩Linux(WiOS)]:
 
-http://download.o2oa.net/download/o2server-5.1.1-arm.zip
+http://download.o2oa.net/download/o2server-5.2.1-linux-arm.zip
 
 RISC-V[Debian GNU/Linux,银河麒麟飞腾]:
 
-http://download.o2oa.net/download/o2server-5.1.1-risc.zip
+http://download.o2oa.net/download/o2server-5.2.1-linux-mips.zip
 
 
 
@@ -107,205 +107,303 @@ http://download.o2oa.net/download/o2server-5.1.1-risc.zip
 腾讯微云:https://share.weiyun.com/5krUMjj
 
 
-# 最新版本 v5.1.1\:
+# 最新版本 v5.2\:
 
 功能新增
 
-[安全认证]认证能力增强,支持微软oa/adfs单点认证及AD用户认证、用户组织数据同步能力
+[系统架构]系统安全加固,使用加密信息传输配置文件密码
 
-[安全认证]增加在用户登录时新增判断密码过期的能力,如果是先修改密码再重新登录
+[系统架构]功能增强,增加通过URL传入参数,直接打开指定应用界面的功能
 
-[脚本设计]新增monaco脚本编辑器
+[系统架构]功能增强,Dump命令支持全量数据导出和部分数据导出
 
-[考勤管理]为考勤结果申诉新增自定义审批流程能力
+[系统架构]功能增强,Dump命令支持对数据和文件信息的合并操作
 
-[考勤管理]移动考勤打卡策略可选择一天二次,三次,四次打卡,目前实现三种策略
+[系统架构]系统增强,改用Instrumentation实现jar包加载
 
-[流程管理]新增流程自定义提交功能
+[系统架构]系统增强,webServer增加proxy功能,可以替代nginx实现映射
 
-[流程管理]增加字典路径为null条件判断,解决oracel,kingbase数据获取问题
+[系统架构]新增集成消息中间件管理消息队列,比如kafka,activeMQ
 
-[流程维护]增加处理人搜索,业务数据映射搜索。
+[平台配置]系统增强,增加在线编辑部分配置文件的能力,并在集群时同步配置信息
 
-[流程维护]增加业务数据、是否流转等相关过滤。
+[用户认证]新增用户登录ip限制(黑名单)功能
 
-[平台功能]平台增加在线部署资源、部署服务的功能
+[流程管理]新增了数据字典编辑器
 
-[平台功能]新版应用市场数据同步及展现
+[流程管理]新增了管理员 (增加、删除、修改)授权接口
 
-[企业社区]企业社区增加对匿名访问权限的相关配置
+[流程平台]新增了待办已办待阅已阅稽核查询接口
 
-[表单设计]人员选择组件增加群组中的身份
+[流程平台]新增了流程附件拷贝到已完成工作接口
 
-[移动办公]Android端聊天表情和创建单聊功能
+[流程平台]新增了数据字典、脚本分页查询接口
 
-[移动办公]Android移动办公应用添加底部消息未读数量,支持群聊
+[流程平台]新增了流程草稿模式
 
-[移动办公]IOS聊天消息增加位置消息功能
+[流程平台]新增了管理员转交记录功能
 
-[移动办公]IOS移动办公IM消息应用增加语音消息、图片消息等功能
+[流程平台]新增了拆分值记录功能
 
-[移动办公]IOS移动办公应用增加消息展现和聊天消息功能
+[流程平台]新增了Message消息中流程上一处理人信息
 
-[移动办公]平台增加antv组件,增加移动端脚本调试工具Eruda
+[流程平台]新增了流程环节可以异步返回功能,针对大量拆分时可以异步返回
 
-[人员组织]增加人员组织升降序排序相关配置
+[表单设计]新增了表单版本恢复功能
 
-[数据中心]增加清空自建表数据的功能
+[表单设计]新增了表单中直接选择需要引入的脚本的功能
 
-[数据中心]增加视图查询对数组的支持
+[表单设计]新增了表单中直接选择引入的数据字典的功能
 
-[系统日志]增加了以集群方式在WEB端查看所有服务器的功能
+[表单设计]新增了版式文件缩放比例调整功能
 
-[移动办公]增加流程表单移动端蓝白界面样式
+[内容管理]新增了数据字典、脚本分页查询接口
+
+[内容管理]新增了查询文档阅读权限接口
+
+[门户管理]新增了脚本分页查询接口
+
+[数据中心]新增了数据视图中默认选中行的配置
+
+[数据中心]新增了清空自建表数据功能
+
+[考勤管理]新增了指定人员分析打卡数据接口考勤
+
+[考勤管理]新增了指定人员分析打卡数据接口
+
+[个人通讯录]新增通讯录权限设置
+
+[会议管理]新增了会议室分页功能
+
+[会议管理]新增了对会议室预定时间修改功能
+
+[会议管理]新增了根据会议室ID查询,某一时间段一个会议的使用情况的功能
+
+[即时通讯]新增了IM聊天Web端创建群聊功能和修改群属性等功能
+
+[移动办公]新增了移动端通知消息可打开对应应用的功能
+
+[移动办公]新增了移动端工作消息可以打开对应工作的功能
+
+[移动办公]新增了移动端添加地图位置展现功能,js api支持
+
+[移动办公]新增了移动端支持第三方地图打开位置信息,js api打开
+
+[移动办公]新增了移动端添加jsapi支持定位功能
+
+[移动办公]新增了华为WeLink集成能力
+
+[移动办公]新增了移动端启动流程的列表配置
+
+[移动办公]新增了Android添加修改个人密码功能
+
+[平台API]新增了数据库表结构显示功能
+
+[平台工具]新增了Html转PDF工具接口
 
 功能优化
 
-[表单设计]优化版式正文编辑的部分功能,优化WORD拷贝缩进优化以及半角空格转全角空显示
+[应用市场]应用市场整体升级,提供应用下载安装相关说明,提供对应用评论打分的功能
 
-[表单设计]优化表单人员选择器,允许根据职务选择的时候进行跨层级全选
+[系统架构]服务器身份可以调用前端服务
 
-[表单设计]优化表单转换功能,表单转PDF默认为A4的长宽
+[系统架构]options响应头更新
 
-[平台设计]优化表单设计,修复表单设计元素部分样式的问题
+[系统架构]后台优先连接到本地服务器
 
-[会议管理]优化会议显示,在列表中增加正在进行中会议的显示
+[系统架构]页面缓存更新
 
-[脚本设计]优化流程表单中的弹出选择器组件,允许自定义弹出选择器选中分类
+[系统架构]默认mysql驱动由 com.mysql.jdbc.Driver 改为 com.mysql.cj.jdbc.Driver
 
-[考勤管理]优化考勤管理移动打卡API,以及三次打卡中的相关打卡时间计算逻辑和分析逻辑
+[通用功能]ACE编辑器从1.2.8升级到1.4.12
 
-[流程管理]优化架构,增加对长文本标题的处理逻辑
+[平台命令]创建encryptKey时增加please restart sever提示
 
-[流程管理]优化流程表单载入机制,大幅提升流程启动时表单展现效率
+[平台API]ResetAction里增加了JaxrsDescribe注解
 
-[流程管理]优化和补充审批日志中的部分信息
+[人员组织]新增人员组织属性导入
 
-[内容管理]优化内容管理文档权限机制,适应二段[如:unique@P]结构组织对象权限设定
+[人员组织]人员相关选择组件增加保存精简数据的配置
 
-[平台架构]架构优化,集群切换功能优化,增加集群应用掉线判断的能力,避免在运行过程中出现集群应用掉线的情况
+[人员组织]人员选择增加选项:当候选只有一个选项时,是否默认选中
 
-[平台架构]前端架构优化,支持主流前端技术集成:Vue, React, Angular
+[人员组织]组织管理和个人设置增加字段[登录IP]
 
-[数据中心]视图关于内容管理权限查询优化
+[人员组织]批量查询用户、组织接口返回内容修改
 
-问题修复
+[人员组织]人员组织导入添加校验手机号有效性
+
+[流程平台]并行节点接拆分分支执行错误
+
+[流程平台]并行活动路由时,如果选择的路由数相同,那么优先执行数量相同的最晚路由
+
+[流程管理]内容管理、流程管理人员相关选择组件增加保存精简数据的配置
+
+[流程管理]流程重置处理人选择范围增加脚本
 
-[表单设计]修复表单设计Tab页展现不正确的问题
+[流程平台]简化待阅发送内容
 
-[表单设计]修复移动端日期选择组件描述选择问题
+[流程平台]流程活动增加重置处理人脚本
 
-[表单设计]修正版式正文从WORD文件粘贴后段落首行缩进不正确的问题
+[流程平台]增加work中的活动到达时间数据存入item数据中,可用于视图查询
 
-[表单设计]修正某些情况下版式文件日期显示错误的问题
+[流程平台]流程审计日志补充
 
-[表单设计]修正某些情况下表单单选框选项不显示的问题
+[流程平台]优化已办查询,增加已办title字段搜索
 
-[会议管理]修复了某些情况下会议管理重复选择邀请人等问题
+[流程平台]打开流程工作性能优化
 
-[脚本设计]修复拷贝、粘贴或剪切脚本时,会影响到表单和流程设计元素的问题
+[表单设计]增加子表单延迟加载的功能
 
-[脚本设计]修复流程脚本在使用monaco编辑器时,点击保存按钮无法保存的问题
+[表单设计]表单样式允许使用脚本在前台自定义
 
-[考勤管理]修复考勤管理中请假半天计算出勤天数不正确的问题
+[表单设计]流程表单的组件校验脚本中增加了当前决策
+
+[表单设计]增加表单中数据字典的缓存,重复使用不用每次都发起后台请求
+
+[表单设计]Fck编辑器图片上传增加保存为base64选项
+
+[表单设计]流程记录增加加载每行记录的事件
+
+[表单设计]数据网格增加允许添加允许删除选项
+
+[内容管理]缓存系统升级,使用新的缓存写法,随平台一起支持Redis
+
+[内容管理]新建内容管理应用,不自动添加当前处理人为管理员
+
+[服务管理]修改webserver增加几个类包升级到3.3.7
+
+[数据中心]优化视图查询,取消视图查询2000条限制
+
+[会议管理]允许会议申请发布后修改
+
+[会议管理]优化会议签到二维码,修改二维码大小
+
+[个人通讯录]base64编码解码优化个人通讯录,base64编码解码优化
+
+[移动办公]更新语音助手功能
+
+[移动办公]ios已办日志展现形式和UI改进优化
+
+[移动办公]更新改进扫码功能
+
+[移动办公]会议签到二维码大小调整
+
+[移动办公]考勤打卡界面更新,使用钉钉类似的界面
+
+[移动办公]移动端聊天窗口上拉加载更多消息内容
+
+[移动办公]移动端聊天窗口下拉刷新消息内容
+
+[移动办公]移动端聊天语音消息上滑取消发送功能优化
+
+[移动办公]群发消息增加华为WeLink的类型
+
+[移动办公]Welink 消息提示功能完成
+
+[移动办公]im消息用户不在线发送app推送消息
+
+[移动办公]移动端页面支持xtoken query传入
+
+问题修复
 
-[考勤管理]修复考勤优化修改后,无法根据个人请假信息正确计算考勤结果的问题
+[系统架构]修复了ScriptObjectMirror映射过程中嵌套循环的问题
 
-[考勤管理]修复了考勤申诉使用流程时,启动流程和流程状态同步的问题
+[平台API]修复了api接口界面附件上传报错的问题
 
-[考勤管理]修复了移动打卡数据服务无法指定打卡时间的问题
+[平台API]修复了x_program_center load模块api脚本出错的问题
 
-[考勤管理]修复了以前的打卡在某些情况下会被误判为缺勤的问题,添加了每日定时分析前一天所有未签退的打卡信息
+[流程平台]修复了可调度人员权限判断错误的问题
 
-[考勤管理]修复了在某些情况下移动打卡后无法查询出结果的问题
+[流程平台]修复了在特定情况下编号脚本执行错误的问题
 
-[考勤管理]修复了在某些情况下移动打卡无效的问题
+[人员组织]修复了在某些情况下人员搜索不正确的问题
 
-[考勤管理]修复在某些特殊情况下,日程管理编辑时报错的问题以及对可见日程列表查询的相关优化
+[人员组织]修复了部分群组查询接口缺少身份信息的问题
 
-[流程管理]修复弹出选择器某些情况下无法取消选择分类的问题
+[人员组织]修复了钉钉同步员工编码的问题
 
-[流程管理]修复了某些情况下移动端数据网格设置数据异常的问题
+[系统架构]修复了在某此情况下Distinct 导致的排序的问题
 
-[流程管理]修复了确认框取消按钮某些情况下无背景色的问题
+[流程平台]修复了一键下载标题带斜杠的问题
 
-[流程管理]修复了数据网格和多选按钮校验异常的问题
+[流程平台]修复了流程多版本的查询的问题
 
-[流程管理]修复了提交界面某些情况下选择人员字样没有隐藏的问题
+[流程平台]修复了附件查询权限的问题
 
-[流程管理]修复流程表单操作条组件设置操作图标的时候未及时关闭图标选择器的问题
+[流程平台]修复了旧版本流程意见展现不全的问题
 
-[流程管理]修复流程分支合并后待阅仍发送多条通知的问题
+[流程平台]修复了流程流转到取消环节报错的问题
 
-[流程管理]修复流程结束后,没有“一键下载”和“打印”按钮的问题
+[流程平台]修复了删除流程未删除草稿的问题
 
-[流程管理]修复某些情况下流程应用中'无标题'显示为'undefined'的问题
+[流程平台]修复了意见过长,流程记录(record)显示的问题
 
-[流程管理]修复某些情况下普通人员打开流程应用编号视图报无权限错误的问题
+[流程平台]修复了脚本拷贝粘贴时,和设计元素的拷贝粘贴冲突的问题
 
-[流程管理]修复数据网格删除最后一条数据保存后仍存在的问题
+[表单设计]修复了日期选择组件在表单中跟随滚动条滚动的问题
 
-[流程管理]修复新建流程的时候,有可能会出现[object]字样的问题
+[表单设计]修复了某些情况下日期选择界面异常的问题
 
-[流程管理]修复在某些情况下自定义弹出框分类未选中的问题
+[表单设计]修复了页面设置树组件无效的问题
 
-[门户管理]修复了某些情况下门户分类显示'null'的问题
+[表单设计]修复了textarea只读状态下内容有尖括号的时候内容被截断的问题
 
-[门户管理]修复门户管理中某些情况下分类展现应用图标未正确获取的问题
+[表单设计]修复了表单可选值插入报错的问题
 
-[内容管理]新增了管理员根据人员标识查询人员可以看到的文档列表服务
+[内容管理]修复了在没有设置主身份时,内容管理和考勤管理中根据用户名查询主身份报错的问题
 
-[内容管理]修复了某些情况下内容管理脚本报错的问题
+[内容管理]修复了在某些情况下,分页数据排序不正确引起,分页功能不正常的问题
 
-[内容管理]修复内容管理表单操作条不能设置样式的问题
+[内容管理]修复了在某些情况下,发布文档时会通知所有人员的问题
 
-[内容管理]修复内容管理表单脚本编辑器无法正常拷贝粘贴的问题
+[内容管理]修复了在某些情况下排序索引列过长,无法正确处理权限的问题
 
-[内容管理]修复内容管理信息删除后,相关的热点图片不会立即自动删除的问题(需要等待热点图片自动检测后才能删除)
+[人员选择]修复了人员选择双击分类可能重复加载的问题
 
-[内容管理]修复在存在发布文档的情况下分类仍可以在无任何提醒的情况下删除的问题
+[内容管理]修复了模块中分类过长时不显示的问题
 
-[人员组织]修复部分版本中钉钉同步员工中编码不正确或者无法同步的问题
+[数据中心]修复了数据统计图表类型无法保存的问题
 
-[人员组织]修复某些情况下群组新增报错问题
+[考勤管理]修复了考勤部门人员明细排除不参加考勤人员考勤部门人员明细排除不参加考勤人员的问题
 
-[日程管理]修复在某些特殊情况下,日程管理会展示两条系统自建日历的问题
+[考勤管理]修复了考勤统计结果-排除不参加考勤的人员及组织的问题
 
-[数据中心]修复了视图某些情况下跳页报错的问题
+[考勤管理]修复了部门考勤月报排除不参加考勤的组织和人员的问题
 
-[数据中心]修复视图某些情况下不能正确删除列和排序列顺序不对的问题
+[考勤管理]修复了移动打卡类型错误的问题
 
-[数据中心]修复视图搜索和高级搜索切换显示的数据未切换的问题
+[论坛管理]修复了论坛停用分区后,在导航中还是会显示的问题
 
-[系统首页]修正首页日历高度在过低分辨率下无法对齐的问题
+[论坛管理]修复了论坛回复数量不会实时更新的问题
 
-[移动办公]修复Android云文件分享的文件在某些情况下无法打开的问题
+[会议管理]修复了serviceAPI枚举类型提交错误的问题
 
-[移动办公]修复滚动图片不显示的的问题以及IM图片音频消息无法下载的问题
+[移动办公]修复了IOS任务列表图标随机变化的问题
 
-[移动办公]修复了某些手机型下Android版脑图应用无法打开,闪退的问题
+[移动办公]修复了ios考勤统计列表排序的问题
 
-[移动办公]修复论坛帖子附件在某些情况下无法查看的问题
+[移动办公]修复了了文档附件无法打开的问题
 
-[移动办公]修复某些情况下应用窗口关闭时移动端无法正常关闭的问题
+[移动办公]修复了IOS通讯录搜索框按钮看不到的问题
 
-[移动办公]修复消息模块功能中某些情况下修复无法下载文件的问题
+[移动办公]修复了android sdk环境升级,developtools、Android support等官方库升级的问题
 
-[移动办公]修复移动打卡在某些情况下无法定位的问题
+[移动办公]修复了Android流程启动身份选择样式的问题
 
-[移动办公]修复移动考勤打卡按钮在某些情况下无法显示的问题
+[移动办公]修复了IOS流程启动身份选择样式的问题
 
-[应用管理]修复某些情况下应用无法正常导出的问题
+[移动办公]修复了ios已办查询功能,修复多次下拉闪退的问题
 
-[云文件]修复了某些情况下不同用户上传同一文件到根目录失败的问题
+[移动办公]修复了IOS打开结束工作错误的问题
 
-[云文件]修复了云文件在Oracle和人大金仓数据库环境下查询顶层列表不正确的问题
+[移动办公]修复了Android 8 下面的闪退的问题
 
-[组织管理]修复了组织管理没有输入内容搜索结果异常的问题
+[移动办公]修复了移动端消息没有消费的问题
 
-[组织管理]修复组织管理搜索翻页后会出现范围外的内容的问题
+[移动办公]修复了Android 10 图片选择不了的问题
 
-[组织管理]修复组织管理性别选择其他可能显示不正常的问题
+[移动办公]修复了jpush配置文件名字错误的问题
 
 
 # 配置编译环境\:
@@ -329,7 +427,7 @@ http://download.o2oa.net/download/o2server-5.1.1-risc.zip
 
 4.打开o2server文件夹,选择start_windows.bat双击打开。
 
-5.在命令行中输入"start" 回车,启动服务,等待相关服务启动完成。
+5.启动服务,等待相关服务启动完成。
 
 6.启动完成后打开浏览器访问http://127.0.0.1。
 

+ 66 - 66
build.xml

@@ -15,8 +15,8 @@
 			project.setNewProperty("length_win_mb", length_win_mbytes);
 		]]>
 		</script>
-		<checksum file="${preName}-${VERSION}-linux.zip" property="build_linux.sha" algorithm="SHA-256" />
-		<length file="${preName}-${VERSION}-linux.zip" property="length_linux"/>
+		<checksum file="${preName}-${VERSION}-linux-x86.zip" property="build_linux.sha" algorithm="SHA-256" />
+		<length file="${preName}-${VERSION}-linux-x86.zip" property="length_linux"/>
 		<script language="javascript">
 			<![CDATA[
 			var length_linux_bytes = project.getProperty("length_linux");
@@ -45,8 +45,8 @@
 			project.setNewProperty("length_aix_mb", length_aix_mbytes);
 		]]>
 		</script>
-		<checksum file="${preName}-${VERSION}-raspberrypi.zip" property="build_raspberrypi.sha" algorithm="SHA-256" />
-		<length file="${preName}-${VERSION}-raspberrypi.zip" property="length_raspberrypi"/>
+		<checksum file="${preName}-${VERSION}-raspi.zip" property="build_raspberrypi.sha" algorithm="SHA-256" />
+		<length file="${preName}-${VERSION}-raspi.zip" property="length_raspberrypi"/>
 		<script language="javascript">
 			<![CDATA[
 			var length_raspberrypi_bytes = project.getProperty("length_raspberrypi");
@@ -55,18 +55,18 @@
 			project.setNewProperty("length_raspberrypi_mb", length_raspberrypi_mbytes);
 		]]>
 		</script>
-		<checksum file="${preName}-${VERSION}-risc.zip" property="build_risc.sha" algorithm="SHA-256" />
-		<length file="${preName}-${VERSION}-risc.zip" property="length_risc"/>
+		<checksum file="${preName}-${VERSION}-linux-mips.zip" property="build_mips.sha" algorithm="SHA-256" />
+		<length file="${preName}-${VERSION}-linux-mips.zip" property="length_mips"/>
 		<script language="javascript">
 			<![CDATA[
-			var length_risc_bytes = project.getProperty("length_risc");
-			var length_risc_kbytes = Math.round((length_risc_bytes / 1024) * Math.pow(10,2))/ Math.pow(10,2);
-			var length_risc_mbytes = Math.round((length_risc_kbytes / 1024) * Math.pow(10,2))/ Math.pow(10,2);
-			project.setNewProperty("length_risc_mb", length_risc_mbytes);
+			var length_mips_bytes = project.getProperty("length_mips");
+			var length_mips_kbytes = Math.round((length_mips_bytes / 1024) * Math.pow(10,2))/ Math.pow(10,2);
+			var length_mips_mbytes = Math.round((length_mips_kbytes / 1024) * Math.pow(10,2))/ Math.pow(10,2);
+			project.setNewProperty("length_mips_mb", length_mips_mbytes);
 		]]>
 		</script>
-		<checksum file="${preName}-${VERSION}-arm.zip" property="build_arm.sha" algorithm="SHA-256" />
-		<length file="${preName}-${VERSION}-arm.zip" property="length_arm"/>
+		<checksum file="${preName}-${VERSION}-linux-arm.zip" property="build_arm.sha" algorithm="SHA-256" />
+		<length file="${preName}-${VERSION}-linux-arm.zip" property="length_arm"/>
 		<script language="javascript">
 			<![CDATA[
 			var length_arm_bytes = project.getProperty("length_arm");
@@ -82,7 +82,7 @@
 			{
 			"windows": {
 			"system": "windows",
-			"name": "o2server-windows-${VERSION}",
+			"name": "o2server-${VERSION}-windows",
 			"fileName": "o2server-${VERSION}-windows.zip",
 			"fileSize": "${length_win_mb}MB",
 			"updateTime": "${TODAY}",
@@ -91,16 +91,16 @@
 			},
 			"linux": {
 			"system": "linux",
-			"name": "o2server-linux-${VERSION}",
-			"fileName": "o2server-${VERSION}-linux.zip",
+			"name": o2server-${VERSION}-linux-x86",
+			"fileName": "o2server-${VERSION}-linux-x86.zip",
 			"fileSize": "${length_linux_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-linux.zip",
+			"url": "/download/o2server-${VERSION}-linux-x86.zip",
 			"sha256": "${build_linux.sha}"
 			},
 			"macos": {
 			"system": "macos",
-			"name": "o2server-macos-${VERSION}",
+			"name": "o2server-${VERSION}-macos",
 			"fileName": "o2server-${VERSION}-macos.zip",
 			"fileSize": "${length_macos_mb}MB",
 			"updateTime": "${TODAY}",
@@ -109,7 +109,7 @@
 			},
 			"aix": {
 			"system": "aix",
-			"name": "o2server-aix-${VERSION}",
+			"name": "o2server-${VERSION}-aix",
 			"fileName": "o2server-${VERSION}-aix.zip",
 			"fileSize": "${length_aix_mb}MB",
 			"updateTime": "${TODAY}",
@@ -118,29 +118,29 @@
 			},
 			"raspberrypi": {
 			"system": "raspberrypi",
-			"name": "o2server-${VERSION}-raspberrypi.zip",
-			"fileName": "o2server-${VERSION}-raspberrypi.zip",
+			"name": "o2server-${VERSION}-raspi.zip",
+			"fileName": "o2server-${VERSION}-raspi.zip",
 			"fileSize": "${length_raspberrypi_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-raspberrypi.zip",
+			"url": "/download/o2server-${VERSION}-raspi.zip",
 			"sha256": "${build_raspberrypi.sha}"
 			},
-			"risc": {
-			"system": "risc",
-			"name": "o2server-${VERSION}-risc",
-			"fileName": "o2server-${VERSION}-risc.zip",
-			"fileSize": "${length_risc_mb}MB",
+			"mips": {
+			"system": "mips",
+			"name": "o2server-${VERSION}-linux-mips",
+			"fileName": "o2server-${VERSION}-linux-mips.zip",
+			"fileSize": "${length_mips_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-risc.zip",
-			"sha256": "${build_risc.sha}"
+			"url": "/download/o2server-${VERSION}-linux-mips.zip",
+			"sha256": "${build_mips.sha}"
 			},
 			"arm": {
 			"system": "arm",
-			"name": "o2server-${VERSION}-arm",
-			"fileName": "o2server-${VERSION}-arm.zip",
+			"name": "o2server-${VERSION}-linux-arm",
+			"fileName": "o2server-${VERSION}-linux-arm.zip",
 			"fileSize": "${length_arm_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-arm.zip",
+			"url": "/download/o2server-${VERSION}-linux-arm.zip",
 			"sha256": "${build_arm.sha}"
 			},
 			"jvm_windows": {}
@@ -151,7 +151,7 @@
 			"publishTime": "${TODAY}",
 			"windows": {
 			"system": "windows",
-			"name": "o2server-windows-${VERSION}",
+			"name": "o2server-${VERSION}-windows",
 			"fileName": "o2server-${VERSION}-windows.zip",
 			"fileSize": "${length_win_mb}MB",
 			"updateTime": "${TODAY}",
@@ -160,16 +160,16 @@
 			},
 			"linux": {
 			"system": "linux",
-			"name": "o2server-linux-${VERSION}",
-			"fileName": "o2server-${VERSION}-linux.zip",
+			"name": "o2server-${VERSION}-linux-x86",
+			"fileName": "o2server-${VERSION}-linux-x86.zip",
 			"fileSize": "${length_linux_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-linux.zip",
+			"url": "/download/o2server-${VERSION}-linux-x86.zip",
 			"sha256": "${build_linux.sha}"
 			},
 			"macos": {
 			"system": "macos",
-			"name": "o2server-macos-${VERSION}",
+			"name": "o2server-${VERSION}-macos",
 			"fileName": "o2server-${VERSION}-macos.zip",
 			"fileSize": "${length_macos_mb}MB",
 			"updateTime": "${TODAY}",
@@ -178,7 +178,7 @@
 			},
 			"aix": {
 			"system": "aix",
-			"name": "o2server-aix-${VERSION}",
+			"name": "o2server-${VERSION}-aix",
 			"fileName": "o2server-${VERSION}-aix.zip",
 			"fileSize": "${length_aix_mb}MB",
 			"updateTime": "${TODAY}",
@@ -187,29 +187,29 @@
 			},
 			"raspberrypi": {
 			"system": "raspberrypi",
-			"name": "o2server-${VERSION}-raspberrypi.zip",
-			"fileName": "o2server-${VERSION}-raspberrypi.zip",
+			"name": "o2server-${VERSION}-raspi.zip",
+			"fileName": "o2server-${VERSION}-raspi.zip",
 			"fileSize": "${length_raspberrypi_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-raspberrypi.zip",
+			"url": "/download/o2server-${VERSION}-raspi.zip",
 			"sha256": "${build_raspberrypi.sha}"
 			},
-			"risc": {
-			"system": "risc",
-			"name": "o2server-${VERSION}-risc",
-			"fileName": "o2server-${VERSION}-risc.zip",
-			"fileSize": "${length_risc_mb}MB",
+			"mips": {
+			"system": "mips",
+			"name": "o2server-${VERSION}-linux-mips",
+			"fileName": "o2server-${VERSION}-linux-mips.zip",
+			"fileSize": "${length_mips_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-risc.zip",
-			"sha256": "${build_risc.sha}"
+			"url": "/download/o2server-${VERSION}-linux-mips.zip",
+			"sha256": "${build_mips.sha}"
 			},
 			"arm": {
 			"system": "arm",
-			"name": "o2server-${VERSION}-arm",
-			"fileName": "o2server-${VERSION}-arm.zip",
+			"name": "o2server-${VERSION}-linux-arm",
+			"fileName": "o2server-${VERSION}-linux-arm.zip",
 			"fileSize": "${length_arm_mb}MB",
 			"updateTime": "${TODAY}",
-			"url": "/download/o2server-${VERSION}-arm.zip",
+			"url": "/download/o2server-${VERSION}-linux-arm.zip",
 			"sha256": "${build_arm.sha}"
 			},
 			"source":{
@@ -220,7 +220,7 @@
 			}
 			}</echo>
 	</target>
-	<target name="default_zip" depends="version_o2,zip_windows,zip_linux,zip_macos,zip_aix,zip_raspberrypi,zip_risc,zip_arm" />
+	<target name="default_zip" depends="version_o2,zip_windows,zip_linux,zip_macos,zip_aix,zip_raspberrypi,zip_mips,zip_arm" />
 	<target name="version_o2">
 		<tstamp>
 			<format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss"/>
@@ -249,7 +249,7 @@
 		</zip>
 	</target>
 	<target name="zip_linux">
-		<zip encoding="utf-8" destfile="${preName}-${VERSION}-linux.zip" update="false">
+		<zip encoding="utf-8" destfile="${preName}-${VERSION}-linux-x86.zip" update="false">
 			<zipfileset dir="${targetdir}/o2server" filemode="777" dirmode="777" encoding="utf-8" prefix="o2server">
 				<include name="commons/"/>
 				<include name="configSample/"/>
@@ -309,7 +309,7 @@
 		</zip>
 	</target>
 	<target name="zip_raspberrypi">
-		<zip encoding="utf-8" destfile="${preName}-${VERSION}-raspberrypi.zip" update="false">
+		<zip encoding="utf-8" destfile="${preName}-${VERSION}-raspi.zip" update="false">
 			<zipfileset dir="${targetdir}/o2server" filemode="777" dirmode="777" encoding="utf-8" prefix="o2server">
 				<include name="commons/"/>
 				<include name="configSample/"/>
@@ -321,15 +321,15 @@
 				<include name="version.o2"/>
 				<include name="console.jar"/>
 				<include name="jvm/raspberrypi/"/>
-				<include name="start_raspberrypi.sh"/>
-				<include name="start_raspberrypi_debug.sh"/>
-				<include name="console_raspberrypi.sh"/>
-				<include name="stop_raspberrypi.sh"/>
+				<include name="start_raspi.sh"/>
+				<include name="start_raspi_debug.sh"/>
+				<include name="console_raspi.sh"/>
+				<include name="stop_raspi.sh"/>
 			</zipfileset>
 		</zip>
 	</target>
-	<target name="zip_risc">
-		<zip encoding="utf-8" destfile="${preName}-${VERSION}-risc.zip" update="false">
+	<target name="zip_mips">
+		<zip encoding="utf-8" destfile="${preName}-${VERSION}-linux-mips.zip" update="false">
 			<zipfileset dir="${targetdir}/o2server" filemode="777" dirmode="777" encoding="utf-8" prefix="o2server">
 				<include name="commons/"/>
 				<include name="configSample/"/>
@@ -340,16 +340,16 @@
 				<include name="index.html"/>
 				<include name="version.o2"/>
 				<include name="console.jar"/>
-				<include name="jvm/risc/"/>
-				<include name="start_risc.sh"/>
-				<include name="start_risc_debug.sh"/>
-				<include name="console_risc.sh"/>
-				<include name="stop_risc.sh"/>
+				<include name="jvm/mips/"/>
+				<include name="start_mips.sh"/>
+				<include name="start_mips_debug.sh"/>
+				<include name="console_mips.sh"/>
+				<include name="stop_mips.sh"/>
 			</zipfileset>
 		</zip>
 	</target>
 	<target name="zip_arm">
-		<zip encoding="utf-8" destfile="${preName}-${VERSION}-arm.zip" update="false">
+		<zip encoding="utf-8" destfile="${preName}-${VERSION}-linux-arm.zip" update="false">
 			<zipfileset dir="${targetdir}/o2server" filemode="777" dirmode="777" encoding="utf-8" prefix="o2server">
 				<include name="commons/"/>
 				<include name="configSample/"/>
@@ -368,4 +368,4 @@
 			</zipfileset>
 		</zip>
 	</target>
-</project>
+</project>

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

@@ -36,7 +36,8 @@
 
     <application
         android:name=".O2App"
-        android:allowBackup="true"
+        android:allowBackup="false"
+        tools:replace="android:allowBackup"
         android:hardwareAccelerated="true"
         android:icon="@mipmap/logo"
         android:label="@string/app_name"

+ 2 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseMVPActivity.kt

@@ -2,6 +2,7 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 
 import android.content.Context
 import android.os.Bundle
+import android.view.WindowManager
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.Toolbar
 import android.widget.TextView
@@ -50,6 +51,7 @@ abstract class BaseMVPActivity<in V: BaseView, T: BasePresenter<V>>: AppCompatAc
         super.onCreate(savedInstanceState)
         beforeSetContentView()
         setContentView(layoutResId())
+        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         // 沉浸式状态栏
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
 

+ 2 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2Activity.kt

@@ -1,6 +1,7 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 
 import android.os.Bundle
+import android.view.WindowManager
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.Toolbar
 import android.widget.TextView
@@ -37,6 +38,7 @@ abstract class BaseO2Activity : AppCompatActivity() {
         super.onCreate(savedInstanceState)
         beforeSetContentView()
         setContentView(layoutResId())
+        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         // 沉浸式状态栏
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
         afterSetContentView(savedInstanceState)

+ 2 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2BindActivity.kt

@@ -1,6 +1,7 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 
 import android.os.Bundle
+import android.view.WindowManager
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.Toolbar
 import android.widget.TextView
@@ -37,6 +38,7 @@ abstract class BaseO2BindActivity : AppCompatActivity() {
         super.onCreate(savedInstanceState)
         beforeSetContentView()
         bindView(savedInstanceState)
+        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         // 沉浸式状态栏
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
         afterSetContentView(savedInstanceState)

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

@@ -16,6 +16,7 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.bbs.main.BBSMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.calendar.CalendarMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.clouddrive.CloudDriveActivity
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.clouddrive.v2.CloudDiskActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.cms.index.CMSIndexActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.meeting.main.MeetingMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.webview.TaskWebViewActivity
@@ -122,7 +123,8 @@ class O2InstantMessageActivity : BaseMVPActivity<O2InstantMessageContract.View,
             }
         }else if (type.startsWith("attachment_")) {
             setLinkStyle(textView) {
-                go<CloudDriveActivity>()
+//                go<CloudDriveActivity>()
+                go<CloudDiskActivity>()
             }
         }else if (type.startsWith("calendar_")) {
             setLinkStyle(textView) {

+ 17 - 13
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/launch/LaunchActivity.kt

@@ -120,21 +120,25 @@ class LaunchActivity : BaseMVPActivity<LaunchContract.View, LaunchContract.Prese
     fun start() {
         tv_launch_status.text = getString(R.string.launch_start) //开始启动
         circleProgressBar_launch.visible()
-        PermissionRequester(this)
-                .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
-                .o2Subscribe {
-                    onNext { (granted, shouldShowRequestPermissionRationale, deniedPermissions) ->
-                        Log.d("LaunchActivity", "granted:$granted, show:$shouldShowRequestPermissionRationale, deniedList:$deniedPermissions")
-                        if (!granted) {
-                            O2DialogSupport.openAlertDialog(this@LaunchActivity, "非常抱歉,应用需要存储权限才能正常运行, 马上去设置", { permissionSetting() })
-                        } else {
-                            checkNetwork()
+        if (CheckRoot.isDeviceRooted()) {
+            O2DialogSupport.openAlertDialog(this, "当前是Root环境,App禁止使用!")
+        }else {
+            PermissionRequester(this)
+                    .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+                    .o2Subscribe {
+                        onNext { (granted, shouldShowRequestPermissionRationale, deniedPermissions) ->
+                            Log.d("LaunchActivity", "granted:$granted, show:$shouldShowRequestPermissionRationale, deniedList:$deniedPermissions")
+                            if (!granted) {
+                                O2DialogSupport.openAlertDialog(this@LaunchActivity, "非常抱歉,应用需要存储权限才能正常运行, 马上去设置", { permissionSetting() })
+                            } else {
+                                checkNetwork()
+                            }
+                        }
+                        onError { e, _ ->
+                            Log.e("LaunchActivity", "检查权限出错", e)
                         }
                     }
-                    onError { e, _ ->
-                        Log.e("LaunchActivity", "检查权限出错", e)
-                    }
-                }
+        }
     }
 
     /**

+ 153 - 16
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginActivity.kt

@@ -1,27 +1,30 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 
 import android.content.Context
+import android.graphics.BitmapFactory
 import android.media.AudioManager
 import android.media.MediaPlayer
 import android.os.Bundle
-import androidx.core.content.ContextCompat
+import android.os.Looper
 import android.text.InputType
 import android.text.TextUtils
 import android.view.KeyEvent
 import android.view.View
 import android.view.WindowManager
 import android.view.inputmethod.InputMethodManager
+import android.widget.Toast
+import androidx.core.content.ContextCompat
 import kotlinx.android.synthetic.main.activity_login.*
 import net.muliba.changeskin.FancySkinManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.bind.BindPhoneActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.main.MainActivity
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.CaptchaImgData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginModeData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginWithCaptchaForm
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.BitmapUtil
-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.utils.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.BioConstants
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.BiometryManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.OnBiometryAuthCallback
@@ -85,11 +88,21 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
     private var loginType = 0 // 0默认的用户名验证码登录 1用户名密码登录
     private var canBioAuth = false //是否有指纹认证
 
+    //验证码
+    private var useCaptcha = true
+    private var captcha : CaptchaImgData? = null
 
-    override fun afterSetContentView(savedInstanceState: Bundle?) {
-        receivePhone = intent.extras?.getString(REQUEST_PHONE_KEY) ?: ""
 
 
+    override fun afterSetContentView(savedInstanceState: Bundle?) {
+        //获取加密key
+        mPresenter.getRSAPublicKey()
+        //获取图片验证码
+        mPresenter.getCaptcha()
+        //
+        mPresenter.getLoginMode()
+
+        receivePhone = intent.extras?.getString(REQUEST_PHONE_KEY) ?: ""
         setDefaultLogo()
         login_edit_username_id.setText(receivePhone)
         tv_login_copyright.text = getString(R.string.copy_right).plus(" ")
@@ -114,23 +127,29 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
                 view_login_password_bottom.setBackgroundColor(FancySkinManager.instance().getColor(this, R.color.z_color_input_line_blur))
             }
         }
-
-
+        edit_login_captcha_input.setOnFocusChangeListener { _, hasFocus ->
+            if (hasFocus) {
+                view_login_captcha_input_bottom.setBackgroundColor(FancySkinManager.instance().getColor(this, R.color.z_color_input_line_focus))
+            }else {
+                view_login_captcha_input_bottom.setBackgroundColor(FancySkinManager.instance().getColor(this, R.color.z_color_input_line_blur))
+            }
+        }
 
         btn_login_submit.setOnClickListener(this)
         btn_bio_auth_login.setOnClickListener(this)
         tv_user_fallback_btn.setOnClickListener(this)
         tv_bioauth_btn.setOnClickListener(this)
+        image_login_captcha.setOnClickListener(this)
 
         //是否开启了指纹识别登录
         checkBioAuthLogin()
         if (BuildConfig.InnerServer) {
             login_edit_password_id.setHint(R.string.activity_login_password)
             login_edit_password_id.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
-//            InputType.TYPE_TEXT_VARIATION_PASSWORD
             button_login_phone_code.gone()
             tv_rebind_btn.gone()
             tv_bioauth_btn.gone()
+            ll_login_captcha.visible()
         }else {
             tv_bioauth_btn.visible()
             login_edit_password_id.setHint(R.string.login_code)
@@ -139,6 +158,8 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
             button_login_phone_code.setOnClickListener(this)
             tv_rebind_btn.visible()
             tv_rebind_btn.setOnClickListener(this)
+            //不需要图片验证码
+            ll_login_captcha.gone()
         }
 
     }
@@ -166,6 +187,10 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
 
     override fun onResume() {
         super.onResume()
+        //清除用户名密码
+        login_edit_username_id.setText("")
+        login_edit_password_id.setText("")
+        edit_login_captcha_input.setText("")
 
         playBeep = true
         val audioService = getSystemService(Context.AUDIO_SERVICE) as AudioManager
@@ -175,6 +200,26 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
         initBeepSound()
     }
 
+    override fun onStop() {
+        super.onStop()
+
+        //Activity反劫持检测工具
+        Thread(Runnable { // 白名单
+            val safe = AntiHijackingUtil.checkActivity(applicationContext)
+            // 系统桌面
+            val isHome = AntiHijackingUtil.isHome(applicationContext)
+            // 锁屏操作
+            val isReflectScreen = AntiHijackingUtil.isReflectScreen(applicationContext)
+            // 判断程序是否当前显示
+            if (!safe && !isHome && !isReflectScreen) {
+                Looper.prepare()
+                Toast.makeText(applicationContext, R.string.activity_safe_warning,
+                        Toast.LENGTH_LONG).show()
+                Looper.loop()
+            }
+        }).start()
+    }
+
     override fun onDestroy() {
         super.onDestroy()
         countDownHelper.destroy()
@@ -202,6 +247,10 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
                     reBindService()
                 })
             }
+            R.id.image_login_captcha -> {
+                showLoadingDialog()
+                mPresenter.getCaptcha()
+            }
         }
     }
 
@@ -228,11 +277,17 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
     }
     private  fun changeLoginType() {
         if (loginType == 0) {
+            if (useCaptcha) {
+                ll_login_captcha.visible()
+            }else {
+                ll_login_captcha.gone()
+            }
             login_edit_password_id.setHint(R.string.activity_login_password)
             login_edit_password_id.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD
             button_login_phone_code.gone()
             loginType = 1
         }else {
+            ll_login_captcha.gone()
             login_edit_password_id.setHint(R.string.login_code)
             login_edit_password_id.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_NORMAL
             button_login_phone_code.visible()
@@ -242,6 +297,32 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
     }
 
 
+    override fun loginMode(mode: LoginModeData?) {
+        if (mode != null) {
+            useCaptcha = mode.captchaLogin
+            if (useCaptcha) {
+                ll_login_captcha.visible()
+            }else {
+                ll_login_captcha.gone()
+            }
+        }
+    }
+
+    override fun showCaptcha(data: CaptchaImgData) {
+        hideLoadingDialog()
+        captcha = data
+         val stream = Base64ImageUtil.generateBase642Inputstream(data.image)
+        if (stream != null) {
+            image_login_captcha.setImageBitmap(BitmapFactory.decodeStream(stream))
+        }
+    }
+
+    override fun getCaptchaError(err: String) {
+        hideLoadingDialog()
+        //todo 图片验证码没有
+        XLog.error(err)
+    }
+
     override fun loginSuccess(data: AuthenticationInfoJson) {
         if (login_main_biometry.visibility == View.VISIBLE) {
             playBeepSound()
@@ -280,16 +361,72 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
             XToast.toastShort(this, "$label 不能为空!")
             return
         }
-        showLoadingDialog()
-        if (BuildConfig.InnerServer) {
-            mPresenter.loginByPassword(credential, code)
+        if (useCaptcha) {
+            if (BuildConfig.InnerServer) {
+//                mPresenter.loginByPassword(credential, code)
+                val captchaCode = edit_login_captcha_input.text.toString()
+                if (TextUtils.isEmpty(captchaCode)) {
+                    XToast.toastShort(this, "图片验证码 不能为空!")
+                    return
+                }
+                if (captcha == null) {
+                    XToast.toastShort(this, "图片验证码 不能为空!")
+                    return
+                }
+                val form = LoginWithCaptchaForm()
+                form.credential = credential
+                form.password = code
+                form.captcha = captcha!!.id
+                form.captchaAnswer = captchaCode
+                showLoadingDialog()
+                mPresenter.loginWithCaptcha(form)
+            }else {
+                if (loginType == 0) {
+                    showLoadingDialog()
+                    mPresenter.login(credential, code)
+                }else {
+//                    mPresenter.loginByPassword(credential, code)
+                    val captchaCode = edit_login_captcha_input.text.toString()
+                    if (TextUtils.isEmpty(captchaCode)) {
+                        XToast.toastShort(this, "图片验证码 不能为空!")
+                        return
+                    }
+                    if (captcha == null) {
+                        XToast.toastShort(this, "图片验证码 不能为空!")
+                        return
+                    }
+                    val form = LoginWithCaptchaForm()
+                    form.credential = credential
+                    form.password = code
+                    form.captcha = captcha!!.id
+                    form.captchaAnswer = captchaCode
+                    showLoadingDialog()
+                    mPresenter.loginWithCaptcha(form)
+                }
+            }
         }else {
-            if (loginType == 0) {
-                mPresenter.login(credential, code)
+            if (BuildConfig.InnerServer) {
+//                mPresenter.loginByPassword(credential, code)
+                val form = LoginWithCaptchaForm()
+                form.credential = credential
+                form.password = code
+                showLoadingDialog()
+                mPresenter.loginWithCaptcha(form)
             }else {
-                mPresenter.loginByPassword(credential, code)
+                if (loginType == 0) {
+                    showLoadingDialog()
+                    mPresenter.login(credential, code)
+                }else {
+//                    mPresenter.loginByPassword(credential, code)
+                    val form = LoginWithCaptchaForm()
+                    form.credential = credential
+                    form.password = code
+                    showLoadingDialog()
+                    mPresenter.loginWithCaptcha(form)
+                }
             }
         }
+
     }
 
 

+ 26 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginContract.kt

@@ -2,6 +2,9 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 
 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.CaptchaImgData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginModeData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginWithCaptchaForm
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
 
 /**
@@ -13,11 +16,19 @@ object LoginContract {
         fun getCodeError()
         fun loginSuccess(data: AuthenticationInfoJson)
         fun loginFail()
+        fun showCaptcha(data: CaptchaImgData)
+        fun getCaptchaError(err: String)
+        fun loginMode(mode: LoginModeData?)
     }
 
     interface Presenter: BasePresenter<View> {
 
 
+        /**
+         * 登录方式
+         */
+        fun getLoginMode()
+
         /**
          * 获取验证码
          * @param value 用户名或者手机号码
@@ -37,6 +48,21 @@ object LoginContract {
 
         fun ssoLogin(userId: String)
 
+        /**
+         * 获取图片验证码
+         */
+        fun getCaptcha()
+
+
+        /**
+         * 图片验证码登录
+         */
+        fun loginWithCaptcha(form: LoginWithCaptchaForm)
+
+        /**
+         *
+         */
+        fun getRSAPublicKey()
 
     }
 }

+ 85 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginPresenter.kt

@@ -1,11 +1,14 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 
 
+import android.text.TextUtils
 import net.muliba.accounting.app.ExceptionHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginWithCaptchaForm
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.Base64ImageUtil
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.CryptRSA
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import rx.android.schedulers.AndroidSchedulers
@@ -17,8 +20,90 @@ import rx.schedulers.Schedulers
 
 class LoginPresenter : BasePresenterImpl<LoginContract.View>(), LoginContract.Presenter {
 
+    //rsa加密公钥
+    private var publicKey: String = ""
 
 
+    override fun getLoginMode() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.loginMode()
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            mView?.loginMode(it.data)
+                        }
+                        onError { e, _ ->
+                            XLog.error("", e)
+                            mView?.loginMode(null)
+                        }
+                    }
+        }
+    }
+
+    override fun getCaptcha() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.getCaptchaCodeImg(120, 50)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            if (it.data != null) {
+                                mView?.showCaptcha(it.data)
+                            }else {
+                                mView?.getCaptchaError("没有获取到图片验证码")
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("获取图片验证码错误,", e)
+                            mView?.getCaptchaError("没有获取到图片验证码")
+                        }
+                    }
+        }
+    }
+
+    override fun loginWithCaptcha(form: LoginWithCaptchaForm) {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            //加密
+            if (!TextUtils.isEmpty(publicKey)) {
+                XLog.debug("key:$publicKey")
+                val newPwd = CryptRSA.rsaEncryptByPublicKey(form.password, publicKey)
+                if (!TextUtils.isEmpty(newPwd)) {
+                    form.password = newPwd
+                    form.isEncrypted = "y"
+                    XLog.debug("加密成功。。。。。$newPwd")
+                }
+            }
+            service.loginWithCaptchaCode(form)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(ResponseHandler { data -> mView?.loginSuccess(data) },
+                            ExceptionHandler(mView?.getContext()) { e ->
+                                XLog.error("", e)
+                                mView?.loginFail()
+                            })
+        }
+    }
+
+    override fun getRSAPublicKey() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.getRSAPublicKey()
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            if (it.data!=null) {
+                                publicKey = it.data.publicKey
+                                XLog.debug("public key is ok.lllll ")
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("public key is error ", e)
+                        }
+                    }
+        }
+    }
+
     override fun getVerificationCode(value: String) {
         getAssembleAuthenticationService(mView?.getContext())?.let { service ->
             service.getPhoneCode(value)

+ 2 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexFragment.kt

@@ -81,7 +81,8 @@ class IndexFragment : BaseMVPViewPagerFragment<IndexContract.View, IndexContract
                 ApplicationEnum.READCOMPLETED.key -> activity.go<ReadCompletedListActivity>()
                 ApplicationEnum.BBS.key -> activity.go<BBSMainActivity>()
                 ApplicationEnum.CMS.key -> activity.go<CMSIndexActivity>()
-                ApplicationEnum.YUNPAN.key -> activity.go<CloudDriveActivity>()
+                ApplicationEnum.YUNPAN.key -> activity.go<CloudDiskActivity>()
+//                ApplicationEnum.YUNPAN.key -> activity.go<CloudDriveActivity>()
                 ApplicationEnum.clouddisk.key -> activity.go<CloudDiskActivity>()
                 ApplicationEnum.MEETING.key -> activity.go<MeetingMainActivity>()
                 ApplicationEnum.ATTENDANCE.key -> activity.go<AttendanceMainActivity>()

+ 4 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexPortalFragment.kt

@@ -114,7 +114,10 @@ class IndexPortalFragment : BaseMVPViewPagerFragment<IndexPortalContract.View, I
     }
 
     override fun lazyLoad() {
-
+        //页面显示的时候调用一个js方法 这个方法可以用来刷新数据之类的
+        web_view_portal_content.evaluateJavascript("window.o2Reload()") { value ->
+            XLog.info("执行o2Reload , result: $value")
+        }
     }
 
     override fun loadCmsCategoryListByAppId(categoryList: List<CMSCategoryInfoJson>) {

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

@@ -35,10 +35,10 @@ class MyAppPresenter : BasePresenterImpl<MyAppContract.View>(), MyAppContract.Pr
                         obj.appTitle = it.name
                         result.add(obj)
                     }
-                    val newCloudDiskApp = MyAppListObject()
-                    newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
-                    newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
-                    result.add(newCloudDiskApp)
+//                    val newCloudDiskApp = MyAppListObject()
+//                    newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
+//                    newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
+//                    result.add(newCloudDiskApp)
                     service.findAllPortalList()
                 }
                 ?.flatMap { list ->
@@ -66,10 +66,10 @@ class MyAppPresenter : BasePresenterImpl<MyAppContract.View>(), MyAppContract.Pr
                                             obj.appTitle = it.name
                                             result.add(obj)
                                         }
-                                        val newCloudDiskApp = MyAppListObject()
-                                        newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
-                                        newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
-                                        result.add(newCloudDiskApp)
+//                                        val newCloudDiskApp = MyAppListObject()
+//                                        newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
+//                                        newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
+//                                        result.add(newCloudDiskApp)
                                         portalList.filter { portal -> portal.enable }.map {
                                             val obj = MyAppListObject()
                                             obj.appId = it.id

+ 1 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityActivity.kt

@@ -23,6 +23,7 @@ class AccountSecurityActivity : BaseMVPActivity<AccountSecurityContract.View, Ac
     override var mPresenter: AccountSecurityContract.Presenter = AccountSecurityPresenter()
     override fun layoutResId(): Int  = R.layout.activity_account_security
     override fun afterSetContentView(savedInstanceState: Bundle?) {
+        mPresenter.getRSAPublicKey()
         setupToolBar(getString(R.string.title_activity_account_security), true)
 
         account_name_id.text = O2SDKManager.instance().cName

+ 5 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityContract.kt

@@ -15,5 +15,10 @@ object AccountSecurityContract {
     interface Presenter : BasePresenter<View> {
         fun logout(deviceId:String)
         fun updateMyPassword(old: String, newPwd: String, newPwdConfirm: String)
+        /**
+         *
+         */
+        fun getRSAPublicKey()
+
     }
 }

+ 42 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityPresenter.kt

@@ -1,11 +1,13 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.security
 
+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.ResponseHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.exception.O2ResponseException
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.IdData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.person.PersonPwdForm
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.CryptRSA
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import rx.android.schedulers.AndroidSchedulers
@@ -13,6 +15,28 @@ import rx.schedulers.Schedulers
 
 class AccountSecurityPresenter : BasePresenterImpl<AccountSecurityContract.View>(), AccountSecurityContract.Presenter {
 
+    //rsa加密公钥
+    private var publicKey: String = ""
+
+
+    override fun getRSAPublicKey() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.getRSAPublicKey()
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            if (it.data!=null) {
+                                publicKey = it.data.publicKey
+                                XLog.debug("public key is ok.lllll ")
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("public key is error ", e)
+                        }
+                    }
+        }
+    }
 
     override fun logout(deviceId: String) {
         getAssembleAuthenticationService(mView?.getContext())?.let { service->
@@ -29,6 +53,24 @@ class AccountSecurityPresenter : BasePresenterImpl<AccountSecurityContract.View>
         val service = getAssemblePersonalApi(mView?.getContext())
         if (service != null) {
             val form = PersonPwdForm(old, newPwd, newPwdConfirm)
+
+            if (!TextUtils.isEmpty(publicKey)) {
+                XLog.debug("key:$publicKey")
+                val newOld = CryptRSA.rsaEncryptByPublicKey(old, publicKey)
+                if (!TextUtils.isEmpty(newOld)) {
+                    form.oldPassword = newOld
+                }
+                val newNewPwd = CryptRSA.rsaEncryptByPublicKey(newPwd, publicKey)
+                if (!TextUtils.isEmpty(newNewPwd)) {
+                    form.newPassword = newNewPwd
+                }
+                val newNewPwdConfirm = CryptRSA.rsaEncryptByPublicKey(newPwdConfirm, publicKey)
+                if (!TextUtils.isEmpty(newNewPwdConfirm)) {
+                    form.confirmPassword = newNewPwdConfirm
+                }
+                form.isEncrypted = "y"
+            }
+
             service.modifyCurrentPersonPassword(form)
                     .subscribeOn(Schedulers.io())
                     .observeOn(AndroidSchedulers.mainThread())

+ 151 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/AntiHijackingUtil.java

@@ -0,0 +1,151 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils;
+
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Description: Activity反劫持检测工具
+ * author: zs
+ * Date: 2018/7/8 16:31
+ */
+public class AntiHijackingUtil {
+    public static final String TAG = "AntiHijackingUtil";
+
+    /**
+     * 检测当前Activity是否安全
+     */
+    public static boolean checkActivity(Context context) {
+        PackageManager pm = context.getPackageManager();
+        // 查询所有已经安装的应用程序
+        List<ApplicationInfo> listAppcations =
+                pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
+        Collections.sort(listAppcations, new ApplicationInfo.DisplayNameComparator(pm));// 排序
+
+        List<String> safePackages = new ArrayList<>();
+        for (ApplicationInfo app : listAppcations) {// 这个排序必须有.
+            if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                safePackages.add(app.packageName);
+            }
+        }
+        // 得到所有的系统程序包名放进白名单里面.
+        ActivityManager activityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        String runningActivityPackageName;
+        int sdkVersion;
+        try {
+            sdkVersion = Integer.valueOf(android.os.Build.VERSION.SDK);
+        } catch (NumberFormatException e) {
+            sdkVersion = 0;
+        }
+        if (sdkVersion >= 21) {// 获取系统api版本号,如果是5x系统就用这个方法获取当前运行的包名
+            runningActivityPackageName = getCurrentPkgName(context);
+        } else {
+            runningActivityPackageName =
+                    activityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
+        }
+        // 如果是4x及以下,用这个方法.
+        if (runningActivityPackageName != null) {
+            // 有些情况下在5x的手机中可能获取不到当前运行的包名,所以要非空判断。
+            if (runningActivityPackageName.equals(context.getPackageName())) {
+                return true;
+            }
+            // 白名单比对
+            for (String safePack : safePackages) {
+                if (safePack.equals(runningActivityPackageName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static String getCurrentPkgName(Context context) {
+        // 5x系统以后利用反射获取当前栈顶activity的包名.
+        ActivityManager.RunningAppProcessInfo currentInfo = null;
+        Field field = null;
+        int START_TASK_TO_FRONT = 2;
+        String pkgName = null;
+        try {
+            // 通过反射获取进程状态字段.
+            field = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        List appList = am.getRunningAppProcesses();
+        ActivityManager.RunningAppProcessInfo app;
+        for (int i = 0; i < appList.size(); i++) {
+            //ActivityManager.RunningAppProcessInfo app : appList
+            app = (ActivityManager.RunningAppProcessInfo) appList.get(i);
+            //表示前台运行进程.
+            if (app.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                Integer state = null;
+                try {
+                    state = field.getInt(app);// 反射调用字段值的方法,获取该进程的状态.
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                // 根据这个判断条件从前台中获取当前切换的进程对象
+                if (state != null && state == START_TASK_TO_FRONT) {
+                    currentInfo = app;
+                    break;
+                }
+            }
+        }
+        if (currentInfo != null) {
+            pkgName = currentInfo.processName;
+        }
+        return pkgName;
+    }
+
+    /**
+     * 判断当前是否在桌面
+     *
+     * @param context 上下文
+     */
+    public static boolean isHome(Context context) {
+        ActivityManager mActivityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        List<ActivityManager.RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
+        return getHomes(context).contains(rti.get(0).topActivity.getPackageName());
+    }
+
+    /**
+     * 获得属于桌面的应用的应用包名称
+     *
+     * @return 返回包含所有包名的字符串列表
+     */
+    private static List<String> getHomes(Context context) {
+        List<String> names = new ArrayList<String>();
+        PackageManager packageManager = context.getPackageManager();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
+                PackageManager.MATCH_DEFAULT_ONLY);
+        for (ResolveInfo ri : resolveInfo) {
+            names.add(ri.activityInfo.packageName);
+        }
+        return names;
+    }
+
+    /**
+     * 判断当前是否在锁屏再解锁状态
+     *
+     * @param context 上下文
+     */
+    public static boolean isReflectScreen(Context context) {
+        KeyguardManager mKeyguardManager =
+                (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+        return mKeyguardManager.inKeyguardRestrictedInputMode();
+    }
+}

+ 200 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CheckRoot.java

@@ -0,0 +1,200 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils;
+
+/**
+ * Created by fancyLou on 2020-09-28.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+
+public class CheckRoot {
+    private static String LOG_TAG = CheckRoot.class.getName();
+
+    public static boolean isDeviceRooted() {
+        if (checkDeviceDebuggable()) {
+            return true;
+        }//check buildTags
+        if (checkSuperuserApk()) {
+            return true;
+        }//Superuser.apk
+        //if (checkRootPathSU()){return true;}//find su in some path
+        //if (checkRootWhichSU()){return true;}//find su use 'which'
+        if (checkBusybox()) {
+            return true;
+        }//find su use 'which'
+        if (checkAccessRootData()) {
+            return true;
+        }//find su use 'which'
+        if (checkGetRootAuth()) {
+            return true;
+        }//exec su
+
+        return false;
+    }
+
+    public static boolean checkDeviceDebuggable() {
+        String buildTags = android.os.Build.TAGS;
+        if (buildTags != null && buildTags.contains("test-keys")) {
+            Log.i(LOG_TAG, "buildTags=" + buildTags);
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean checkSuperuserApk() {
+        try {
+            File file = new File("/system/app/Superuser.apk");
+            if (file.exists()) {
+                Log.i(LOG_TAG, "/system/app/Superuser.apk exist");
+                return true;
+            }
+        } catch (Exception e) {
+        }
+        return false;
+    }
+
+    public static synchronized boolean checkGetRootAuth() {
+        Process process = null;
+        DataOutputStream os = null;
+        try {
+            Log.i(LOG_TAG, "to exec su");
+            process = Runtime.getRuntime().exec("su");
+            os = new DataOutputStream(process.getOutputStream());
+            os.writeBytes("exit\n");
+            os.flush();
+            int exitValue = process.waitFor();
+            Log.i(LOG_TAG, "exitValue=" + exitValue);
+            if (exitValue == 0) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception e) {
+            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
+                    + e.getMessage());
+            return false;
+        } finally {
+            try {
+                if (os != null) {
+                    os.close();
+                }
+                process.destroy();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static synchronized boolean checkBusybox() {
+        try {
+            Log.i(LOG_TAG, "to exec busybox df");
+            String[] strCmd = new String[]{"busybox", "df"};
+            ArrayList<String> execResult = executeCommand(strCmd);
+            if (execResult != null) {
+                Log.i(LOG_TAG, "execResult=" + execResult.toString());
+                return true;
+            } else {
+                Log.i(LOG_TAG, "execResult=null");
+                return false;
+            }
+        } catch (Exception e) {
+            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
+                    + e.getMessage());
+            return false;
+        }
+    }
+
+    public static ArrayList<String> executeCommand(String[] shellCmd) {
+        String line = null;
+        ArrayList<String> fullResponse = new ArrayList<String>();
+        Process localProcess = null;
+        try {
+            Log.i(LOG_TAG, "to shell exec which for find su :");
+            localProcess = Runtime.getRuntime().exec(shellCmd);
+        } catch (Exception e) {
+            return null;
+        }
+        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
+        BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
+        try {
+            while ((line = in.readLine()) != null) {
+                Log.i(LOG_TAG, "–> Line received: " + line);
+                fullResponse.add(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Log.i(LOG_TAG, "–> Full response was: " + fullResponse);
+        return fullResponse;
+    }
+
+    public static synchronized boolean checkAccessRootData() {
+        try {
+            Log.i(LOG_TAG, "to write /data");
+            String fileContent = "test_ok";
+            Boolean writeFlag = writeFile("/data/su_test", fileContent);
+            if (writeFlag) {
+                Log.i(LOG_TAG, "write ok");
+            } else {
+                Log.i(LOG_TAG, "write failed");
+            }
+
+            Log.i(LOG_TAG, "to read /data");
+            String strRead = readFile("/data/su_test");
+            Log.i(LOG_TAG, "strRead=" + strRead);
+            if (fileContent.equals(strRead)) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception e) {
+            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
+                    + e.getMessage());
+            return false;
+        }
+    }
+
+    //写文件
+    public static Boolean writeFile(String fileName, String message) {
+        try {
+            FileOutputStream fout = new FileOutputStream(fileName);
+            byte[] bytes = message.getBytes();
+            fout.write(bytes);
+            fout.close();
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    //读文件
+    public static String readFile(String fileName) {
+        File file = new File(fileName);
+        try {
+            FileInputStream fis = new FileInputStream(file);
+            byte[] bytes = new byte[1024];
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            int len;
+            while ((len = fis.read(bytes)) > 0) {
+                bos.write(bytes, 0, len);
+            }
+            String result = new String(bos.toByteArray());
+            Log.i(LOG_TAG, result);
+            return result;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}

+ 41 - 0
o2android/app/src/main/res/layout/activity_login.xml

@@ -153,6 +153,47 @@
                         android:background="@color/z_color_input_line_blur"
                         />
 
+                    <LinearLayout
+                        android:id="@+id/ll_login_captcha"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="10dp"
+                        android:orientation="horizontal">
+                        <LinearLayout
+                            android:layout_width="0dp"
+                            android:layout_weight="1"
+                            android:layout_height="match_parent"
+                            android:orientation="vertical">
+                            <net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.ClearTextEdit
+                                android:id="@+id/edit_login_captcha_input"
+                                android:layout_width="match_parent"
+                                android:layout_height="49dp"
+                                android:layout_gravity="center_vertical"
+                                android:background="@null"
+                                android:hint="@string/login_captcha"
+                                android:maxLines="1"
+                                android:inputType="number"
+                                android:textColor="@color/z_color_text_primary"
+                                android:textColorHint="@color/z_color_text_hint"
+                                android:textSize="13sp" />
+                            <View
+                                android:id="@+id/view_login_captcha_input_bottom"
+                                android:layout_width="match_parent"
+                                android:layout_height="1dp"
+                                android:background="@color/z_color_input_line_blur"
+                                />
+                        </LinearLayout>
+                        <ImageView
+                            android:id="@+id/image_login_captcha"
+                            android:layout_width="120dp"
+                            android:layout_height="50dp"
+                            android:scaleType="fitCenter"
+                            />
+
+                    </LinearLayout>
+
+
+
                     <Button
                         android:id="@+id/btn_login_submit"
                         android:layout_width="match_parent"

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

@@ -2,6 +2,7 @@
     <string name="app_name">O2OA</string>
     <string name="app_about">关于O2OA</string>
     <string name="app_name_about">O2OA</string>
+    <string name="activity_safe_warning">已切换至后台运行!</string>
     <string name="copy_right">&#169;</string>
     <string name="reserved">All right reserved.</string>
     <string name="version">版本:</string>
@@ -13,6 +14,8 @@
     <string name="bind_phone_choose_company">选择单位</string>
     <string name="app_error">应用异常</string>
 
+
+
     <string name="launch_start">准备中&#8230;</string>
     <string name="launch_network_is_not_connected">网络未连接,请检查网络连接情况!</string>
     <string name="launch_check_bind">正在连接O2云&#8230;</string>
@@ -112,6 +115,7 @@
     <string name="activity_login_username">用户名或手机号码</string>
     <string name="login_phone">输入手机号码</string>
     <string name="login_code">验证码</string>
+    <string name="login_captcha">图片验证码</string>
     <string name="activity_login_password">密码</string>
     <string name="activity_login_submit">登    录</string>
     <string name="activity_login_other">其他登录方式</string>

+ 2 - 2
o2android/gradle.properties

@@ -23,6 +23,6 @@ android.enableJetifier=true
 
 
 # o2
-o2.versionName=5.1.9
-o2.versionCode=119
+o2.versionName=5.2.0
+o2.versionCode=120
 

+ 2 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2.kt

@@ -114,6 +114,8 @@ object O2 {
     //////////////////////////////////SharedPreferences KEY /////////////////////////////////////////////////
 
     val PREFERENCE_FILE = "API_DISTRIBUTE_FILE"
+    val SECURITY_PREFERENCE_FILE = "API_DIST_FILE_SECURITY"
+    val SECURITY_IS_UPDATE = "SECURITY_IS_UPDATE"
     val PRE_ASSEMBLESJSON_KEY = "ASSEMBLESJSON_KEY"
     val PRE_WEBSERVERJSON_KEY = "WEBSERVERJSON_KEY"
     val PRE_CENTER_HOST_KEY = "PRE_CENTER_HOST_KEY"//中心服务器地址

+ 11 - 1
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2SDKManager.kt

@@ -7,6 +7,7 @@ import android.text.TextUtils
 import android.util.Log
 import com.google.gson.Gson
 import com.google.gson.GsonBuilder
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2.SECURITY_IS_UPDATE
 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.LaunchState
@@ -19,6 +20,7 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.portal.PortalData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.SharedPreferencesHelper
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.edit
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.security.SecuritySharedPreference
 import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
@@ -107,6 +109,13 @@ class O2SDKManager private constructor()  {
         //初始化RetrofitClient
         this.context = context
         spHelper = SharedPreferencesHelper(context)
+        //检查老的sp 是否要更新
+        val isUpdate = prefs().getBoolean(SECURITY_IS_UPDATE, false)
+        if (!isUpdate) {
+            Log.i(TAG, "过渡老的sp文件!")
+            prefs().handleTransition() //执行过渡程序把老的sp文件读取覆盖一下
+            prefs().edit().putBoolean(SECURITY_IS_UPDATE, true).apply()
+        }
 
         RetrofitClient.instance().init(context)
         cId = prefs().getString(CURRENT_PERSON_ID_KEY, "") ?: ""
@@ -132,8 +141,9 @@ class O2SDKManager private constructor()  {
 
     }
 
-    fun prefs(): SharedPreferences = spHelper.prefs()
+//    fun prefs(): SharedPreferences = spHelper.prefs()
 
+    fun prefs(): SecuritySharedPreference = spHelper.securityPrefs()
 
     /**
      * 启动  整个启动过程,检查绑定 连接中心服务器 下载配置 登录

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

@@ -1,8 +1,6 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.service
 
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.ApiResponse
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.IdData
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.ValueData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
 import retrofit2.http.*
 import rx.Observable
@@ -15,6 +13,13 @@ import rx.Observable
 
 interface OrgAssembleAuthenticationService{
 
+
+    /**
+     * 登录状态
+     */
+    @GET("jaxrs/authentication/mode")
+    fun loginMode(): Observable<ApiResponse<LoginModeData>>
+
     /**
      * 登陆
      * @param json
@@ -62,6 +67,21 @@ interface OrgAssembleAuthenticationService{
     fun getPhoneCode(@Path("credential") credential: String): Observable<ApiResponse<ValueData>>
 
 
+    /**
+     * 获取图片验证码
+     */
+    @GET("jaxrs/authentication/captcha/width/{width}/height/{height}")
+    fun getCaptchaCodeImg(@Path("width") width: Int, @Path("height") height: Int): Observable<ApiResponse<CaptchaImgData>>
+
+
+    /**
+     * 用图片验证码登录
+     */
+    @Headers("Content-Type:application/json;charset=UTF-8")
+    @POST("jaxrs/authentication/captcha")
+    fun loginWithCaptchaCode(@Body form:LoginWithCaptchaForm): Observable<ApiResponse<AuthenticationInfoJson>>
+
+
     /**
      * 扫一扫 确认登录
      * @param meta
@@ -72,6 +92,13 @@ interface OrgAssembleAuthenticationService{
     @POST("jaxrs/authentication/bind/meta/{meta}")
     fun scanConfirmWebLogin(@Path("meta") meta: String): Observable<ApiResponse<AuthenticationInfoJson>>
 
+    /**
+     * 获取RSA 加密公钥
+     */
+    @GET("jaxrs/authentication/captchaRSAPublicKey")
+    fun getRSAPublicKey(): Observable<ApiResponse<RSAPublicKeyData>>
+
+
     /**
      * 登出
      * @return

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

@@ -51,6 +51,6 @@ interface OrgAssemblePersonalService {
     /**
      * 更新当前用户密码
      */
-    @PUT("jaxrs/password")
+    @PUT("jaxrs/person/password")
     fun modifyCurrentPersonPassword(@Body body: PersonPwdForm): Observable<ApiResponse<ValueData>>
 }

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

@@ -0,0 +1,12 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+data class CaptchaImgData (
+        var id: String = "",
+        var image: String = "" //验证码图片的base64
+)

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

@@ -0,0 +1,14 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+data class LoginModeData (
+        var captchaLogin: Boolean = false, //验证码登录
+        var codeLogin: Boolean = false, //短信验证码登录
+        var bindLogin: Boolean = false,
+        var faceLogin: Boolean = false
+)

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

@@ -0,0 +1,14 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+data class LoginWithCaptchaForm (
+        var credential: String = "",
+        var password: String = "",
+        var captcha: String ="", //图片认证编号id
+        var captchaAnswer: String =  "",//图片认证码
+        var isEncrypted: String = "" //是否启用加密
+)

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

@@ -0,0 +1,11 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+data class RSAPublicKeyData (
+        var publicKey: String = "" //公钥
+)

+ 2 - 1
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/main/person/PersonPwdForm.kt

@@ -9,5 +9,6 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.person
 class PersonPwdForm(
         var oldPassword: String = "",
         var newPassword: String = "",
-        var confirmPassword: String = ""
+        var confirmPassword: String = "",
+        var isEncrypted: String = ""
 )

+ 53 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CryptRSA.java

@@ -0,0 +1,53 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils;
+
+
+import android.util.Base64;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.Cipher;
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class CryptRSA {
+    /**RSA算法*/
+    private static final String RSA = "RSA";
+
+    private static KeyFactory keyFactory;
+    static {
+        //实例化密钥工厂
+        try {
+            keyFactory = KeyFactory.getInstance(RSA);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 公钥加密
+     *
+     * @param content   待加密数据
+     * @param publicKey 密钥
+     * @return string 加密后数据
+     */
+    public static String rsaEncryptByPublicKey(String content, String publicKey) throws Exception {
+        byte[] keyBytes = Base64.decode(publicKey, Base64.NO_WRAP);
+        //初始化公钥
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+        //产生公钥
+        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
+        //数据加密
+        //PKCS1Padding
+        Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
+        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
+        return new String(Base64.encode(cipher.doFinal(content.trim().getBytes("utf-8")), Base64.NO_WRAP));
+
+    }
+
+
+}

+ 8 - 4
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/SharedPreferencesHelper.kt

@@ -1,9 +1,8 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils
 
-import android.annotation.SuppressLint
 import android.content.Context
-import android.content.SharedPreferences
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.security.SecuritySharedPreference
 
 /**
  * Created by fancyLou on 2018/11/22.
@@ -15,7 +14,12 @@ class SharedPreferencesHelper(cxt: Context)   {
 
     private var context: Context = cxt
 
-    fun prefs(): SharedPreferences = context.getSharedPreferences(O2.PREFERENCE_FILE, Context.MODE_PRIVATE)
+//    fun prefs(): SharedPreferences = context.getSharedPreferences(O2.PREFERENCE_FILE, Context.MODE_PRIVATE)
 
-    
+    /**
+     * 加密的SharedPreference
+     */
+    fun securityPrefs(): SecuritySharedPreference {
+        return SecuritySharedPreference(context, O2.PREFERENCE_FILE, Context.MODE_PRIVATE)
+    }
 }

+ 10 - 3
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/extension/Ext.kt

@@ -11,6 +11,8 @@ import androidx.appcompat.app.AppCompatActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.high_order_func.KTXDrawerListener
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.high_order_func._OnPageChangeListener
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.high_order_func._OnSubscribe
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.security.SecurityEditor
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.security.SecuritySharedPreference
 import rx.Observable
 
 /**
@@ -39,13 +41,18 @@ fun Long.friendlyFileLength(): String {
     }
 }
 
-inline fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {
-    val editor = edit()
+//inline fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {
+//    val editor = edit()
+//    editor.func()
+//    editor.apply()
+//}
+
+inline fun SecuritySharedPreference.edit(func: SecurityEditor.() -> Unit) {
+    val editor  = edit()
     editor.func()
     editor.apply()
 }
 
-
 inline fun ViewPager.addOnPageChangeListener(func: _OnPageChangeListener.() -> Unit) {
     val listener = _OnPageChangeListener()
     listener.func()

+ 147 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/security/EncryptUtil.java

@@ -0,0 +1,147 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.security;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Build;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * AES加密解密工具
+ * @author Max
+ * 2016年11月25日15:25:17
+ */
+public class EncryptUtil {
+
+    private String key;
+    private static EncryptUtil instance;
+    private static final String TAG = EncryptUtil.class.getSimpleName();
+
+
+    private EncryptUtil(Context context){
+        String serialNo = getDeviceSerialNumber(context);
+        //加密随机字符串生成AES key
+        key = SHA(serialNo + "#$ERDTS$D%F^Gojikbh").substring(0, 16);
+        Log.e(TAG, key);
+    }
+
+    /**
+     * 单例模式
+     * @param context context
+     * @return
+     */
+    public static EncryptUtil getInstance(Context context){
+        if (instance == null){
+            synchronized (EncryptUtil.class){
+                if (instance == null){
+                    instance = new EncryptUtil(context);
+                }
+            }
+        }
+
+        return instance;
+    }
+
+    /**
+     * Gets the hardware serial number of this device.
+     *
+     * @return serial number or Settings.Secure.ANDROID_ID if not available.
+     */
+    @SuppressLint("HardwareIds")
+    private String getDeviceSerialNumber(Context context) {
+        // We're using the Reflection API because Build.SERIAL is only available
+        // since API Level 9 (Gingerbread, Android 2.3).
+        try {
+            String deviceSerial = (String) Build.class.getField("SERIAL").get(null);
+            if (TextUtils.isEmpty(deviceSerial)) {
+                return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
+            } else {
+                return deviceSerial;
+            }
+        } catch (Exception ignored) {
+            // Fall back  to Android_ID
+            return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
+        }
+    }
+
+
+    /**
+     * SHA加密
+     * @param strText 明文
+     * @return
+     */
+    private String SHA(final String strText){
+        // 返回值
+        String strResult = null;
+        // 是否是有效字符串
+        if (strText != null && strText.length() > 0){
+            try{
+                // SHA 加密开始
+                MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
+                // 传入要加密的字符串
+                messageDigest.update(strText.getBytes());
+                byte byteBuffer[] = messageDigest.digest();
+                StringBuffer strHexString = new StringBuffer();
+                for (int i = 0; i < byteBuffer.length; i++){
+                    String hex = Integer.toHexString(0xff & byteBuffer[i]);
+                    if (hex.length() == 1){
+                        strHexString.append('0');
+                    }
+                    strHexString.append(hex);
+                }
+                strResult = strHexString.toString();
+            } catch (NoSuchAlgorithmException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return strResult;
+    }
+
+
+    /**
+     * AES128加密
+     * @param plainText 明文
+     * @return
+     */
+    public String encrypt(String plainText) {
+        try {
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
+            cipher.init(Cipher.ENCRYPT_MODE, keyspec);
+            byte[] encrypted = cipher.doFinal(plainText.getBytes());
+            return Base64.encodeToString(encrypted, Base64.NO_WRAP);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * AES128解密
+     * @param cipherText 密文
+     * @return
+     */
+    public String decrypt(String cipherText) {
+        try {
+            byte[] encrypted1 = Base64.decode(cipherText, Base64.NO_WRAP);
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
+            cipher.init(Cipher.DECRYPT_MODE, keyspec);
+            byte[] original = cipher.doFinal(encrypted1);
+            String originalString = new String(original);
+            return originalString;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}

+ 130 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/security/SecurityEditor.java

@@ -0,0 +1,130 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.security;
+
+/**
+ * Created by fancyLou on 2020-09-29.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Build;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 自动加密Editor
+ */
+public class SecurityEditor implements SharedPreferences.Editor {
+
+    private SharedPreferences mSharedPreferences;
+    private Context mContext;
+    private SharedPreferences.Editor mEditor;
+
+    /**
+     * constructor
+     */
+    public SecurityEditor(SharedPreferences sharedPreferences, Context context){
+        this.mContext = context;
+        this.mSharedPreferences = sharedPreferences;
+        this.mEditor = mSharedPreferences.edit();
+    }
+
+    @Override
+    public SharedPreferences.Editor putString(String key, String value) {
+        mEditor.putString(encryptPreference(key), encryptPreference(value));
+        return this;
+    }
+
+    @Override
+    public SharedPreferences.Editor putStringSet(String key, Set<String> values) {
+        final Set<String> encryptSet = new HashSet<>();
+        for (String value : values){
+            encryptSet.add(encryptPreference(value));
+        }
+        mEditor.putStringSet(encryptPreference(key), encryptSet);
+        return this;
+    }
+
+    @Override
+    public SharedPreferences.Editor putInt(String key, int value) {
+        mEditor.putString(encryptPreference(key), encryptPreference(Integer.toString(value)));
+        return this;
+    }
+
+    @Override
+    public SharedPreferences.Editor putLong(String key, long value) {
+        mEditor.putString(encryptPreference(key), encryptPreference(Long.toString(value)));
+        return this;
+    }
+
+    @Override
+    public SharedPreferences.Editor putFloat(String key, float value) {
+        mEditor.putString(encryptPreference(key), encryptPreference(Float.toString(value)));
+        return this;
+    }
+
+    @Override
+    public SharedPreferences.Editor putBoolean(String key, boolean value) {
+        mEditor.putString(encryptPreference(key), encryptPreference(Boolean.toString(value)));
+        return this;
+    }
+
+    @Override
+    public SharedPreferences.Editor remove(String key) {
+        mEditor.remove(encryptPreference(key));
+        return this;
+    }
+
+    /**
+     * encrypt function
+     * @return cipherText base64
+     */
+    private String encryptPreference(String plainText){
+        return EncryptUtil.getInstance(mContext).encrypt(plainText);
+    }
+
+    /**
+     * decrypt function
+     * @return plainText
+     */
+    private String decryptPreference(String cipherText){
+        return EncryptUtil.getInstance(mContext).decrypt(cipherText);
+    }
+
+    /**
+     * Mark in the editor to remove all values from the preferences.
+     * @return this
+     */
+    @Override
+    public SharedPreferences.Editor clear() {
+        mEditor.clear();
+        return this;
+    }
+
+    /**
+     * 提交数据到本地
+     * @return Boolean 判断是否提交成功
+     */
+    @Override
+    public boolean commit() {
+
+        return mEditor.commit();
+    }
+
+    /**
+     * Unlike commit(), which writes its preferences out to persistent storage synchronously,
+     * apply() commits its changes to the in-memory SharedPreferences immediately but starts
+     * an asynchronous commit to disk and you won't be notified of any failures.
+     */
+    @Override
+    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+    public void apply() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+            mEditor.apply();
+        } else {
+            commit();
+        }
+    }
+}

+ 170 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/security/SecuritySharedPreference.java

@@ -0,0 +1,170 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.security;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.preference.PreferenceManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 自动加密SharedPreference
+ * Created by Max on 2016/11/23.
+ */
+
+public class SecuritySharedPreference implements SharedPreferences {
+
+    private SharedPreferences mSharedPreferences;
+    private static final String TAG = SecuritySharedPreference.class.getName();
+    private Context mContext;
+
+    /**
+     * constructor
+     * @param context should be ApplicationContext not activity
+     * @param name file name
+     * @param mode context mode
+     */
+    public SecuritySharedPreference(Context context, String name, int mode){
+        mContext = context;
+        if (TextUtils.isEmpty(name)){
+            mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+        } else {
+            mSharedPreferences =  context.getSharedPreferences(name, mode);
+        }
+
+    }
+
+    @Override
+    public Map<String, String> getAll() {
+        final Map<String, ?> encryptMap = mSharedPreferences.getAll();
+        final Map<String, String> decryptMap = new HashMap<>();
+        for (Map.Entry<String, ?> entry : encryptMap.entrySet()){
+            Object cipherText = entry.getValue();
+            if (cipherText != null){
+                decryptMap.put(entry.getKey(), entry.getValue().toString());
+            }
+        }
+        return decryptMap;
+    }
+
+    /**
+     * encrypt function
+     * @return cipherText base64
+     */
+    private String encryptPreference(String plainText){
+        return EncryptUtil.getInstance(mContext).encrypt(plainText);
+    }
+
+    /**
+     * decrypt function
+     * @return plainText
+     */
+    private String decryptPreference(String cipherText){
+        return EncryptUtil.getInstance(mContext).decrypt(cipherText);
+    }
+
+    @Nullable
+    @Override
+    public String getString(String key, String defValue) {
+        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
+        return encryptValue == null ? defValue : decryptPreference(encryptValue);
+    }
+
+    @Nullable
+    @Override
+    public Set<String> getStringSet(String key, Set<String> defValues) {
+        final Set<String> encryptSet = mSharedPreferences.getStringSet(encryptPreference(key), null);
+        if (encryptSet == null){
+            return defValues;
+        }
+        final Set<String> decryptSet = new HashSet<>();
+        for (String encryptValue : encryptSet){
+            decryptSet.add(decryptPreference(encryptValue));
+        }
+        return decryptSet;
+    }
+
+    @Override
+    public int getInt(String key, int defValue) {
+        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
+        if (encryptValue == null) {
+            return defValue;
+        }
+        return Integer.parseInt(decryptPreference(encryptValue));
+    }
+
+    @Override
+    public long getLong(String key, long defValue) {
+        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
+        if (encryptValue == null) {
+            return defValue;
+        }
+        return Long.parseLong(decryptPreference(encryptValue));
+    }
+
+    @Override
+    public float getFloat(String key, float defValue) {
+        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
+        if (encryptValue == null) {
+            return defValue;
+        }
+        return Float.parseFloat(decryptPreference(encryptValue));
+    }
+
+    @Override
+    public boolean getBoolean(String key, boolean defValue) {
+        final String encryptValue = mSharedPreferences.getString(encryptPreference(key), null);
+        if (encryptValue == null) {
+            return defValue;
+        }
+        return Boolean.parseBoolean(decryptPreference(encryptValue));
+    }
+
+    @Override
+    public boolean contains(String key) {
+        return mSharedPreferences.contains(encryptPreference(key));
+    }
+
+    @Override
+    public SecurityEditor edit() {
+        return new SecurityEditor(mSharedPreferences, mContext);
+    }
+
+    @Override
+    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
+        mSharedPreferences.registerOnSharedPreferenceChangeListener(listener);
+    }
+
+    @Override
+    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
+        mSharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);
+    }
+
+    /**
+     * 处理加密过渡
+     */
+    public void handleTransition(){
+        Map<String, ?> oldMap = mSharedPreferences.getAll();
+        Map<String, String> newMap = new HashMap<>();
+        for (Map.Entry<String, ?> entry : oldMap.entrySet()){
+            Log.i(TAG, "key:"+entry.getKey()+", value:"+ entry.getValue());
+            newMap.put(encryptPreference(entry.getKey()), encryptPreference(entry.getValue().toString()));
+        }
+        Editor editor = mSharedPreferences.edit();
+        editor.clear().commit();
+        for (Map.Entry<String, String> entry : newMap.entrySet()){
+            editor.putString(entry.getKey(), entry.getValue());
+        }
+        editor.commit();
+    }
+
+
+}

+ 12 - 0
o2ios/O2Platform.xcodeproj/project.pbxproj

@@ -218,6 +218,8 @@
 		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 */; };
+		B17DCCB32519A31900E9EE37 /* OOCalendarStoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B17DCCB22519A31900E9EE37 /* OOCalendarStoreViewController.swift */; };
+		B17DCCE32519BCC100E9EE37 /* CalendarStoreTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B17DCCE22519BCC100E9EE37 /* CalendarStoreTableViewCell.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 */; };
@@ -271,6 +273,7 @@
 		B1D1BC8F234C8349002025DA /* CloudFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D1BC8E234C8349002025DA /* CloudFileCell.swift */; };
 		B1D4AFED24B409A9004E648E /* AudioTouchButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D4AFEC24B409A9004E648E /* AudioTouchButton.swift */; };
 		B1DA305F2282754500669418 /* QCalendarPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DA305E2282754500669418 /* QCalendarPicker.swift */; };
+		B1DB0843252314F400EE6673 /* SecurityCheckManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DB0842252314F400EE6673 /* SecurityCheckManager.swift */; };
 		B1DB6EA5237E6F2C00D7BA94 /* O2VersionInfoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DB6EA4237E6F2C00D7BA94 /* O2VersionInfoModel.swift */; };
 		B1DE853823602D36003C36E2 /* Languager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE853723602D36003C36E2 /* Languager.swift */; };
 		B1DE8564236030E2003C36E2 /* Bundle+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DE8563236030E2003C36E2 /* Bundle+Extension.swift */; };
@@ -1389,6 +1392,8 @@
 		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>"; };
+		B17DCCB22519A31900E9EE37 /* OOCalendarStoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OOCalendarStoreViewController.swift; sourceTree = "<group>"; };
+		B17DCCE22519BCC100E9EE37 /* CalendarStoreTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarStoreTableViewCell.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>"; };
@@ -1440,6 +1445,7 @@
 		B1D1BC8E234C8349002025DA /* CloudFileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudFileCell.swift; sourceTree = "<group>"; };
 		B1D4AFEC24B409A9004E648E /* AudioTouchButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioTouchButton.swift; sourceTree = "<group>"; };
 		B1DA305E2282754500669418 /* QCalendarPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QCalendarPicker.swift; sourceTree = "<group>"; };
+		B1DB0842252314F400EE6673 /* SecurityCheckManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityCheckManager.swift; sourceTree = "<group>"; };
 		B1DB6EA4237E6F2C00D7BA94 /* O2VersionInfoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2VersionInfoModel.swift; sourceTree = "<group>"; };
 		B1DE853723602D36003C36E2 /* Languager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Languager.swift; sourceTree = "<group>"; };
 		B1DE8563236030E2003C36E2 /* Bundle+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Extension.swift"; sourceTree = "<group>"; };
@@ -2634,6 +2640,7 @@
 				B15F812B21102BBF00B81F35 /* DatePickerView.xib */,
 				B1089692210AD8E400F02267 /* CalendarEventTableViewCell.swift */,
 				B1C1905C2114410D00935829 /* CalendarTableViewCell.swift */,
+				B17DCCE22519BCC100E9EE37 /* CalendarStoreTableViewCell.swift */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -2646,6 +2653,7 @@
 				B1C19024211437E200935829 /* OOCalendarLeftMenuController.swift */,
 				B1FAE9E02115F95800981A25 /* OOCalendarViewController.swift */,
 				8840A991248CDC9D005970A5 /* OOCalendarEditRemarkViewController.swift */,
+				B17DCCB22519A31900E9EE37 /* OOCalendarStoreViewController.swift */,
 			);
 			path = Controller;
 			sourceTree = "<group>";
@@ -2807,6 +2815,7 @@
 				B14E0C0B2484F1F0008AF6AE /* O2WebsocketManager.swift */,
 				B15BE0BD2499BCEF008CD1DB /* O2RecordVoiceManager.swift */,
 				B15BE110249A6002008CD1DB /* AudioPlayerManager.swift */,
+				B1DB0842252314F400EE6673 /* SecurityCheckManager.swift */,
 			);
 			path = Manager;
 			sourceTree = "<group>";
@@ -5295,6 +5304,7 @@
 				E4B888811D9D48F1002E1A46 /* CellTouchImageView.swift in Sources */,
 				E40E246320B55064009F8BE7 /* OOAttanceCheckinHeaderView.swift in Sources */,
 				B107453921A52BC70015F1B2 /* PersonalAPI.swift in Sources */,
+				B17DCCB32519A31900E9EE37 /* OOCalendarStoreViewController.swift in Sources */,
 				E4B8885D1D9D48F1002E1A46 /* O2App.swift in Sources */,
 				E4B697C120764A2D0062F6E8 /* O2DesktopAPI.swift in Sources */,
 				B165CD6A2242093500373B66 /* CoverVerticalFromTopAnimation.swift in Sources */,
@@ -5610,6 +5620,7 @@
 				E45DA8F91DADC06400E0735D /* TaskBarButtonItem.swift in Sources */,
 				E4B888A21D9D48F1002E1A46 /* MJRefreshAutoStateFooter.m in Sources */,
 				B12FD1DF2283D5B700E636BA /* ThemePicker.swift in Sources */,
+				B17DCCE32519BCC100E9EE37 /* CalendarStoreTableViewCell.swift in Sources */,
 				B165CD622242093500373B66 /* BackgroundView.swift in Sources */,
 				B1912BE72146154700AB36E6 /* OOAIViewModel.swift in Sources */,
 				E4C24C4E208D7EDE00E426B0 /* OOContactSearchCell.swift in Sources */,
@@ -5637,6 +5648,7 @@
 				B15F8129210EF15E00B81F35 /* OOCalendarEventViewController.swift in Sources */,
 				09E02E941F16319600579887 /* String+Haneke.swift in Sources */,
 				E40E24B420B7DA3C009F8BE7 /* OOMeetingModels.swift in Sources */,
+				B1DB0843252314F400EE6673 /* SecurityCheckManager.swift in Sources */,
 				E4B888F61D9D48F1002E1A46 /* Application.swift in Sources */,
 				E4C24C3F208D7EDE00E426B0 /* OOContactSearchViewModel.swift in Sources */,
 				E4B697FC2076520E0062F6E8 /* OOFileModels.swift in Sources */,

+ 28 - 36
o2ios/O2Platform/App/Applications/v/O2CollectionViewCell.swift

@@ -21,52 +21,44 @@ class O2CollectionViewCell: UICollectionViewCell {
     
     @IBOutlet weak var appTitle: UILabel!
     
+    private var nowData:O2App?
+    
     override func prepareForReuse() {
         super.prepareForReuse()
         self.appIconImageView.image = nil
     }
     
-    func initImg(app:O2App){
-        
-        let storeBoard = app.storyBoard
-        if storeBoard == "webview" {
-            guard let iconUrl = AppDelegate.o2Collect.generateURLWithAppContextKey(ApplicationContext.applicationContextKey2, query: ApplicationContext.applicationIconQuery, parameter: ["##applicationId##":app.appId! as AnyObject]) else {
-                DDLogError("没有获取到icon的url。。。。。。")
-                return
-            }
-            
-            let url = URL(string: iconUrl)
-            let size = self.appIconImageView.bounds.size
-            if size.width == 0 {
-                self.appIconImageView.bounds.size = CGSize(width: 38, height: 38)
+    func setAppData(app: O2App) {
+        self.nowData = app
+        if let storeBoard = app.storyBoard, storeBoard == "webview" {
+            if let iconUrl = AppDelegate.o2Collect.generateURLWithAppContextKey(ApplicationContext.applicationContextKey2, query: ApplicationContext.applicationIconQuery, parameter: ["##applicationId##":app.appId! as AnyObject])  {
+                let url = URL(string: iconUrl)
+                let size = self.appIconImageView.bounds.size
+                if size.width == 0 {
+                    self.appIconImageView.bounds.size = CGSize(width: 38, height: 38)
+                }
+                self.appIconImageView.image = UIImage(named: app.normalIcon!)
+                self.appIconImageView.highlightedImage = UIImage(named: app.normalIcon!)
+                self.appIconImageView.hnk_setImageFromURL(url!, placeholder: UIImage(named: app.normalIcon!), format: nil, failure: { (err) in
+                    self.appIconImageView.image = UIImage(named: app.normalIcon!)
+                }) { image in
+                    if self.nowData?.appId == app.appId {
+                        self.appIconImageView.image = image
+                        
+                    }
+                }
+            } else{
+                self.appIconImageView.image = UIImage(named: app.normalIcon!)
+                self.appIconImageView.highlightedImage = UIImage(named: app.selectedIcon!)
             }
-            self.appIconImageView.image = UIImage(named: app.normalIcon!)
-            self.appIconImageView.highlightedImage = UIImage(named: app.normalIcon!)
-//            let format = HanekeGlobals.UIKit.formatWithSize(CGSize(width: 38, height: 38), scaleMode: .AspectFill)
-            self.appIconImageView.hnk_setImageFromURL(url!)
-            
-//            let cache = Shared.imageCache
             
-//            let formatName = format.name
-//            cache.addFormat(format)
-//            let fetcher = NetworkFetcher<UIImage>(URL: url!)
-//            cache.fetch(fetcher: fetcher, formatName: formatName).onSuccess { image in
-//                if(self.o2CellTag != nil && self.o2CellTag == indexPath) {
-//                    DDLogError("eeeeeeee\(app.title)")
-//                    self.appIconImageView.bounds.size = CGSize(width: 38, height: 38)
-//                    self.appIconImageView.hnk_setImageFromURL(<#T##URL: URL##URL#>)
-//                    self.appIconImageView.image = image
-//                    self.appIconImageView.highlightedImage = image
-//                }else {
-//                    DDLogError("ddddddddd\(app.title)")
-//                }
-//            }
-        }else {
+        } else{
             self.appIconImageView.image = UIImage(named: app.normalIcon!)
-            self.appIconImageView.highlightedImage = UIImage(named: app.normalIcon!)
+            self.appIconImageView.highlightedImage = UIImage(named: app.selectedIcon!)
         }
-        
+        self.appTitle.text = app.title
     }
+   
     
     
 }

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

@@ -11,6 +11,9 @@ import CocoaLumberjack
 
 class OOCalendarLeftMenuController: UITableViewController {
     
+    
+    var calendarIds:[String] = []
+    
     private var myCalendarList: [OOCalendarInfo] = []
     private var departmentCalendarList: [OOCalendarInfo] = []
     private var followCalendarList: [OOCalendarInfo] = []
@@ -24,6 +27,7 @@ class OOCalendarLeftMenuController: UITableViewController {
         super.viewDidLoad()
         self.navigationItem.title = "日历"
         self.tableView.tableFooterView = UIView(frame: CGRect.zero)
+        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "日历广场", style: .plain, target: self, action: #selector(openCalendars))
         
         addCalendarBtnView.addTapGesture { (tap) in
             DDLogInfo("点击了新增日历。。。。。。")
@@ -37,6 +41,7 @@ class OOCalendarLeftMenuController: UITableViewController {
             self.myCalendarList = calendars.myCalendars ?? []
             self.departmentCalendarList = calendars.unitCalendars ?? []
             self.followCalendarList = calendars.followCalendars ?? []
+            self.loadCalendarIds()
             self.tableView.reloadData()
             }.catch { (error) in
                 DDLogError(error.localizedDescription)
@@ -100,17 +105,22 @@ class OOCalendarLeftMenuController: UITableViewController {
     /**/
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: "calendarTableCell", for: indexPath) as! CalendarTableViewCell
+        
         switch indexPath.section {
-        case 0:
-            cell.renderCalendar(info: self.myCalendarList[indexPath.row])
-            cell.calendarCellDelegate = self
-        case 1:
-            cell.renderCalendar(info: self.departmentCalendarList[indexPath.row])
-        case 2:
-            cell.renderCalendar(info: self.followCalendarList[indexPath.row])
-        default:
-            DDLogInfo("没有的事。。。。。")
+            case 0:
+                cell.renderCalendar(info: self.myCalendarList[indexPath.row], self.calendarIds)
+                break
+            case 1:
+                cell.renderCalendar(info: self.departmentCalendarList[indexPath.row], self.calendarIds)
+                break
+            case 2:
+                cell.renderCalendar(info: self.followCalendarList[indexPath.row], self.calendarIds)
+                break
+            default:
+                DDLogInfo("没有的事。。。。。")
         }
+        
+        cell.calendarCellDelegate = self
         return cell
     }
  
@@ -152,13 +162,75 @@ class OOCalendarLeftMenuController: UITableViewController {
         }
     }
  
-
+    //前一页传过来的ids如果有值 和 这边重新从网络获取的数据进行id比较合并
+    private func loadCalendarIds() {
+        var newCalendarids:[String] = []
+        self.myCalendarList.forEach { (c) in
+            newCalendarids.append(c.id!)
+        }
+        self.followCalendarList.forEach { (c) in
+            newCalendarids.append(c.id!)
+        }
+        self.departmentCalendarList.forEach { (c) in
+            newCalendarids.append(c.id!)
+        }
+        
+        self.calendarIds.forEach { (id) in
+            if !newCalendarids.contains(id) {
+                self.calendarIds.removeFirst(id)
+            }
+        }
+        
+    }
+    //日历广场
+    @objc private func openCalendars() {
+        self.performSegue(withIdentifier: "showCalendarStore", sender: nil)
+    }
+    
 }
 
 // extension
 
 extension OOCalendarLeftMenuController: CalendarCellSwithOnDelegate {
     func click(isOn: Bool, calendar: OOCalendarInfo?) {
-        DDLogInfo("点击了切换 ison:\(isOn), 日历名称: \(calendar?.name)")
+        
+        if !self.calendarIds.isEmpty {
+            if isOn {
+                self.calendarIds.append(calendar!.id!)
+            }else {
+                self.calendarIds.removeFirst(calendar!.id!)
+            }
+        }else { //第一次
+            var newCalendarids:[String] = []
+            self.myCalendarList.forEach { (c) in
+                if c.id == calendar?.id  {
+                    if isOn {
+                        newCalendarids.append(c.id!)
+                    }
+                }else {
+                    newCalendarids.append(c.id!)
+                }
+            }
+            self.followCalendarList.forEach { (c) in
+                if c.id == calendar?.id  {
+                    if isOn {
+                        newCalendarids.append(c.id!)
+                    }
+                }else {
+                    newCalendarids.append(c.id!)
+                }
+            }
+            self.departmentCalendarList.forEach { (c) in
+                if c.id == calendar?.id  {
+                    if isOn {
+                        newCalendarids.append(c.id!)
+                    }
+                }else {
+                    newCalendarids.append(c.id!)
+                }
+            }
+            self.calendarIds = newCalendarids
+        }
+        NotificationCenter.default.post(name: OONotification.calendarIds.notificationName, object: self.calendarIds)
     }
 }

+ 19 - 2
o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarMainMonthViewController.swift

@@ -22,6 +22,7 @@ class OOCalendarMainMonthViewController: UIViewController {
             //todo
         }
     }
+    var calendarIds:[String] = []
     private var eventShowList:[OOCalendarEventInfo] = []
     private var _today: Date?
     private var _selectDay: Date?
@@ -66,6 +67,7 @@ class OOCalendarMainMonthViewController: UIViewController {
         _startTime = DateUtil.share.monthStartDate(date: _today!)
         _endTime = DateUtil.share.monthEndDate(startDate: _startTime!)
         setNavTitle(date: _today!)
+        NotificationCenter.default.addObserver(self, selector: #selector(setTheCalendarIds(_:)), name: OONotification.calendarIds.notificationName, object: nil)
     }
     override func viewWillAppear(_ animated: Bool) {
         loadData()
@@ -77,6 +79,14 @@ class OOCalendarMainMonthViewController: UIViewController {
     }
     
 
+    //设置
+    @objc private func setTheCalendarIds(_ notification:NSNotification) {
+        DDLogDebug("接收到通知消息")
+        if let ids = notification.object as? [String] {
+            DDLogDebug("设置ids:\(ids)")
+            self.calendarIds = ids
+        }
+    }
     /*
     // MARK: - Navigation
     // In a storyboard-based application, you will often want to do a little preparation before navigation
@@ -92,6 +102,13 @@ class OOCalendarMainMonthViewController: UIViewController {
                 destination.eventInfo = self.eventShowList[row]
             }
         }
+        if segue.identifier == "showCalendarList" {
+            if !self.calendarIds.isEmpty {
+                if let dest = segue.destination as? OOCalendarLeftMenuController {
+                    dest.calendarIds = self.calendarIds
+                }
+            }
+        }
     }
  
     //MARK: - private func
@@ -108,8 +125,8 @@ class OOCalendarMainMonthViewController: UIViewController {
         let filter = OOCalendarEventFilter()
         filter.startTime = self._startTime?.toString("yyyy-MM-dd HH:mm:ss")
         filter.endTime = self._endTime?.toString("yyyy-MM-dd HH:mm:ss")
-        filter.createPerson = _currentPerson
-        // TODO calendarIds.....
+        filter.calendarIds = self.calendarIds
+        
         viewModel.filterCalendarEventList(filter: filter).then { (response) -> Promise<[String:[OOCalendarEventInfo]]>  in
             return Promise<[String:[OOCalendarEventInfo]]> { fulfill, reject in
                 var result: [String:[OOCalendarEventInfo]] = [:]

+ 90 - 0
o2ios/O2Platform/App/Calendar-日程管理/Controller/OOCalendarStoreViewController.swift

@@ -0,0 +1,90 @@
+//
+//  OOCalendarStoreViewController.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/9/22.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+import CocoaLumberjack
+
+class OOCalendarStoreViewController: UITableViewController {
+    
+    
+    private var publicCalendarList: [OOCalendarInfo] = []
+    private lazy var viewModel: OOCalendarViewModel = {
+        return OOCalendarViewModel()
+    }()
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.tableView.tableFooterView = UIView(frame: CGRect.zero)
+        self.viewModel.getPublicCalendarList().then { (list)  in
+            self.publicCalendarList = list
+            self.tableView.reloadData()
+        }.catch{ err in
+            DDLogError("请求错误,\(err.localizedDescription)")
+            self.showError(title: "获取日历失败!")
+        }
+    }
+
+    // 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.publicCalendarList.count
+    }
+    
+    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        if let cell = tableView.dequeueReusableCell(withIdentifier: "calendarStoreTableCell", for: indexPath) as? CalendarStoreTableViewCell {
+            cell.setOOCalendarInfo(calendar: self.publicCalendarList[indexPath.row])
+            cell.delegate = self
+            return cell
+        }else {
+            return UITableViewCell()
+        }
+    }
+    
+    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        return 48.0
+    }
+    
+
+    private func setFollow(follow: Bool, id: String) {
+        for (idx, c) in (self.publicCalendarList.enumerated()) {
+            if c.id == id {
+                c.followed = follow
+                self.publicCalendarList[idx] = c
+                DDLogDebug("设置了。。。\(follow)")
+            }
+        }
+        self.tableView.reloadData()
+    }
+
+}
+
+extension OOCalendarStoreViewController: CalendarStoreCellFollowDelegate {
+    func follow(calendar: OOCalendarInfo?) {
+        if let c = calendar {
+            if c.followed == true {
+                self.viewModel.followCalendarCancel(id: c.id!).then { (v)  in
+                    self.setFollow(follow: false, id: c.id!)
+                }.catch { (err) in
+                    DDLogError("请求错误,\(err.localizedDescription)")
+                    self.showError(title: "取消失败!")
+                }
+            }else {
+                self.viewModel.followCalendar(id: c.id!).then{ v in
+                    self.setFollow(follow: true, id: c.id!)
+                }.catch { (err) in
+                    DDLogError("请求错误,\(err.localizedDescription)")
+                    self.showError(title: "关注失败!")
+                }
+            }
+        }
+    }
+}

+ 61 - 0
o2ios/O2Platform/App/Calendar-日程管理/View/CalendarStoreTableViewCell.swift

@@ -0,0 +1,61 @@
+//
+//  CalendarStoreTableViewCell.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/9/22.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import UIKit
+
+
+protocol CalendarStoreCellFollowDelegate {
+    func follow(calendar: OOCalendarInfo?)
+}
+
+class CalendarStoreTableViewCell: UITableViewCell {
+
+    @IBOutlet weak var calendarColorView: UIView!
+    
+    @IBOutlet weak var calendarTitleLable: UILabel!
+    
+    @IBOutlet weak var calendarOwnerLabel: UILabel!
+    
+    @IBOutlet weak var calendarFllowBtn: UIButton!
+    
+    @IBAction func tapFollowBtn(_ sender: UIButton) {
+        self.delegate?.follow(calendar: self.info)
+    }
+    
+    var delegate: CalendarStoreCellFollowDelegate?
+    private var info: OOCalendarInfo?
+    
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+    }
+
+    override func setSelected(_ selected: Bool, animated: Bool) {
+        super.setSelected(selected, animated: animated)
+
+    }
+    
+    func setOOCalendarInfo(calendar: OOCalendarInfo) {
+        self.info = calendar
+        if let color = calendar.color {
+            self.calendarColorView.backgroundColor = UIColor.init(hex: color)
+        }else {
+            self.calendarColorView.theme_backgroundColor = ThemeColorPicker(keyPath: "Base.base_color")
+        }
+        self.calendarTitleLable.text = calendar.name ?? ""
+        self.calendarOwnerLabel.text = "创建人: \(calendar.createor?.getChinaName() ?? "")"
+        if calendar.followed == true {
+            self.calendarFllowBtn.setTitle("已关注", for: .normal)
+            self.calendarFllowBtn.setTitleColor(toolbar_text_color, for: .normal)
+        }else {
+            self.calendarFllowBtn.setTitle("关注", for: .normal)
+            self.calendarFllowBtn.setTitleColor(base_color, for: .normal)
+        }
+    }
+
+}

+ 8 - 1
o2ios/O2Platform/App/Calendar-日程管理/View/CalendarTableViewCell.swift

@@ -35,7 +35,7 @@ class CalendarTableViewCell: UITableViewCell {
         // Configure the view for the selected state
     }
     
-    func renderCalendar(info: OOCalendarInfo?) {
+    func renderCalendar(info: OOCalendarInfo?, _ calendarIds:[String] = []) {
         self.calendarInfo = info
         if let color = info?.color {
             calendarColorView.backgroundColor = UIColor.init(hex: color)
@@ -43,6 +43,13 @@ class CalendarTableViewCell: UITableViewCell {
             calendarColorView.theme_backgroundColor = ThemeColorPicker(keyPath: "Base.base_color")
         }
         calendarNameView.text = info?.name
+        if !calendarIds.isEmpty {
+            if let id = info?.id, calendarIds.contains(id) {
+                self.calendarSwitch.isOn = true
+            } else {
+                self.calendarSwitch.isOn = false
+            }
+        }
     }
 
 }

+ 144 - 40
o2ios/O2Platform/App/Calendar-日程管理/calendar.storyboard

@@ -1,10 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="tKt-3P-uQz">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" 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="16087"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
@@ -95,7 +96,7 @@
                             <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">
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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="今天"/>
@@ -103,12 +104,12 @@
                                             <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">
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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>
-                                            <segue destination="L5W-fh-UuH" kind="show" id="DF4-xt-Rlu"/>
+                                            <segue destination="L5W-fh-UuH" kind="show" identifier="showCalendarList" id="DF4-xt-Rlu"/>
                                         </connections>
                                     </button>
                                 </subviews>
@@ -122,6 +123,7 @@
                                 </constraints>
                             </view>
                         </subviews>
+                        <viewLayoutGuide key="safeArea" id="YOP-fD-eOB"/>
                         <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"/>
@@ -132,7 +134,6 @@
                             <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>
@@ -586,7 +587,7 @@
                                                 <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">
+                                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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"/>
@@ -595,7 +596,7 @@
                                                                 <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">
+                                                        <button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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"/>
@@ -603,35 +604,35 @@
                                                                 <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">
+                                                        <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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">
+                                                        <button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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">
+                                                        <button opaque="NO" tag="4" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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">
+                                                        <button opaque="NO" tag="5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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">
+                                                        <button opaque="NO" tag="6" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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="周日">
@@ -668,7 +669,7 @@
                                                         <constraint firstAttribute="height" constant="40" id="3Bl-DY-BuS"/>
                                                     </constraints>
                                                 </webView>
-                                                <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OMA-Fp-nFl">
+                                                <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OMA-Fp-nFl">
                                                     <rect key="frame" x="24" y="99" width="327" height="30"/>
                                                     <color key="backgroundColor" red="0.98431372549019602" green="0.27843137254901962" blue="0.27843137254901962" alpha="1" colorSpace="calibratedRGB"/>
                                                     <state key="normal" title="删   除">
@@ -683,7 +684,7 @@
                                                         <action selector="tapDeleteBtn:" destination="Vxk-45-vB1" eventType="touchUpInside" id="d3V-gw-XoF"/>
                                                     </connections>
                                                 </button>
-                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pZL-hd-WYm">
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pZL-hd-WYm">
                                                     <rect key="frame" x="24" y="64" width="62" height="30"/>
                                                     <state key="normal" title="编辑内容"/>
                                                     <connections>
@@ -772,14 +773,14 @@
                         </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"/>
+                                <rect key="frame" x="0.0" y="78" width="375" height="41.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"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="41.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"/>
+                                            <rect key="frame" x="24" y="12" 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"/>
@@ -792,17 +793,13 @@
                                             </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"/>
+                                            <rect key="frame" x="52" y="0.0" width="246" height="41.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>
+                                            <rect key="frame" x="308" y="5" width="51" height="31.5"/>
                                             <connections>
                                                 <action selector="calendarSwitchTap:" destination="hIV-F8-hEt" eventType="valueChanged" id="cgk-KU-AwN"/>
                                             </connections>
@@ -810,11 +807,13 @@
                                     </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="top" secondItem="vcr-nc-qYD" secondAttribute="top" constant="5" id="6dq-te-AwO"/>
                                         <constraint firstItem="BTT-cO-3bH" firstAttribute="leading" secondItem="onv-WL-BxB" secondAttribute="trailing" constant="10" id="ZWp-uB-5KZ"/>
+                                        <constraint firstAttribute="bottom" secondItem="onv-WL-BxB" secondAttribute="bottom" id="asd-bw-2ru"/>
                                         <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 firstAttribute="bottom" secondItem="BTT-cO-3bH" secondAttribute="bottom" constant="5" id="m8U-oP-bSE"/>
+                                        <constraint firstItem="onv-WL-BxB" firstAttribute="top" secondItem="vcr-nc-qYD" secondAttribute="top" id="osg-a9-knU"/>
                                         <constraint firstItem="nUr-LS-pfg" firstAttribute="leading" secondItem="vcr-nc-qYD" secondAttribute="leading" constant="24" id="sih-O1-7td"/>
                                     </constraints>
                                 </tableViewCellContentView>
@@ -834,6 +833,7 @@
                     <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="Bfb-e1-6Y0" kind="show" identifier="showCalendarStore" id="6j2-dN-seh"/>
                     </connections>
                 </tableViewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="ffa-JI-hF2" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -868,6 +868,7 @@
                                 </subviews>
                             </stackView>
                         </subviews>
+                        <viewLayoutGuide key="safeArea" id="VP9-5C-v7b"/>
                         <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"/>
@@ -875,7 +876,6 @@
                             <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"/>
@@ -901,16 +901,16 @@
                                             <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"/>
+                                                    <rect key="frame" x="16" y="5" width="349" height="34"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
                                                     <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 firstAttribute="bottom" secondItem="E1I-tu-3OF" secondAttribute="bottom" constant="5" 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"/>
+                                                <constraint firstItem="E1I-tu-3OF" firstAttribute="top" secondItem="ey7-OW-MZr" secondAttribute="top" constant="5" id="xW5-Or-ZFH"/>
                                             </constraints>
                                         </tableViewCellContentView>
                                     </tableViewCell>
@@ -927,7 +927,7 @@
                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                     <textInputTraits key="textInputTraits"/>
                                                 </textField>
-                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GjW-u2-fg5">
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GjW-u2-fg5">
                                                     <rect key="frame" x="315" y="6" width="44" height="32"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="44" id="rno-Bo-Yb6"/>
@@ -1233,7 +1233,7 @@
                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                     <textInputTraits key="textInputTraits"/>
                                                 </textField>
-                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kae-RP-FyB">
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kae-RP-FyB">
                                                     <rect key="frame" x="315" y="6" width="44" height="32"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="44" id="Hwl-ng-8iq"/>
@@ -1268,7 +1268,7 @@
                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                     <textInputTraits key="textInputTraits"/>
                                                 </textField>
-                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="m4R-gF-vOd">
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="m4R-gF-vOd">
                                                     <rect key="frame" x="315" y="6" width="44" height="32"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="44" id="L1T-hn-46f"/>
@@ -1303,7 +1303,7 @@
                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                     <textInputTraits key="textInputTraits"/>
                                                 </textField>
-                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yrc-Ws-oZH">
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yrc-Ws-oZH">
                                                     <rect key="frame" x="315" y="6" width="44" height="32"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="44" id="qzS-jN-n7Y"/>
@@ -1338,7 +1338,7 @@
                                                     <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                     <textInputTraits key="textInputTraits"/>
                                                 </textField>
-                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ueU-we-edj">
+                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ueU-we-edj">
                                                     <rect key="frame" x="315" y="6" width="44" height="32"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="44" id="LGG-fL-DaH"/>
@@ -1372,7 +1372,7 @@
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="是否启用" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qf3-2G-kRZ">
-                                                    <rect key="frame" x="74" y="19" width="70" height="11"/>
+                                                    <rect key="frame" x="74" y="11" width="70" height="27"/>
                                                     <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                     <nil key="textColor"/>
                                                     <nil key="highlightedColor"/>
@@ -1385,8 +1385,8 @@
                                                 </switch>
                                             </subviews>
                                             <constraints>
-                                                <constraint firstAttribute="bottomMargin" secondItem="qf3-2G-kRZ" secondAttribute="bottom" constant="8" id="GjC-rC-dNw"/>
-                                                <constraint firstItem="qf3-2G-kRZ" firstAttribute="top" secondItem="W0o-2J-yuQ" secondAttribute="topMargin" constant="8" id="Oda-cU-M70"/>
+                                                <constraint firstAttribute="bottomMargin" secondItem="qf3-2G-kRZ" secondAttribute="bottom" id="GjC-rC-dNw"/>
+                                                <constraint firstItem="qf3-2G-kRZ" firstAttribute="top" secondItem="W0o-2J-yuQ" secondAttribute="topMargin" id="Oda-cU-M70"/>
                                                 <constraint firstItem="GTC-NP-gGg" firstAttribute="leading" secondItem="W0o-2J-yuQ" secondAttribute="leading" constant="16" id="goD-5C-BW3"/>
                                                 <constraint firstItem="GTC-NP-gGg" firstAttribute="top" secondItem="W0o-2J-yuQ" secondAttribute="top" constant="8" id="v4N-sc-Chi"/>
                                                 <constraint firstItem="qf3-2G-kRZ" firstAttribute="leading" secondItem="GTC-NP-gGg" secondAttribute="trailing" constant="10" id="xtU-RP-ae1"/>
@@ -1420,6 +1420,107 @@
             </objects>
             <point key="canvasLocation" x="1648.8" y="97.601199400299862"/>
         </scene>
+        <!--日历广场-->
+        <scene sceneID="g3n-kS-6vi">
+            <objects>
+                <tableViewController title="日历广场" id="Bfb-e1-6Y0" customClass="OOCalendarStoreViewController" 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="cef-ke-3He">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <prototypes>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="calendarStoreTableCell" rowHeight="48" id="Ndh-HP-3ck" customClass="CalendarStoreTableViewCell" customModule="O2Platform" customModuleProvider="target">
+                                <rect key="frame" x="0.0" y="28" width="375" height="48"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Ndh-HP-3ck" id="tLV-v6-ZMd">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="48"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vnc-mF-rIl">
+                                            <rect key="frame" x="34" y="15" width="18" height="18"/>
+                                            <color key="backgroundColor" red="0.42352941176470588" green="0.42352941176470588" blue="0.42352941176470588" alpha="1" colorSpace="calibratedRGB"/>
+                                            <constraints>
+                                                <constraint firstAttribute="width" constant="18" id="IF3-GM-Qgv"/>
+                                                <constraint firstAttribute="height" constant="18" id="vvg-DX-rFF"/>
+                                            </constraints>
+                                            <userDefinedRuntimeAttributes>
+                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                                    <real key="value" value="9"/>
+                                                </userDefinedRuntimeAttribute>
+                                            </userDefinedRuntimeAttributes>
+                                        </view>
+                                        <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillProportionally" translatesAutoresizingMaskIntoConstraints="NO" id="JVL-J4-yhe">
+                                            <rect key="frame" x="60" y="0.0" width="209" height="48"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="公开的日历" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VmY-o1-rF9">
+                                                    <rect key="frame" x="0.0" y="0.0" width="209" height="26"/>
+                                                    <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="创建人:xxx" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jle-N2-9Fg">
+                                                    <rect key="frame" x="0.0" y="26" width="209" height="22"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.57045853140000002" green="0.57047235969999999" blue="0.57046490910000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                        </stackView>
+                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uuR-AT-jup">
+                                            <rect key="frame" x="293" y="8" width="64" height="32"/>
+                                            <constraints>
+                                                <constraint firstAttribute="width" constant="64" id="bXP-Fz-asJ"/>
+                                            </constraints>
+                                            <state key="normal" title="关注">
+                                                <color key="titleColor" red="0.98431372549999996" green="0.2784313725" blue="0.2784313725" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                            </state>
+                                            <userDefinedRuntimeAttributes>
+                                                <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                                    <real key="value" value="1"/>
+                                                </userDefinedRuntimeAttribute>
+                                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                                    <real key="value" value="5"/>
+                                                </userDefinedRuntimeAttribute>
+                                                <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                                    <color key="value" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                                </userDefinedRuntimeAttribute>
+                                            </userDefinedRuntimeAttributes>
+                                            <connections>
+                                                <action selector="tapFollowBtn:" destination="Ndh-HP-3ck" eventType="touchUpInside" id="nTo-6K-MKs"/>
+                                            </connections>
+                                        </button>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="JVL-J4-yhe" firstAttribute="top" secondItem="tLV-v6-ZMd" secondAttribute="top" id="5B6-la-gs1"/>
+                                        <constraint firstItem="vnc-mF-rIl" firstAttribute="leading" secondItem="tLV-v6-ZMd" secondAttribute="leadingMargin" constant="18" id="JeK-qR-yPw"/>
+                                        <constraint firstItem="JVL-J4-yhe" firstAttribute="leading" secondItem="vnc-mF-rIl" secondAttribute="trailing" constant="8" id="KJx-6z-vsd"/>
+                                        <constraint firstAttribute="bottom" secondItem="uuR-AT-jup" secondAttribute="bottom" constant="8" id="M7a-F5-8fa"/>
+                                        <constraint firstAttribute="bottom" secondItem="JVL-J4-yhe" secondAttribute="bottom" id="a8N-Zw-VFh"/>
+                                        <constraint firstItem="uuR-AT-jup" firstAttribute="top" secondItem="tLV-v6-ZMd" secondAttribute="top" constant="8" id="erk-KH-Qzk"/>
+                                        <constraint firstItem="uuR-AT-jup" firstAttribute="leading" secondItem="JVL-J4-yhe" secondAttribute="trailing" constant="24" id="nT4-A6-3Hj"/>
+                                        <constraint firstItem="vnc-mF-rIl" firstAttribute="centerY" secondItem="tLV-v6-ZMd" secondAttribute="centerY" id="wXx-cu-GTi"/>
+                                        <constraint firstAttribute="trailing" secondItem="uuR-AT-jup" secondAttribute="trailing" constant="18" id="zJN-ZN-tdX"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <connections>
+                                    <outlet property="calendarColorView" destination="vnc-mF-rIl" id="bI3-7K-9dZ"/>
+                                    <outlet property="calendarFllowBtn" destination="uuR-AT-jup" id="E7a-t1-YTJ"/>
+                                    <outlet property="calendarOwnerLabel" destination="jle-N2-9Fg" id="gUV-lw-0E5"/>
+                                    <outlet property="calendarTitleLable" destination="VmY-o1-rF9" id="A4w-vW-DYW"/>
+                                </connections>
+                            </tableViewCell>
+                        </prototypes>
+                        <connections>
+                            <outlet property="dataSource" destination="Bfb-e1-6Y0" id="ol9-J4-wab"/>
+                            <outlet property="delegate" destination="Bfb-e1-6Y0" id="WKp-wX-oG4"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" id="Rpv-5V-KGp"/>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="NEG-LV-WH8" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1649" y="838"/>
+        </scene>
         <!--编辑内容-->
         <scene sceneID="d6n-Ns-IYR">
             <objects>
@@ -1427,8 +1528,8 @@
                     <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"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                     </view>
                     <navigationItem key="navigationItem" title="编辑内容" id="8m9-cj-hJa">
                         <barButtonItem key="leftBarButtonItem" title="取消" landscapeImage="icon_off_grey" id="Nbx-21-hlf">
@@ -1476,5 +1577,8 @@
         <image name="icon_shijian" width="22" height="22"/>
         <image name="icon_tixing" width="22" height="22"/>
         <image name="icon_zengjia" width="22" height="22"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
     </resources>
 </document>

+ 77 - 72
o2ios/O2Platform/App/Login-绑定登录/c/LoginViewController.swift

@@ -68,84 +68,89 @@ class LoginViewController: UIViewController {
     }
 
     func startFlowForPromise() {
-        
-        if !O2IsConnect2Collect {
-            let unit = O2BindUnitModel()
-            if let infoPath = Bundle.main.path(forResource: "Info", ofType: "plist"), let dic = NSDictionary(contentsOfFile: infoPath) {
-                let o2Server = dic["o2 server"] as? NSDictionary
-                let id = o2Server?["id"] as? String
-                let name = o2Server?["name"] as? String
-                let centerHost = o2Server?["centerHost"] as? String
-                let centerContext = o2Server?["centerContext"] as? String
-                let centerPort = o2Server?["centerPort"] as? Int
-                let httpProtocol = o2Server?["httpProtocol"] as? String
-                DDLogDebug("连接服务器:\(String(describing: name)) , host:\(String(describing: centerHost)) , context:\(String(describing: centerContext)), port:\(centerPort ?? 0), portocal:\(String(describing: httpProtocol)) ")
-                if name == nil || centerHost == nil || centerContext == nil {
-                    self.showError(title:  "服务器配置信息异常!")
+        //越狱检查
+        if SecurityCheckManager.shared.isJailBroken() {
+            self.showSystemAlert(title: "提示", message: "当前运行环境已经越狱,本应用将不提供服务!") { (action) in
+                DDLogError("已经越狱的机器,不进入app!")
+            }
+        }else {
+            if !O2IsConnect2Collect {
+                let unit = O2BindUnitModel()
+                if let infoPath = Bundle.main.path(forResource: "Info", ofType: "plist"), let dic = NSDictionary(contentsOfFile: infoPath) {
+                    let o2Server = dic["o2 server"] as? NSDictionary
+                    let id = o2Server?["id"] as? String
+                    let name = o2Server?["name"] as? String
+                    let centerHost = o2Server?["centerHost"] as? String
+                    let centerContext = o2Server?["centerContext"] as? String
+                    let centerPort = o2Server?["centerPort"] as? Int
+                    let httpProtocol = o2Server?["httpProtocol"] as? String
+                    DDLogDebug("连接服务器:\(String(describing: name)) , host:\(String(describing: centerHost)) , context:\(String(describing: centerContext)), port:\(centerPort ?? 0), portocal:\(String(describing: httpProtocol)) ")
+                    if name == nil || centerHost == nil || centerContext == nil {
+                        self.showError(title:  "服务器配置信息异常!")
+                        return
+                    }
+                    unit.id = id
+                    unit.centerContext = centerContext
+                    unit.centerHost = centerHost
+                    unit.centerPort = centerPort
+                    unit.httpProtocol = httpProtocol
+                    unit.name = name
+                }else {
+                    self.showError(title:  "没有配置服务器信息!")
                     return
                 }
-                unit.id = id
-                unit.centerContext = centerContext
-                unit.centerHost = centerHost
-                unit.centerPort = centerPort
-                unit.httpProtocol = httpProtocol
-                unit.name = name
-            }else {
-                self.showError(title:  "没有配置服务器信息!")
-                return
-            }
-            
-            O2AuthSDK.shared.launchInner(unit: unit) { (state, msg) in
-                switch state {
-                case .bindError:
-                    //校验绑定结点信息错误
-                   self.showError(title: "未知错误!")
-                    break
-                case .loginError:
-                    self.forwardToSegue("loginSystemSegue")
-                    //自动登录出错
-                    break
-                case .unknownError:
-                    self.showError(title: msg ?? "未知错误!")
-                    break
-                case .success:
-                    //处理移动端应用
-                    self.viewModel._saveAppConfigToDb()
-                    //跳转到主页
-                    let destVC = O2MainController.genernateVC()
-                    destVC.selectedIndex = 2 // 首页选中 TODO 图标不亮。。。。。
-                    UIApplication.shared.keyWindow?.rootViewController = destVC
-                    UIApplication.shared.keyWindow?.makeKeyAndVisible()
+                
+                O2AuthSDK.shared.launchInner(unit: unit) { (state, msg) in
+                    switch state {
+                    case .bindError:
+                        //校验绑定结点信息错误
+                       self.showError(title: "未知错误!")
+                        break
+                    case .loginError:
+                        self.forwardToSegue("loginSystemSegue")
+                        //自动登录出错
+                        break
+                    case .unknownError:
+                        self.showError(title: msg ?? "未知错误!")
+                        break
+                    case .success:
+                        //处理移动端应用
+                        self.viewModel._saveAppConfigToDb()
+                        //跳转到主页
+                        let destVC = O2MainController.genernateVC()
+                        destVC.selectedIndex = 2 // 首页选中 TODO 图标不亮。。。。。
+                        UIApplication.shared.keyWindow?.rootViewController = destVC
+                        UIApplication.shared.keyWindow?.makeKeyAndVisible()
+                    }
                 }
-            }
-        }else {
-            //本地 -> 校验 -> 下载NodeAPI -> 下载configInfo -> 自动登录
-            O2AuthSDK.shared.launch { (state, msg) in
-                switch state {
-                case .bindError:
-                    //校验绑定结点信息错误
-                    self.forwardToSegue("bindPhoneSegue")
-                    break
-                case .loginError:
-                    self.forwardToSegue("loginSystemSegue")
-                    //自动登录出错
-                    break
-                case .unknownError:
-//                    self.showError(title: msg ?? "未知错误!")
-                    self.needReBind(msg ?? "未知错误!")
-                    break
-                case .success:
-                    //处理移动端应用
-                    self.viewModel._saveAppConfigToDb()
-                    //跳转到主页
-                    let destVC = O2MainController.genernateVC()
-                    destVC.selectedIndex = 2 // 首页选中 TODO 图标不亮。。。。。
-                    UIApplication.shared.keyWindow?.rootViewController = destVC
-                    UIApplication.shared.keyWindow?.makeKeyAndVisible()
+            }else {
+                //本地 -> 校验 -> 下载NodeAPI -> 下载configInfo -> 自动登录
+                O2AuthSDK.shared.launch { (state, msg) in
+                    switch state {
+                    case .bindError:
+                        //校验绑定结点信息错误
+                        self.forwardToSegue("bindPhoneSegue")
+                        break
+                    case .loginError:
+                        self.forwardToSegue("loginSystemSegue")
+                        //自动登录出错
+                        break
+                    case .unknownError:
+    //                    self.showError(title: msg ?? "未知错误!")
+                        self.needReBind(msg ?? "未知错误!")
+                        break
+                    case .success:
+                        //处理移动端应用
+                        self.viewModel._saveAppConfigToDb()
+                        //跳转到主页
+                        let destVC = O2MainController.genernateVC()
+                        destVC.selectedIndex = 2 // 首页选中 TODO 图标不亮。。。。。
+                        UIApplication.shared.keyWindow?.rootViewController = destVC
+                        UIApplication.shared.keyWindow?.makeKeyAndVisible()
+                    }
                 }
             }
         }
-        
     }
 
     

+ 8 - 6
o2ios/O2Platform/App/Login-绑定登录/c/OOBindNodeViewController.swift

@@ -57,13 +57,15 @@ class OOBindNodeViewController:OOBaseViewController,UITableViewDataSource,UITabl
         headerView1.configTitle(title: "选择服务节点", actionTitle: nil)
         headerView1.frame = CGRect(x: 0, y: 0, width: kScreenW, height: 66)
         headerView1.theme_backgroundColor = ThemeColorPicker(keyPath: "Base.base_color")
-        if #available(iOS 11, *) {
-            self.tableView.contentInsetAdjustmentBehavior = .never
-            self.view.addSubview(headerView1)
-        }else{
-            self.view.addSubview(headerView1)
-        }
+//        if #available(iOS 11, *) {
+//            self.tableView.contentInsetAdjustmentBehavior = .never
+//            self.view.addSubview(headerView1)
+//        }else{
+//
+//        }
+        self.view.addSubview(headerView1)
         self.tableView.tableHeaderView = headerView
+        headerView.contentMode = .scaleAspectFill
         self.tableView.tableFooterView = footerView
         self.tableView.dataSource = self
         self.tableView.delegate = self

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

@@ -48,11 +48,22 @@ class OOLoginViewController: OOBaseViewController {
     
     override func viewDidLoad() {
         super.viewDidLoad()
+        //监听截屏通知
+        NotificationCenter.default.addObserver(self, selector: #selector(screenshots),
+                                               name: UIApplication.userDidTakeScreenshotNotification,
+                                               object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
+                
         //delegate
         passwordTextField.buttonDelegate = self
         setupUI()
         
     }
+    
+    deinit {
+        NotificationCenter.default.removeObserver(self, name: UIApplication.userDidTakeScreenshotNotification, object: nil)
+    }
+    
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         let bioAuthUser = AppConfigSettings.shared.bioAuthUser
@@ -71,6 +82,7 @@ class OOLoginViewController: OOBaseViewController {
         }
         
     }
+     
     
     @IBAction func unwindFromBioAuthLogin(_ unwindSegue: UIStoryboardSegue) {
         if unwindSegue.identifier == "goBack2Login" {
@@ -79,6 +91,19 @@ class OOLoginViewController: OOBaseViewController {
         }
     }
     
+    @objc private func didEnterBackground() {
+        DDLogDebug("进入后台.................")
+        self.userNameTextField.text = ""
+        self.passwordField.text = ""
+    }
+    
+    //截屏提示
+    @objc private func screenshots() {
+        self.showSystemAlert(title: "提示", message: "为了保护用户名密码安全,请不要截图!") { (action) in
+            DDLogDebug("确定提示。")
+        }
+    }
+    
     private func setupUI(){
         logoImageView.image = OOCustomImageManager.default.loadImage(.login_avatar)
         let backImageView = UIImageView(image: #imageLiteral(resourceName: "pic_beijing"))

+ 39 - 13
o2ios/O2Platform/App/Login-绑定登录/login.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="2FW-oB-Z7W">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="2FW-oB-Z7W">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
@@ -121,7 +121,7 @@
                                             </userDefinedRuntimeAttribute>
                                         </userDefinedRuntimeAttributes>
                                     </textField>
-                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RFi-UF-mda" customClass="OOBaseUIButton" customModule="O2Platform" customModuleProvider="target">
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RFi-UF-mda" customClass="OOBaseUIButton" customModule="O2Platform" customModuleProvider="target">
                                         <rect key="frame" x="0.0" y="140" width="343" height="40"/>
                                         <color key="backgroundColor" red="0.98431372549999996" green="0.2784313725" blue="0.2784313725" alpha="1" colorSpace="calibratedRGB"/>
                                         <constraints>
@@ -183,7 +183,7 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="dnx-pt-seb">
-                                <rect key="frame" x="0.0" y="66" width="375" height="601"/>
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                                 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <inset key="separatorInset" minX="15" minY="0.0" maxX="15" maxY="0.0"/>
                                 <prototypes>
@@ -195,14 +195,14 @@
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_liebiao1" highlightedImage="icon_liebiao1" translatesAutoresizingMaskIntoConstraints="NO" id="eSE-rC-sdC">
-                                                    <rect key="frame" x="15" y="11" width="22" height="22"/>
+                                                    <rect key="frame" x="16" y="11" width="22" height="22"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="22" id="lbS-6x-LVf"/>
                                                         <constraint firstAttribute="height" constant="22" id="rwO-Dc-TVx"/>
                                                     </constraints>
                                                 </imageView>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ANNA组织" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="86p-zE-rWI">
-                                                    <rect key="frame" x="48" y="12.5" width="279" height="18.5"/>
+                                                    <rect key="frame" x="49" y="12.5" width="277" height="18.5"/>
                                                     <constraints>
                                                         <constraint firstAttribute="height" constant="18.5" id="utf-Qz-Nga"/>
                                                     </constraints>
@@ -211,7 +211,7 @@
                                                     <nil key="highlightedColor"/>
                                                 </label>
                                                 <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_circle" highlightedImage="icon__ok2_click" translatesAutoresizingMaskIntoConstraints="NO" id="6pg-2l-8AO">
-                                                    <rect key="frame" x="338" y="11" width="22" height="22"/>
+                                                    <rect key="frame" x="337" y="11" width="22" height="22"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="22" id="Kh2-7z-vhD"/>
                                                         <constraint firstAttribute="height" constant="22" id="eDN-ft-sSR"/>
@@ -242,7 +242,7 @@
                             <constraint firstItem="dnx-pt-seb" firstAttribute="leading" secondItem="xoM-4c-VPc" secondAttribute="leading" id="1dK-o5-Mxg"/>
                             <constraint firstItem="r53-28-RdP" firstAttribute="top" secondItem="dnx-pt-seb" secondAttribute="bottom" id="4j3-Ja-xbw"/>
                             <constraint firstAttribute="trailing" secondItem="dnx-pt-seb" secondAttribute="trailing" id="7lf-X7-E8I"/>
-                            <constraint firstItem="dnx-pt-seb" firstAttribute="top" secondItem="xoM-4c-VPc" secondAttribute="top" constant="66" id="nU3-HT-gYj"/>
+                            <constraint firstItem="dnx-pt-seb" firstAttribute="top" secondItem="xoM-4c-VPc" secondAttribute="top" id="nU3-HT-gYj"/>
                         </constraints>
                     </view>
                     <connections>
@@ -343,7 +343,7 @@
                                             </userDefinedRuntimeAttribute>
                                         </userDefinedRuntimeAttributes>
                                     </textField>
-                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bkV-iJ-Vkd" customClass="OOBaseUIButton" customModule="O2Platform" customModuleProvider="target">
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bkV-iJ-Vkd" customClass="OOBaseUIButton" customModule="O2Platform" customModuleProvider="target">
                                         <rect key="frame" x="0.0" y="140" width="343" height="40"/>
                                         <color key="backgroundColor" red="0.98431372549999996" green="0.2784313725" blue="0.2784313725" alpha="1" colorSpace="calibratedRGB"/>
                                         <constraints>
@@ -372,7 +372,7 @@
                                 <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
                                 <nil key="highlightedColor"/>
                             </label>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sdH-Rd-Uu5">
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sdH-Rd-Uu5">
                                 <rect key="frame" x="243" y="363" width="100" height="35"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="35" id="McM-ZF-FyV"/>
@@ -385,7 +385,7 @@
                                     <action selector="btnReBindNodeAction:" destination="a0S-mR-qpd" eventType="touchUpInside" id="qQA-3H-Xcv"/>
                                 </connections>
                             </button>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VU6-Hu-1I4">
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VU6-Hu-1I4">
                                 <rect key="frame" x="32" y="363" width="100" height="35"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="35" id="DyV-tz-NyM"/>
@@ -454,7 +454,7 @@
                                     <constraint firstAttribute="height" constant="120" id="bqd-au-JQf"/>
                                 </constraints>
                             </imageView>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q9Q-4z-Rfe" customClass="OOBaseUIButton" customModule="O2Platform" customModuleProvider="target">
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q9Q-4z-Rfe" customClass="OOBaseUIButton" customModule="O2Platform" customModuleProvider="target">
                                 <rect key="frame" x="26" y="270" width="323" height="40"/>
                                 <color key="backgroundColor" red="0.98431372549999996" green="0.2784313725" blue="0.2784313725" alpha="1" colorSpace="calibratedRGB"/>
                                 <constraints>
@@ -473,7 +473,7 @@
                                     <action selector="tapBioAuthLogin:" destination="cft-aF-Yb3" eventType="touchUpInside" id="hAV-fd-WqM"/>
                                 </connections>
                             </button>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kLj-hW-IW3">
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kLj-hW-IW3">
                                 <rect key="frame" x="257" y="330" width="92" height="30"/>
                                 <state key="normal" title="其它方式登录"/>
                                 <connections>
@@ -503,6 +503,32 @@
             <point key="canvasLocation" x="2825" y="101"/>
         </scene>
     </scenes>
+    <designables>
+        <designable name="Nr9-8F-s20">
+            <size key="intrinsicContentSize" width="71.5" height="18.5"/>
+        </designable>
+        <designable name="ObS-rR-SV6">
+            <size key="intrinsicContentSize" width="86" height="18.5"/>
+        </designable>
+        <designable name="Q9Q-4z-Rfe">
+            <size key="intrinsicContentSize" width="92" height="30"/>
+        </designable>
+        <designable name="RFi-UF-mda">
+            <size key="intrinsicContentSize" width="45" height="33"/>
+        </designable>
+        <designable name="bkV-iJ-Vkd">
+            <size key="intrinsicContentSize" width="31" height="30"/>
+        </designable>
+        <designable name="f1x-qE-7k6">
+            <size key="intrinsicContentSize" width="86" height="18.5"/>
+        </designable>
+        <designable name="lEi-tc-UYF">
+            <size key="intrinsicContentSize" width="86" height="18.5"/>
+        </designable>
+        <designable name="uXf-3e-9Bs">
+            <size key="intrinsicContentSize" width="100" height="18.5"/>
+        </designable>
+    </designables>
     <resources>
         <image name="icon__ok2_click" width="22" height="22"/>
         <image name="icon_circle" width="22" height="22"/>

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

@@ -22,8 +22,12 @@ enum OONotification:String {
     //重载门户webview
     case reloadPortal
     
+    //websocket使用
     case websocket
     
+    //日程管理Main中使用
+    case calendarIds
+    
     
     
     var stringValue:String {

+ 8 - 4
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Headers/O2OA_Auth_SDK-Swift.h

@@ -1,6 +1,8 @@
 #if 0
 #elif defined(__arm64__) && __arm64__
-// Generated by Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
+// Generated by Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1)
+#ifndef O2OA_AUTH_SDK_SWIFT_H
+#define O2OA_AUTH_SDK_SWIFT_H
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wgcc-compat"
 
@@ -410,14 +412,16 @@ SWIFT_CLASS("_TtC13O2OA_Auth_SDK16O2WebServerModel")
 @end
 
 
-
 #if __has_attribute(external_source_symbol)
 # pragma clang attribute pop
 #endif
 #pragma clang diagnostic pop
+#endif
 
 #elif defined(__ARM_ARCH_7A__) && __ARM_ARCH_7A__
-// Generated by Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
+// Generated by Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1)
+#ifndef O2OA_AUTH_SDK_SWIFT_H
+#define O2OA_AUTH_SDK_SWIFT_H
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wgcc-compat"
 
@@ -827,10 +831,10 @@ SWIFT_CLASS("_TtC13O2OA_Auth_SDK16O2WebServerModel")
 @end
 
 
-
 #if __has_attribute(external_source_symbol)
 # pragma clang attribute pop
 #endif
 #pragma clang diagnostic pop
+#endif
 
 #endif

BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Info.plist


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/arm.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/arm64.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/armv7-apple-ios.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/armv7.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/i386-apple-ios-simulator.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/i386.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/Project/x86_64.swiftsourceinfo


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64-apple-ios.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64-apple-ios.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/arm64.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7-apple-ios.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7-apple-ios.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/armv7.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386-apple-ios-simulator.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386-apple-ios-simulator.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/i386.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64.swiftdoc


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/Modules/O2OA_Auth_SDK.swiftmodule/x86_64.swiftmodule


BIN
o2ios/O2Platform/Framework/O2OA_Auth_SDK.framework/O2OA_Auth_SDK


+ 5 - 0
o2ios/O2Platform/Framework/Utils/ZonePermissions.swift

@@ -59,6 +59,11 @@ public class ZonePermissions: NSObject {
                     callback(ZoneAuthorizationStatus.zAuthorizationStatusRestricted)
                 }
                 
+            case .limited:
+                DispatchQueue.main.async {
+                    callback(ZoneAuthorizationStatus.zAuthorizationStatusAuthorized)
+                    
+                }
             }
         }else {
             DispatchQueue.main.async {

+ 2 - 0
o2ios/O2Platform/Framework/scan/LBXPermissions.swift

@@ -30,6 +30,8 @@ class LBXPermissions: NSObject {
                     comletion(status == PHAuthorizationStatus.authorized ? true:false)
                 }
             })
+        case .limited:
+            comletion(true)
         }
     }
     

+ 1 - 1
o2ios/O2Platform/Info.plist

@@ -167,7 +167,7 @@
 	<key>UIViewControllerBasedStatusBarAppearance</key>
 	<true/>
 	<key>o2 app version url</key>
-	<string>https://sample.o2oa.net/app/app.json</string>
+	<string>https://app.o2oa.net/download/app.json</string>
 	<key>o2 server</key>
 	<dict>
 		<key>centerContext</key>

+ 44 - 0
o2ios/O2Platform/Manager/SecurityCheckManager.swift

@@ -0,0 +1,44 @@
+//
+//  SecurityCheckManager.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/9/29.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Foundation
+
+
+class SecurityCheckManager {
+    
+    static let shared : SecurityCheckManager = {
+        return SecurityCheckManager()
+    }()
+    
+    private init() {}
+    
+    ///判断是否存在越狱的软件
+    func isJailBroken() -> Bool {
+      //判断设备上是否安装了这些程序
+      let apps = ["/APPlications/Cydia.app",
+                  "/Library/MobileSubstrate/MobileSubstrate.dylib",
+                  "/bin/bash",
+                  "/usr/sbin/sshd",
+                  "/etc/apt",
+                  "/usr/bin/ssh",
+                  "/APPlications/limera1n.app",
+                  "/APPlications/greenpois0n.app",
+                  "/APPlications/blackra1n.app",
+                  "/APPlications/blacksn0w.app",
+                  "/APPlications/redsn0w.app",
+                  "/APPlications/Absinthe.app"]
+       for app in apps {
+           //通过文件管理器,判断在指定的目录下,是否在对应的应用程序。如果存在的话。就表示当前设备为越狱设备。
+           if FileManager.default.fileExists(atPath: app){
+               return true
+           }
+       }
+       return false
+   }
+    
+}

+ 1 - 7
o2ios/O2Platform/UI/ZLCollectionView.swift

@@ -44,13 +44,7 @@ extension ZLCollectionView:UICollectionViewDataSource{
         
         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "itemCell", for: indexPath) as!  O2CollectionViewCell
         let app = self.apps[indexPath.section][indexPath.row]
-        if app.storyBoard! == "webview" {
-            cell.initImg(app: app)
-        }else{
-            cell.appIconImageView.image = UIImage(named: app.normalIcon!)
-            cell.appIconImageView.highlightedImage = UIImage(named: app.selectedIcon!)
-        }
-        cell.appTitle.text = app.title
+        cell.setAppData(app: app)
         return cell
     }
 }

+ 1 - 1
o2ios/Podfile

@@ -58,7 +58,7 @@ target 'O2Platform' do
     pod 'SDWebImage', '~>4.0'
     
     pod 'BSImagePicker', '~> 3.1.0'
-    pod 'Eureka', '~> 5.2.1'
+    pod 'Eureka', '~> 5.3.0'
     pod 'SwiftyTimer'
 
     pod 'Charts'

+ 5 - 5
o2ios/Podfile.lock

@@ -20,7 +20,7 @@ PODS:
   - CocoaLumberjack/Swift (3.5.3):
     - CocoaLumberjack/Core
   - EmptyDataSet-Swift (5.0.0)
-  - Eureka (5.2.1)
+  - Eureka (5.3.0)
   - FMDB (2.6.2):
     - FMDB/standard (= 2.6.2)
   - FMDB/standard (2.6.2)
@@ -89,7 +89,7 @@ DEPENDENCIES:
   - Chrysan
   - CocoaLumberjack/Swift (~> 3.5)
   - EmptyDataSet-Swift (~> 5.0.0)
-  - Eureka (~> 5.2.1)
+  - Eureka (~> 5.3.0)
   - FMDB (~> 2.6.2)
   - FSCalendar
   - HandyJSON (~> 5.0.2-beta)
@@ -179,7 +179,7 @@ SPEC CHECKSUMS:
   AlamofireImage: 78d67ccbb763d87ba44b21583d2153500a195630
   AlamofireNetworkActivityIndicator: 18346ff6d770d9513d0ac6f2d99706f40f93dbaa
   AlamofireObjectMapper: 3395e698901d8b0e6f48b7d0c43bd47875325102
-  BaiduMapKit: 075465cf7134d0ebf81796b93a59d504c350d9a4
+  BaiduMapKit: 0454428c2475489e3307c55eb67b5765b2cf7b05
   BetterSegmentedControl: b27bddbdff29b6cae988678d6cd106858986cd03
   BMKLocationKit: fd3d6b4a9a3a1a2763819f56b780bda5fc5b8726
   BSImagePicker: 86f28e0f63b78d35fec7c6f0174b7af9e6f1431e
@@ -188,7 +188,7 @@ SPEC CHECKSUMS:
   Chrysan: 6bf6682adb2db76f7f5c103930a8c6670f54eebe
   CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
   EmptyDataSet-Swift: eb382c0c87a2d9c678077385a595cec52da38171
-  Eureka: c883105488e05bc65539f583246ecf9657cabbfe
+  Eureka: 49239596c9d2eed9ab523990c34de62b6feac9f0
   FMDB: 854a0341b4726e53276f2a8996f06f1b80f9259a
   FSCalendar: 3a5ed3636e2ba1b83ebebfcf0c2603105a6f5efe
   HandyJSON: e18b035d60cb4847c609a59bb831c5db8c549663
@@ -220,6 +220,6 @@ SPEC CHECKSUMS:
   YHPhotoKit: e88368af1fca0a110d41b88417088f7e49876981
   YHPopupView: 96d9c05c79a2a17cf69c3def09e5305cfae9e8e8
 
-PODFILE CHECKSUM: 7994fed5103facb0bfff5a065e5612ebe4b411a2
+PODFILE CHECKSUM: 443a1a0e70d86c33975d3a07253f37c7f83d5d0a
 
 COCOAPODS: 1.8.4

+ 3 - 1
o2server/configSample/centerServer.json

@@ -12,6 +12,7 @@
   "statEnable": true,
   "statExclusions": "*.js,*.gif,*.jpg,*.png,*.css,*.ico",
   "maxFormContent": 20.0,
+  "exposeJest": true,
   "###enable": "是否启用###",
   "###order": "center节点顺序,顺序排列0,1,2...###",
   "###sslEnable": "是否启用ssl传输加密,如果启用将使用config/keystore文件作为密钥文件.使用config/token.json文件中的sslKeyStorePassword字段为密钥密码,sslKeyManagerPassword为管理密码.###",
@@ -25,5 +26,6 @@
   "###configApiEnable": "允许通过Api修改config###",
   "###statEnable": "启用统计,默认启用统计.###",
   "###statExclusions": "统计忽略路径,默认忽略*.js,*.gif,*.jpg,*.png,*.css,*.ico###",
-  "###maxFormContent": "最大提交数据限制(M),限制有所上传的内容大小,包括附件.###"
+  "###maxFormContent": "最大提交数据限制(M),限制有所上传的内容大小,包括附件.###",
+  "###exposeJest": "暴露jest接口.###"
 }

+ 10 - 20
o2server/configSample/components.json

@@ -160,16 +160,6 @@
       "allowList": [],
       "dentyList": []
     },
-    {
-      "name": "File",
-      "path": "File",
-      "title": "云文件",
-      "iconPath": "appicon.png",
-      "orderNumber": 16.0,
-      "type": "system",
-      "allowList": [],
-      "dentyList": []
-    },
     {
       "name": "Note",
       "path": "Note",
@@ -190,16 +180,6 @@
       "allowList": [],
       "dentyList": []
     },
-    {
-      "name": "OnlineMeeting",
-      "path": "OnlineMeeting",
-      "title": "网络会议",
-      "iconPath": "appicon.png",
-      "orderNumber": 19.0,
-      "type": "system",
-      "allowList": [],
-      "dentyList": []
-    },
     {
       "name": "Attendance",
       "path": "Attendance",
@@ -259,6 +239,16 @@
       "type": "system",
       "allowList": [],
       "dentyList": []
+    },
+    {
+      "name": "IMV2",
+      "path": "IMV2",
+      "title": "聊天",
+      "iconPath": "appicon.png",
+      "orderNumber": 26.0,
+      "type": "system",
+      "allowList": [],
+      "dentyList": []
     }
   ],
   "###systems": "默认模块###"

+ 4 - 1
o2server/configSample/dumpRestoreData.json

@@ -6,11 +6,14 @@
   "parallel": true,
   "redistribute": true,
   "exceptionInvalidStorage": true,
+  "itemCategory": "",
   "###enable": "是否启用.###",
   "###includes": "导出导入包含对象,可以使用通配符*.###",
   "###excludes": "导出导入排除对象,可以使用通配符*.###",
   "###mode": "导出数据模式,lite|full,默认使用lite###",
   "###parallel": "使用并行导出,默认true###",
   "###redistribute": "是否进行重新分布.###",
-  "###exceptionInvalidStorage": "无法获取storage是否升起错误.###"
+  "###exceptionInvalidStorage": "无法获取storage是否升起错误.###",
+  "###restoreOverride": "数据导入方式,clean:清空重新导入,skipExisted:如果有相同id的数据跳过.默认方式为clean.###",
+  "###itemCategory": "对于com.x.query.core.entity.Item的itemCategory进行单独过滤,可选值pp, cms, bbs, pp_dict.###"
 }

+ 7 - 3
o2server/configSample/node_127.0.0.1.json

@@ -15,6 +15,7 @@
     "statEnable": true,
     "statExclusions": "*.js,*.gif,*.jpg,*.png,*.css,*.ico",
     "maxFormContent": 20.0,
+    "exposeJest": true,
     "###enable": "是否启用###",
     "###order": "center节点顺序,顺序排列0,1,2...###",
     "###sslEnable": "是否启用ssl传输加密,如果启用将使用config/keystore文件作为密钥文件.使用config/token.json文件中的sslKeyStorePassword字段为密钥密码,sslKeyManagerPassword为管理密码.###",
@@ -28,7 +29,8 @@
     "###configApiEnable": "允许通过Api修改config###",
     "###statEnable": "启用统计,默认启用统计.###",
     "###statExclusions": "统计忽略路径,默认忽略*.js,*.gif,*.jpg,*.png,*.css,*.ico###",
-    "###maxFormContent": "最大提交数据限制(M),限制有所上传的内容大小,包括附件.###"
+    "###maxFormContent": "最大提交数据限制(M),限制有所上传的内容大小,包括附件.###",
+    "###exposeJest": "暴露jest接口.###"
   },
   "application": {
     "enable": true,
@@ -45,6 +47,7 @@
     "statEnable": true,
     "statExclusions": "*.js,*.gif,*.jpg,*.png,*.css,*.ico",
     "maxFormContent": 20.0,
+    "exposeJest": true,
     "###enable": "是否启用###",
     "###port": "http/https端口,负责向前端提供数据访问接口.默认为20020端口.###",
     "###sslEnable": "是否启用ssl传输加密,如果启用将使用config/keystore文件作为密钥文件.使用config/token.json文件中的sslKeyStorePassword字段为密钥密码,sslKeyManagerPassword为管理密码.###",
@@ -58,7 +61,8 @@
     "###scheduleWeights": "设置应用的定时任务权重,在集群环境中,一个应用可以部署多个实例提供负载均衡.通过合计占比来分配应用占比.###",
     "###statEnable": "启用统计,默认启用统计.###",
     "###statExclusions": "统计忽略路径,默认忽略*.js,*.gif,*.jpg,*.png,*.css,*.ico###",
-    "###maxFormContent": "最大提交数据限制(M),限制有所上传的内容大小,包括附件.###"
+    "###maxFormContent": "最大提交数据限制(M),限制有所上传的内容大小,包括附件.###",
+    "###exposeJest": "暴露jest接口.###"
   },
   "web": {
     "enable": true,
@@ -104,7 +108,7 @@
     "###excludes": "在此节点上不存储的类,和includes一起设置实际存储的类,可以使用通配符*###",
     "###jmxEnable": "是否启动jmx,如果启用,可以通过本地的jmx客户端进行访问,不支持远程jmx客户端.###",
     "###cacheSize": "H2数据库缓存大小,设置H2用于作为缓存的内存大小,以M作为单位,这里默认为512M.###",
-    "###logLevel": "默认日志级别###",
+    "###logLevel": "默认日志级别,FATAL, ERROR, WARN, INFO, TRACE. 完成的配置为DefaultLevel\u003dWARN, Tool\u003dTRACE, Enhance\u003dTRACE, METADATA\u003dTRACE, Runtime\u003dTRACE, Query\u003dTRACE, DataCache\u003dTRACE, JDBC\u003dTRACE, SQL\u003dTRACE###",
     "###maxTotal": "最大使用连接数###",
     "###maxIdle": "最大空闲连接数###",
     "###statEnable": "启用统计,默认启用###",

+ 2 - 0
o2server/configSample/person.json

@@ -10,6 +10,7 @@
   "passwordRegexHint": "6位以上,包含数字和字母.",
   "register": "disable",
   "superPermission": true,
+  "tokenCookieHttpOnly": false,
   "personUnitOrderByAsc": true,
   "###captchaLogin": "是否启用验证码登录,默认值:true###",
   "###codeLogin": "是否启用验证码登录,默认值:true###",
@@ -34,5 +35,6 @@
   "###failureInterval": "登录限制时间(分钟)###",
   "###failureCount": "尝试登录次数###",
   "###tokenExpiredMinutes": "token时长,分钟###",
+  "###tokenCookieHttpOnly": "保存token的cookie是否启用httpOnly###",
   "###personUnitOrderByAsc": "人员组织排序是否为升序,true为升序(默认),false为降序###"
 }

+ 5 - 3
o2server/configSample/processPlatform.json

@@ -26,13 +26,15 @@
     "###enable": "是否启用###",
     "###cron": "定时cron表达式###"
   },
-  "combine": {
+  "merge": {
     "enable": false,
     "cron": "30 30 6 * * ?",
     "thresholdDays": 730.0,
+    "batchSize": 100.0,
     "###enable": "是否启用###",
     "###cron": "定时cron表达式###",
-    "###thresholdDays": "期限,已完成工作结束间隔指定时间进行combine,默认两年后进行combine###"
+    "###thresholdDays": "期限,已完成工作结束间隔指定时间进行merge,默认两年后进行merge###",
+    "###batchSize": "批量大小.###"
   },
   "deleteDraft": {
     "enable": false,
@@ -69,7 +71,7 @@
   "###urge": "催办任务设置,发现即将过期时发送提醒消息.###",
   "###expire": "将已经过了截至时间的待办标记过期.###",
   "###touchDelay": "延时任务设置,定时触发延时任务,当超过延时时间后继续流转.###",
-  "###combine": "合并任务设置,定时触发合并任务,将已完成工作的Data从Item表中提取合并到WorkCompleted的Data字段中,默认工作完成后2年开始进行合并.###",
+  "###merge": "合并任务设置,定时触发合并任务,将已完成工作的Data从Item表中提取合并到WorkCompleted的Data字段中,默认工作完成后2年开始进行合并.###",
   "###deleteDraft": "清除草稿状态的工作.###",
   "###passExpired": "超时工作路由设置.###",
   "###touchDetained": "触发长时间未处理的工作.###",

+ 1 - 0
o2server/console_mips.sh

@@ -0,0 +1 @@
+$(cd "$(dirname "$0")"; pwd)/jvm/mips/bin/java -javaagent:$(cd "$(dirname "$0")"; pwd)/console.jar -cp $(cd "$(dirname "$0")"; pwd)/console.jar com.x.server.console.Shadow

+ 0 - 1
o2server/console_raspberrypi.sh

@@ -1 +0,0 @@
-sudo $(cd "$(dirname "$0")"; pwd)/jvm/raspberrypi/bin/java -javaagent:$(cd "$(dirname "$0")"; pwd)/console.jar -cp $(cd "$(dirname "$0")"; pwd)/console.jar com.x.server.console.Shadow

+ 1 - 0
o2server/console_raspi.sh

@@ -0,0 +1 @@
+sudo $(cd "$(dirname "$0")"; pwd)/jvm/raspi/bin/java -javaagent:$(cd "$(dirname "$0")"; pwd)/console.jar -cp $(cd "$(dirname "$0")"; pwd)/console.jar com.x.server.console.Shadow

+ 0 - 1
o2server/console_risc.sh

@@ -1 +0,0 @@
-$(cd "$(dirname "$0")"; pwd)/jvm/risc/bin/java -javaagent:$(cd "$(dirname "$0")"; pwd)/console.jar -cp $(cd "$(dirname "$0")"; pwd)/console.jar com.x.server.console.Shadow

+ 0 - 7
o2server/pom.xml

@@ -29,7 +29,6 @@
 		<module>x_meeting_core_entity</module>
 		<module>x_message_core_entity</module>
 		<module>x_mind_core_entity</module>
-		<module>x_okr_core_entity</module>
 		<module>x_organization_core_entity</module>
 		<module>x_portal_core_entity</module>
 		<module>x_processplatform_core_entity</module>
@@ -50,7 +49,6 @@
 		<module>x_meeting_assemble_control</module>
 		<module>x_message_assemble_communicate</module>
 		<module>x_mind_assemble_control</module>
-		<module>x_okr_assemble_control</module>
 		<module>x_organization_assemble_authentication</module>
 		<module>x_organization_assemble_control</module>
 		<module>x_organization_assemble_express</module>
@@ -929,11 +927,6 @@
 				<artifactId>x_mind_core_entity</artifactId>
 				<version>5</version>
 			</dependency>
-			<dependency>
-				<groupId>o2oa</groupId>
-				<artifactId>x_okr_core_entity</artifactId>
-				<version>5</version>
-			</dependency>
 			<dependency>
 				<groupId>o2oa</groupId>
 				<artifactId>x_organization_core_entity</artifactId>

+ 24 - 24
o2server/start_aix.sh

@@ -108,41 +108,41 @@ if [ -d ${current_dir}/local/update ]; then
 		if [ -f ${current_dir}/console_aix.sh ]; then
 			cp -f ${current_dir}/local/update/o2server/console_aix.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/start_raspberrypi.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/start_raspberrypi.sh ${current_dir}/
+		if [ -f ${current_dir}/start_raspi.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/start_raspi.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/start_raspberrypi_debug.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/start_raspberrypi_debug.sh ${current_dir}/
+		if [ -f ${current_dir}/start_raspi_debug.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/start_raspi_debug.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/stop_raspberrypi.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/stop_raspberrypi.sh ${current_dir}/
+		if [ -f ${current_dir}/stop_raspi.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/stop_raspi.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/console_raspberrypi.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/console_raspberrypi.sh ${current_dir}/
+		if [ -f ${current_dir}/console_raspi.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/console_raspi.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/start_risc.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/start_risc.sh ${current_dir}/
+		if [ -f ${current_dir}/start_mips.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/start_mips.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/start_risc_debug.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/start_risc_debug.sh ${current_dir}/
+		if [ -f ${current_dir}/start_mips_debug.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/start_mips_debug.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/stop_risc.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/stop_risc.sh ${current_dir}/
+		if [ -f ${current_dir}/stop_mips.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/stop_mips.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/console_risc.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/console_risc.sh ${current_dir}/
+		if [ -f ${current_dir}/console_mips.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/console_mips.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/start_kylinos_phytium.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/start_kylinos_phytium.sh ${current_dir}/
+		if [ -f ${current_dir}/start_arm.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/start_arm.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/start_kylinos_phytium_debug.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/start_kylinos_phytium_debug.sh ${current_dir}/
+		if [ -f ${current_dir}/start_arm_debug.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/start_arm_debug.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/stop_kylinos_phytium.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/stop_kylinos_phytium.sh ${current_dir}/
+		if [ -f ${current_dir}/stop_arm.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/stop_arm.sh ${current_dir}/
 		fi
-		if [ -f ${current_dir}/console_kylinos_phytium.sh ]; then
-			cp -f ${current_dir}/local/update/o2server/console_kylinos_phytium.sh ${current_dir}/
+		if [ -f ${current_dir}/console_arm.sh ]; then
+			cp -f ${current_dir}/local/update/o2server/console_arm.sh ${current_dir}/
 		fi
 		cp ${current_dir}/local/update/o2server/version.o2 ${current_dir}/
 		rm -Rf ${current_dir}/local/update

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff