南鑫林 пре 6 година
родитељ
комит
b18956b508
100 измењених фајлова са 10435 додато и 0 уклоњено
  1. 25 0
      RainbowPlanet/.gitignore
  2. 90 0
      RainbowPlanet/Podfile
  3. 178 0
      RainbowPlanet/Podfile.lock
  4. 2068 0
      RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj
  5. 112 0
      RainbowPlanet/RainbowPlanet.xcodeproj/xcshareddata/xcschemes/RainbowPlanet.xcscheme
  6. 68 0
      RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate+HandleOpen.swift
  7. 70 0
      RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate+Window.swift
  8. 31 0
      RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate.swift
  9. 26 0
      RainbowPlanet/RainbowPlanet/Base/BaseNavigationController/BaseNavigationViewController.swift
  10. 51 0
      RainbowPlanet/RainbowPlanet/Base/BaseTabbarViewController/BaseTabbarViewController.swift
  11. 33 0
      RainbowPlanet/RainbowPlanet/Base/BaseView/BaseView.swift
  12. 64 0
      RainbowPlanet/RainbowPlanet/Base/BaseViewController/BaseViewController.swift
  13. 30 0
      RainbowPlanet/RainbowPlanet/Base/BaseWebViewController/BaseWebViewController.swift
  14. 17 0
      RainbowPlanet/RainbowPlanet/Define/CacheMacro.swift
  15. 75 0
      RainbowPlanet/RainbowPlanet/Define/ColorMacro.swift
  16. 153 0
      RainbowPlanet/RainbowPlanet/Define/Common.swift
  17. 9 0
      RainbowPlanet/RainbowPlanet/Define/EnumMacro.swift
  18. 81 0
      RainbowPlanet/RainbowPlanet/Define/FontMacro.swift
  19. 14 0
      RainbowPlanet/RainbowPlanet/Define/HTMLURLMacro.swift
  20. 13 0
      RainbowPlanet/RainbowPlanet/Define/NotificationCenterMacro.swift
  21. 42 0
      RainbowPlanet/RainbowPlanet/Define/RainbowPlanet-Bridging-Header.h
  22. 40 0
      RainbowPlanet/RainbowPlanet/Define/ThirdPartyMacro.swift
  23. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/alipay_msp_back@2x.png
  24. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/alipay_msp_refresh@2x.png
  25. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/bar@2x.png
  26. 1 0
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/bridge.js
  27. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/refresh@2x.png
  28. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/refresh_click@2x.png
  29. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/shutdown@2x.png
  30. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/shutdown_click@2x.png
  31. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/AlipaySDK
  32. BIN
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/AlipaySDK-inside-Info.plist
  33. 33 0
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/Headers/APayAuthInfo.h
  34. 203 0
      RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/Headers/AlipaySDK.h
  35. 98 0
      RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/README.txt
  36. 196 0
      RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/WXApi.h
  37. 1101 0
      RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/WXApiObject.h
  38. 68 0
      RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/WechatAuthSDK.h
  39. BIN
      RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/libWeChatSDK.a
  40. 26 0
      RainbowPlanet/RainbowPlanet/Manager/IQKeyboardManagerSwiftManager/IQKeyboardManagerSwiftManager.swift
  41. 121 0
      RainbowPlanet/RainbowPlanet/Manager/MapManager/AMapManager/AMapLocationModel.swift
  42. 201 0
      RainbowPlanet/RainbowPlanet/Manager/MapManager/AMapManager/AMapManager.swift
  43. 147 0
      RainbowPlanet/RainbowPlanet/Manager/MapManager/BaiduMapManager/BaiduMapManager.swift
  44. 119 0
      RainbowPlanet/RainbowPlanet/Manager/MapManager/BaiduMapManager/LocationModel.swift
  45. 111 0
      RainbowPlanet/RainbowPlanet/Manager/PayManager/AlipayManager/AlipayManager.swift
  46. 203 0
      RainbowPlanet/RainbowPlanet/Manager/PayManager/AlipayManager/AlipayResultModel.swift
  47. 83 0
      RainbowPlanet/RainbowPlanet/Manager/PayManager/PayManager/PayManager.swift
  48. 93 0
      RainbowPlanet/RainbowPlanet/Manager/PayManager/WeChatpayManager/WeChatpayManager.swift
  49. 46 0
      RainbowPlanet/RainbowPlanet/Manager/PayManager/WeChatpayManager/WeChatpayOrderModel.swift
  50. 17 0
      RainbowPlanet/RainbowPlanet/Manager/UMManager/UMLoginModel.swift
  51. 398 0
      RainbowPlanet/RainbowPlanet/Manager/UMManager/UMManager.swift
  52. 39 0
      RainbowPlanet/RainbowPlanet/Modules/MineModule/Mine/ViewController/MineViewController.swift
  53. 53 0
      RainbowPlanet/RainbowPlanet/Modules/MineModule/Mine/ViewController/MineViewController.xib
  54. 294 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/BindPhoneNumber/ViewController/BindPhoneNumberViewController.swift
  55. 106 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PasswordLogin/ViewController/PasswordLoginViewController.swift
  56. 132 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PasswordLogin/ViewController/PasswordLoginViewController.xib
  57. 128 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/Model/PhoneCountryAreaListMdoel.swift
  58. 30 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/View/PhoneCountryAreaSectionHeaderView.swift
  59. 13 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/View/PhoneCountryAreaSectionView.swift
  60. 102 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/View/PhoneCountryAreaTableViewCell.swift
  61. 105 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/ViewController/PhoneCountryAreaViewController.swift
  62. 72 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/RegisterLogin/View/RegisterLoginView.swift
  63. 51 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/RegisterLogin/ViewController/RegisterLoginViewController.swift
  64. 132 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/VerificationPhone/ViewController/VerificationPhoneViewController.swift
  65. 160 0
      RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/VerificationPhone/ViewController/VerificationPhoneViewController.xib
  66. 29 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingCartModule/ShoppingCart/ViewController/ShoppingCartViewController.swift
  67. 36 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingCartModule/ShoppingCart/ViewController/ShoppingCartViewController.xib
  68. 174 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/ShoppingMallNavigationBarView.swift
  69. 259 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/ShoppingMallView.swift
  70. 62 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalListCellCollectionViewCell.swift
  71. 14 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalListCellModel.swift
  72. 14 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalListSectionModel.swift
  73. 55 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalSectionHeaderView.swift
  74. 89 0
      RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/ViewController/ShoppingMallViewController.swift
  75. 8 0
      RainbowPlanet/RainbowPlanet/RainbowPlanet.entitlements
  76. 54 0
      RainbowPlanet/RainbowPlanet/Service/Model/RootModel/InfoModel.swift
  77. 78 0
      RainbowPlanet/RainbowPlanet/Service/Model/RootModel/PaginationModel.swift
  78. 63 0
      RainbowPlanet/RainbowPlanet/Service/Model/RootModel/RootModel.swift
  79. 128 0
      RainbowPlanet/RainbowPlanet/Service/Model/UserModel/LoginModel.swift
  80. 83 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaNetWorkManager/ApiMacro.swift
  81. 392 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaNetWorkManager/SwiftMoyaNetWorkManager.swift
  82. 58 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServicePay/SwiftMoyaNetWorkServicePay.swift
  83. 88 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServicePay/SwiftMoyaServicePayApi.swift
  84. 48 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceSMS/SwiftMoyaNetWorkServiceSMS.swift
  85. 103 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceSMS/SwiftMoyaServiceSMSApi.swift
  86. 199 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceUser/SwiftMoyaNetWorkServiceUser.swift
  87. 183 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceUser/SwiftMoyaServiceUserApi.swift
  88. 130 0
      RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftSign/SwiftSign.swift
  89. 116 0
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json
  90. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadApp_76pt.png
  91. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadApp_76pt@2x.png
  92. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadNotifications_20pt.png
  93. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadNotifications_20pt@2x.png
  94. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadProApp_83.5pt@2x.png
  95. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight5_29pt.png
  96. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight5_29pt@2x.png
  97. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight7_40pt.png
  98. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight7_40pt@2x.png
  99. BIN
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPhoneApp_60pt@2x.png
  100. 0 0
      RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPhoneApp_60pt@3x.png

+ 25 - 0
RainbowPlanet/.gitignore

@@ -0,0 +1,25 @@
+# Xcode
+.DS_Store
+*/build/*
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+profile
+*.moved-aside
+DerivedData
+.idea/
+*.hmap
+*.xccheckout
+*.xcworkspace
+!default.xcworkspace
+
+#CocoaPods
+Pods
+!Podfile
+!Podfile.lock

+ 90 - 0
RainbowPlanet/Podfile

@@ -0,0 +1,90 @@
+# Uncomment the next line to define a global platform for your project
+ platform :ios, '9.0'
+
+target 'RainbowPlanet' do
+  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
+  inhibit_all_warnings!
+  use_frameworks!
+  # 网络请求
+  pod 'Alamofire'
+  pod 'Moya/RxSwift'
+  # Rx
+  pod 'RxSwift'
+  pod 'RxCocoa'
+  # json解析
+  pod 'SwiftyJSON'
+  pod 'ObjectMapper'
+  # MoyaMapper
+#  pod 'MoyaMapper'
+#  pod 'MoyaMapper/Rx'
+  pod 'MoyaMapper/MMCache'
+#  pod 'MoyaMapper/RxCache'
+  # 图片加载
+  pod 'Kingfisher'
+#  pod 'Nuke'
+#  pod 'Nuke-WebP-Plugin'
+#  pod 'Gifu'
+  # 自动布局
+  pod 'SnapKit'
+  pod 'TangramKit'
+  # 键盘
+  pod 'IQKeyboardManagerSwift'
+  # 弹框
+  pod 'MBProgressHUD'
+  # 下拉刷新
+  pod 'MJRefresh'
+  # 设备型号
+  pod 'DeviceKit'
+  # 内存检测
+  pod 'MLeaksFinder'
+  # 占位图
+  pod 'LYEmptyView'
+  # 分段导航栏
+  pod 'JXCategoryView'
+  # 轮播
+  pod 'FSPagerView'
+  # 评分
+  pod 'SwiftyStarRatingView'
+  # 二维码
+#  pod 'EFQRCode'
+  # 小红点
+#  pod 'PPBadgeViewSwift'
+  # pop动画
+  pod 'FWPopupView'
+  # 存储数据Keychain
+  pod 'KeychainAccess'
+  # mvvm
+#  pod 'ReactorKit'
+  # 富文本
+  pod 'RichEditorView'
+
+  #======================第三方平台===========
+  #======================友盟===========
+  # UM基础库
+  pod 'UMCCommon'
+  pod 'UMCSecurityPlugins'
+  # 日志库(调试)
+  pod 'UMCCommonLog'
+  # 统计 SDK
+  pod 'UMCAnalytics'
+  # Push SDK
+  pod 'UMCPush'
+  # U-Share SDK UI模块(分享面板,建议添加)
+  pod 'UMCShare/UI'
+  # 集成微信(精简版0.2M)
+  pod 'UMCShare/Social/ReducedWeChat'
+  # 集成QQ/QZone/TIM(精简版0.5M)
+  pod 'UMCShare/Social/ReducedQQ'
+  # 集成新浪微博(精简版1M)
+  pod 'UMCShare/Social/ReducedSina'
+
+  #=====================百度地图===========
+  #百度地图定位SDK
+  pod 'BMKLocationKit'
+
+  #=====================高德地图===========
+  #高德地图定位SDK
+  pod 'AMapLocation'
+
+
+end

+ 178 - 0
RainbowPlanet/Podfile.lock

@@ -0,0 +1,178 @@
+PODS:
+  - Alamofire (4.8.2)
+  - AMapFoundation (1.5.6)
+  - AMapLocation (2.6.1):
+    - AMapFoundation (~> 1.4)
+  - BMKLocationKit (1.5.0)
+  - Cache (5.2.0)
+  - DeviceKit (1.13.0)
+  - FBRetainCycleDetector (0.1.4)
+  - FSPagerView (0.8.2)
+  - FWPopupView (4.0.1):
+    - SnapKit
+  - IQKeyboardManagerSwift (6.2.1)
+  - JXCategoryView (1.3.0)
+  - KeychainAccess (3.2.0)
+  - Kingfisher (4.10.1)
+  - LYEmptyView (1.2.3)
+  - MBProgressHUD (1.1.0)
+  - MJRefresh (3.1.16)
+  - MLeaksFinder (1.0.0):
+    - FBRetainCycleDetector
+  - Moya (12.0.1):
+    - Moya/Core (= 12.0.1)
+  - Moya/Core (12.0.1):
+    - Alamofire (~> 4.1)
+    - Result (~> 4.0)
+  - Moya/RxSwift (12.0.1):
+    - Moya/Core
+    - RxSwift (~> 4.0)
+  - MoyaMapper/Core (1.2.1):
+    - Moya (>= 11.0.0)
+    - SwiftyJSON
+  - MoyaMapper/MMCache (1.2.1):
+    - Cache
+    - MoyaMapper/Core
+  - ObjectMapper (3.4.2)
+  - Result (4.1.0)
+  - RichEditorView (5.0.0)
+  - RxCocoa (4.5.0):
+    - RxSwift (>= 4.4.2, ~> 4.4)
+  - RxSwift (4.5.0)
+  - SnapKit (4.2.0)
+  - SwiftyJSON (4.3.0)
+  - SwiftyStarRatingView (1.0.4)
+  - TangramKit (1.3.1)
+  - UMCAnalytics (6.0.3):
+    - UMCCommon
+  - UMCCommon (2.0.1)
+  - UMCCommonLog (1.0.0)
+  - UMCPush (3.2.4):
+    - UMCCommon
+  - UMCSecurityPlugins (1.0.6)
+  - UMCShare/Core (6.9.5):
+    - UMCCommon
+  - UMCShare/Social/ReducedQQ (6.9.5):
+    - UMCCommon
+    - UMCShare/Core
+  - UMCShare/Social/ReducedSina (6.9.5):
+    - UMCCommon
+    - UMCShare/Core
+  - UMCShare/Social/ReducedWeChat (6.9.5):
+    - UMCCommon
+    - UMCShare/Core
+  - UMCShare/UI (6.9.5):
+    - UMCCommon
+    - UMCShare/Core
+
+DEPENDENCIES:
+  - Alamofire
+  - AMapLocation
+  - BMKLocationKit
+  - DeviceKit
+  - FSPagerView
+  - FWPopupView
+  - IQKeyboardManagerSwift
+  - JXCategoryView
+  - KeychainAccess
+  - Kingfisher
+  - LYEmptyView
+  - MBProgressHUD
+  - MJRefresh
+  - MLeaksFinder
+  - Moya/RxSwift
+  - MoyaMapper/MMCache
+  - ObjectMapper
+  - RichEditorView
+  - RxCocoa
+  - RxSwift
+  - SnapKit
+  - SwiftyJSON
+  - SwiftyStarRatingView
+  - TangramKit
+  - UMCAnalytics
+  - UMCCommon
+  - UMCCommonLog
+  - UMCPush
+  - UMCSecurityPlugins
+  - UMCShare/Social/ReducedQQ
+  - UMCShare/Social/ReducedSina
+  - UMCShare/Social/ReducedWeChat
+  - UMCShare/UI
+
+SPEC REPOS:
+  https://github.com/cocoapods/specs.git:
+    - Alamofire
+    - AMapFoundation
+    - AMapLocation
+    - BMKLocationKit
+    - Cache
+    - DeviceKit
+    - FBRetainCycleDetector
+    - FSPagerView
+    - FWPopupView
+    - IQKeyboardManagerSwift
+    - JXCategoryView
+    - KeychainAccess
+    - Kingfisher
+    - LYEmptyView
+    - MBProgressHUD
+    - MJRefresh
+    - MLeaksFinder
+    - Moya
+    - MoyaMapper
+    - ObjectMapper
+    - Result
+    - RichEditorView
+    - RxCocoa
+    - RxSwift
+    - SnapKit
+    - SwiftyJSON
+    - SwiftyStarRatingView
+    - TangramKit
+    - UMCAnalytics
+    - UMCCommon
+    - UMCCommonLog
+    - UMCPush
+    - UMCSecurityPlugins
+    - UMCShare
+
+SPEC CHECKSUMS:
+  Alamofire: ae5c501addb7afdbb13687d7f2f722c78734c2d3
+  AMapFoundation: 20fce2a12cd152e1092afdd04379cdac21932185
+  AMapLocation: cf024b53dc03663efb4ea4bcce27d4cce58bb97a
+  BMKLocationKit: 40d267478acd8704ddebd0e9deaddc727b13df9f
+  Cache: 807c5d86d01a177f06ede9865add3aea269bbfd4
+  DeviceKit: 5a4accdb2918ce0b69e62dc3bef6e4d2cc06e2e4
+  FBRetainCycleDetector: 46f8179bbb1c587deee3ea838a1a3ee02acf5015
+  FSPagerView: 816a18842306973cc7cc6df8a5332272f7815c30
+  FWPopupView: a463a17aab606b0ef222a68784dbf32accba4711
+  IQKeyboardManagerSwift: 0f0ae8935360b4003e6ea1ac7c19898f01e2f7c7
+  JXCategoryView: b3bf1bedb51b5f98b63d51f0e31007a2ef80de14
+  KeychainAccess: 3b1bf8a77eb4c6ea1ce9404c292e48f948954c6b
+  Kingfisher: c148cd7b47ebde9989f6bc7c27dcaa79d81279a0
+  LYEmptyView: ea5827f3f81fcbec427f990005501991477bdae8
+  MBProgressHUD: e7baa36a220447d8aeb12769bf0585582f3866d9
+  MJRefresh: 7798e16e53a5ef7f332dd05b27664db4e29530fd
+  MLeaksFinder: 8c435bd2f6d070af18cff082b503b21adc130fc0
+  Moya: cf730b3cd9e005401ef37a85143aa141a12fd38f
+  MoyaMapper: 18b9351707f53778d263a987e740252f039521ba
+  ObjectMapper: 0d4402610f4e468903ae64629eec4784531e5c51
+  Result: bd966fac789cc6c1563440b348ab2598cc24d5c7
+  RichEditorView: 1bbb07b87ca2d479ac29a6877014b38b8df233ef
+  RxCocoa: cbf70265dc65a981d4ac982e513c10cf23df24a0
+  RxSwift: f172070dfd1a93d70a9ab97a5a01166206e1c575
+  SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a
+  SwiftyJSON: 6faa0040f8b59dead0ee07436cbf76b73c08fd08
+  SwiftyStarRatingView: a2b0057700e0adeb8e7442c55d99cb53b531d2f4
+  TangramKit: 1b4ee065845919057bdbe930ba39deecbbff181e
+  UMCAnalytics: ff58714ada407682c4a07548156f94bcec92f055
+  UMCCommon: 0263a057a2e1ae1da4c8308541e56904a493ce13
+  UMCCommonLog: 05a2d5de21858e3d870551562cff405c1366d244
+  UMCPush: 1edd856027dcf905333effb4040ace5d236a7316
+  UMCSecurityPlugins: 0831a08f3988f3cea9f1d3a7626cd9bee4fef150
+  UMCShare: 552b29753f1b4da87b51d96545ed19e6263df397
+
+PODFILE CHECKSUM: 1ef546321eb73a0d3ddae7f684d9d4ccb085d748
+
+COCOAPODS: 1.6.1

Разлика између датотеке није приказан због своје велике величине
+ 2068 - 0
RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj


+ 112 - 0
RainbowPlanet/RainbowPlanet.xcodeproj/xcshareddata/xcschemes/RainbowPlanet.xcscheme

@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1020"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "A77F2C5C2231FB49001BD3F6"
+               BuildableName = "RainbowPlanet.app"
+               BlueprintName = "RainbowPlanet"
+               ReferencedContainer = "container:RainbowPlanet.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "A77F2C702231FB4A001BD3F6"
+               BuildableName = "RainbowPlanetTests.xctest"
+               BlueprintName = "RainbowPlanetTests"
+               ReferencedContainer = "container:RainbowPlanet.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "A77F2C7B2231FB4A001BD3F6"
+               BuildableName = "RainbowPlanetUITests.xctest"
+               BlueprintName = "RainbowPlanetUITests"
+               ReferencedContainer = "container:RainbowPlanet.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "A77F2C5C2231FB49001BD3F6"
+            BuildableName = "RainbowPlanet.app"
+            BlueprintName = "RainbowPlanet"
+            ReferencedContainer = "container:RainbowPlanet.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      disableMainThreadChecker = "YES"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "A77F2C5C2231FB49001BD3F6"
+            BuildableName = "RainbowPlanet.app"
+            BlueprintName = "RainbowPlanet"
+            ReferencedContainer = "container:RainbowPlanet.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "A77F2C5C2231FB49001BD3F6"
+            BuildableName = "RainbowPlanet.app"
+            BlueprintName = "RainbowPlanet"
+            ReferencedContainer = "container:RainbowPlanet.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 68 - 0
RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate+HandleOpen.swift

@@ -0,0 +1,68 @@
+//
+//  AppDelegate+HandleOpen.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import Foundation
+
+//MARK: - 设置系统回调
+extension AppDelegate {
+    //仅支持iOS9以上系统,iOS8及以下系统不会回调
+    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
+        //6.3的新的API调用,是为了兼容国外平台(例如:新版facebookSDK,VK等)的调用[如果用6.2的api调用会没有回调],对国内平台没有影响
+        var result = UMSocialManager.default().handleOpen(url, options: options)
+        if (!result) {
+            // 其他如支付等SDK的回调
+            result = PayManager.shared().handleOpen(url: url)
+            return result
+        }
+        return result;
+    }
+    //支持目前所有iOS系统
+    func application(_ application: UIApplication, handleOpen url: URL) -> Bool {
+        var result = UMSocialManager.default().handleOpen(url)
+        if (!result) {
+            // 其他如支付等SDK的回调
+            result = PayManager.shared().handleOpen(url: url)
+            return result
+        }
+        return result;
+    }
+
+    //iOS10以下使用这两个方法接收通知,
+    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
+        //关闭友盟自带的弹出框
+        UMessage.setAutoAlert(true)
+        if #available(iOS 9.0, *)  {
+            if #available(iOS 10.0, *){
+            }else {
+                UMessage.didReceiveRemoteNotification(userInfo)
+                completionHandler(UIBackgroundFetchResult.newData);
+            }
+        }
+    }
+
+    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
+        //关闭友盟自带的弹出框
+        UMessage.setAutoAlert(true)
+        if #available(iOS 9.0, *)  {
+            if #available(iOS 10.0, *){
+            }else {
+                UMessage.didReceiveRemoteNotification(userInfo)
+            }
+        }
+    }
+
+    /// 获取设备的 DeviceToken
+    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
+        var tokenString = ""
+        for byte in deviceToken {
+            let hexString = String(format: "%02x", byte)
+            tokenString += hexString
+        }
+        NXLLog(tokenString)
+    }
+}

+ 70 - 0
RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate+Window.swift

@@ -0,0 +1,70 @@
+//
+//  AppDelegate+Window.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/6/30.
+//  Copyright © 2018年 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+extension AppDelegate {
+
+    func initWindow() {
+        
+        window = UIWindow.init(frame: UIScreen.main.bounds)
+        window?.backgroundColor = UIColor.white
+        window?.makeKeyAndVisible()
+
+
+        if (LoginModel.shared().getLoginModel()?.token) != nil  {
+            /// 设置Tabbar
+           setTabbarController()
+        } else {
+            /// 设置登录
+            setLoginController()
+        }
+
+        /// 设置全局的tabbar
+        setTabbarAppearence()
+
+        /// 设置全局的navigation
+        setNavBarAppearence()
+
+        /// 引导页
+        setGuidePageView()
+
+        /// 刷新token
+        SwiftMoyaNetWorkServiceUser.shared().userRefreshApi {_ in }
+
+    }
+    
+    /// 设置Tabbar
+    func setTabbarController() {
+        self.window?.rootViewController = BaseTabbarViewController.shared().tabBarViewController()
+    }
+
+    /// 设置Login
+    func setLoginController() {
+        self.window?.rootViewController = RegisterLoginViewController()
+    }
+
+     /// 设置全局的navigation
+    func setNavBarAppearence() {
+        WRNavigationBar.defaultStatusBarStyle = .default
+    }
+
+    ///设置全局的Tabbar
+    func setTabbarAppearence() {
+        UITabBar.appearance().isTranslucent = false
+        UITabBar.appearance().backgroundImage = UIImage();
+        UITabBar.appearance().backgroundColor = UIColor.white
+        UITabBar.appearance().shadowImage = UIImage(named: "tab_top_line")
+    }
+
+    //设置引导页
+    func setGuidePageView() {
+        
+    }
+    
+}

+ 31 - 0
RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate.swift

@@ -0,0 +1,31 @@
+//
+//  AppDelegate.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+    var window: UIWindow?
+
+
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+        //初始化高德地图
+//        AMapManager.shared().initAMap()
+        //初始化百度地图
+        BaiduMapManager.shared().initBaiduMap()
+        //初始化窗口
+        initWindow()
+        //初始化友盟
+        UMManager.shared().initUM(launchOptions: launchOptions)
+        //初始化键盘
+        IQKeyboardManagerSwiftManager.shared().initIQKeyboardManagerSwift()
+        return true
+    }
+
+}

+ 26 - 0
RainbowPlanet/RainbowPlanet/Base/BaseNavigationController/BaseNavigationViewController.swift

@@ -0,0 +1,26 @@
+//
+//  BaseNavigationViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class BaseNavigationViewController: UINavigationController {
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        // Do any additional setup after loading the view.
+    }
+    
+    override func pushViewController(_ viewController: UIViewController, animated: Bool) {
+        if (self.children.count > 0) {
+            viewController.hidesBottomBarWhenPushed = true
+        }
+        super.pushViewController(viewController, animated: animated)
+    }
+
+}

+ 51 - 0
RainbowPlanet/RainbowPlanet/Base/BaseTabbarViewController/BaseTabbarViewController.swift

@@ -0,0 +1,51 @@
+//
+//  BaseTabbarViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class BaseTabbarViewController: UITabBarController {
+    private static let _sharedInstance = BaseTabbarViewController()
+
+    class func shared() -> BaseTabbarViewController {
+        return _sharedInstance
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        // Do any additional setup after loading the view.
+    }
+
+    func tabBarViewController() -> BaseTabbarViewController {
+        let tabBarViewController = BaseTabbarViewController()
+
+        let v1 = ShoppingMallViewController()
+        let v2 = ShoppingCartViewController()
+        let v3 = MineViewController()
+
+        let n1 = BaseNavigationViewController.init(rootViewController: v1)
+        let n2 = BaseNavigationViewController.init(rootViewController: v2)
+        let n3 = BaseNavigationViewController.init(rootViewController: v3)
+
+        tabBarItemStyle(navc: n1, normalImg: "tab_home_icon_normal", selectorImg: "tab_home_icon_selected", title: "首页")
+        tabBarItemStyle(navc: n2, normalImg: "tab_shopping_icon_normal", selectorImg: "tab_shopping_icon_selected", title: "逛街")
+        tabBarItemStyle(navc: n3, normalImg: "tab_me_icon_normal", selectorImg: "tab_me_icon_selected", title: "我的")
+
+        tabBarViewController.viewControllers = [n1, n2, n3]
+        return tabBarViewController
+    }
+
+
+    private func tabBarItemStyle(navc : UINavigationController, normalImg : String, selectorImg : String, title : String){
+        navc.tabBarItem = UITabBarItem.init(title: title, image: UIImage(named:normalImg), selectedImage: UIImage(named:selectorImg))
+        navc.tabBarItem.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.gray], for: UIControl.State.normal)
+        navc.tabBarItem.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.blue], for: UIControl.State.selected)
+
+    }
+
+}

+ 33 - 0
RainbowPlanet/RainbowPlanet/Base/BaseView/BaseView.swift

@@ -0,0 +1,33 @@
+//
+//  BaseView.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+
+class BaseView: UIView {
+
+    let disposeBag = DisposeBag()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        self.setupViews()
+        self.setupLayouts()
+    }
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    func setupViews() {
+        backgroundColor = UIColor.white
+    }
+
+    func setupLayouts() {
+
+    }
+
+}

+ 64 - 0
RainbowPlanet/RainbowPlanet/Base/BaseViewController/BaseViewController.swift

@@ -0,0 +1,64 @@
+//
+//  BaseViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+
+class BaseViewController: UIViewController {
+
+    let disposeBag = DisposeBag()
+
+    lazy var navigationBar = WRCustomNavigationBar.CustomNavigationBar()
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        navigationController?.navigationBar.isHidden = true
+        automaticallyAdjustsScrollViewInsets = false
+        view.backgroundColor = UIColor.white
+        if #available(iOS 11.0, *) {
+            UIScrollView.appearance().contentInsetAdjustmentBehavior =  .automatic
+        } else {
+            if self.responds(to: #selector(setter: self.automaticallyAdjustsScrollViewInsets)) {
+                self.automaticallyAdjustsScrollViewInsets = true
+            }
+        }
+        setupNavigationBar()
+    }
+
+    fileprivate func setupNavigationBar()
+    {
+        navigationBar.wr_setBottomLineHidden(hidden: true)
+        navigationBar.barBackgroundColor = UIColor.white
+        navigationBar.titleLabelColor = UIColor.blue
+        view.addSubview(navigationBar)
+
+        if self.navigationController != nil {
+            if self.navigationController?.viewControllers.count == 1 {
+                if self.navigationController?.presentingViewController != nil {
+                    setLeftButton(image: UIImage(named: "navigaitionbar_back_black")! )
+                }
+            } else {
+                setLeftButton(image: UIImage(named: "navigaitionbar_back_black")!)
+            }
+        } else {
+            setLeftButton(image: UIImage(named: "navigaitionbar_back_black")!)
+        }
+    }
+
+    private func setLeftButton(image:UIImage) {
+        navigationBar.wr_setLeftButton(image: image)
+        navigationBar.onClickLeftButton = { [weak self] in
+            self?.wr_toLastViewController(animated: true)
+        }
+    }
+
+    func setupViews() {}
+
+    func setupLayouts() {}
+
+}

+ 30 - 0
RainbowPlanet/RainbowPlanet/Base/BaseWebViewController/BaseWebViewController.swift

@@ -0,0 +1,30 @@
+//
+//  BaseWebViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class BaseWebViewController: BaseViewController {
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        // Do any additional setup after loading the view.
+    }
+    
+
+    /*
+    // MARK: - Navigation
+
+    // In a storyboard-based application, you will often want to do a little preparation before navigation
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        // Get the new view controller using segue.destination.
+        // Pass the selected object to the new view controller.
+    }
+    */
+
+}

+ 17 - 0
RainbowPlanet/RainbowPlanet/Define/CacheMacro.swift

@@ -0,0 +1,17 @@
+//
+//  CacheMacro.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/1/5.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import Foundation
+
+
+/// 百度定位
+let kLocationModelCache = "LocationModel"
+
+/// 百度定位
+let kAMapLocationModelCache = "AMapLocationModel"
+

+ 75 - 0
RainbowPlanet/RainbowPlanet/Define/ColorMacro.swift

@@ -0,0 +1,75 @@
+//
+//  ColorMacro.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/6/30.
+//  Copyright © 2018年 南鑫林. All rights reserved.
+//
+
+import UIKit
+//主题色 导航栏颜色 
+let kNavBgColor = UIColor(hexString: "2d96ee")
+
+let kTabbarSelectColor = UIColor(hexString: "2d96ee")
+
+let kTabbarNormalColor = UIColor(hexString: "b1d3f1")
+
+let kDisabledButtonColor = UIColor(hexString: "#E6E6E6")
+
+let kDisabledTitleColor = UIColor(hexString: "#666666")
+
+let kEnabledButtonColor = UIColor(hexString: "#32B24F")
+
+let kEnabledTitleColor = UIColor(hexString: "#FFFFFF")
+
+let k333333Color = UIColor(hexString: "333333")
+
+let k666666Color = UIColor(hexString: "666666")
+
+let k999999Color = UIColor(hexString: "999999")
+
+let keeeeeeColor = UIColor(hexString: "eeeeee")
+
+let kED3934Color = UIColor(hexString: "ED3934")
+
+let ke6e6e6Color = UIColor(hexString: "e6e6e6")
+
+let kcececeColor = UIColor(hexString: "cecece")
+
+let k457ffdColor = UIColor(hexString: "457ffd")
+
+let kd8d8d8Color = UIColor(hexString: "d8d8d8")
+
+let kd9d9d9Color = UIColor(hexString: "d9d9d9")
+
+let kffffffColor = UIColor(hexString: "ffffff")
+
+let kff630fColor = UIColor(hexString: "ff630f")
+
+let kff8400Color = UIColor(hexString: "ff8400")
+
+let kff481bColor = UIColor(hexString: "ff481b")
+
+let kffeae5Color = UIColor(hexString: "ffeae5")
+
+let kf82323Color = UIColor(hexString: "f82323")
+
+let kf1f1f1Color = UIColor(hexString: "f1f1f1")
+
+let kf7f7f9Color = UIColor(hexString: "f7f7f9")
+
+let kf2f2f2Color = UIColor(hexString: "f2f2f2")
+
+let kf3f3f3Color = UIColor(hexString: "f3f3f3")
+
+let kf6f6f6Color = UIColor(hexString: "f6f6f6")
+
+let kf9f9f9Color = UIColor(hexString: "f9f9f9")
+
+let kfd6031Color = UIColor(hexString: "fd6031")
+
+let kffa500Color = UIColor(hexString: "ffa500")
+
+let kff724fColor = UIColor(hexString: "ff724f")
+
+let kbfbfbfColor = UIColor(hexString: "bfbfbf")

+ 153 - 0
RainbowPlanet/RainbowPlanet/Define/Common.swift

@@ -0,0 +1,153 @@
+//
+//  Common.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/7/1.
+//  Copyright © 2018年 南鑫林. All rights reserved.
+//
+
+import UIKit
+import DeviceKit
+import SnapKit
+import SwiftyJSON
+import ObjectMapper
+import RxCocoa
+import RxSwift
+import Kingfisher
+
+
+let kAppDelegate : AppDelegate = (UIApplication.shared.delegate as! AppDelegate)
+
+//MARK: - 屏幕的高度
+///屏幕宽度
+public let kScreenWidth = UIScreen.main.bounds.size.width
+///屏幕高度
+public let kScreenHeight = UIScreen.main.bounds.size.height
+/// 屏幕宽比例
+public let kScaleWidth = kScreenWidth/375.0
+/// 屏幕高比例
+public let kScaleHeight = kScreenHeight/667.0
+/// 比例值
+public func kScaleValue(value:CGFloat) -> CGFloat {
+    return kScreenWidth / 375.0 * value
+}
+///状态栏高度
+public let kSafeStatusBarHeight = UIApplication.shared.statusBarFrame.size.height
+///navigation高度
+public let kNavBarHeight : CGFloat = 44.0
+///kNavBar高度
+public let kNavBarTotalHeight = navBarTotalHeight()
+///tabbar安全高度
+public let kSafeTabBarHeight = safeTabBarHeight()
+///tabbar高度
+public let kTabBarTotalHeight  =  tabBarTotalHeight()
+///视图的内容高度包含tabbar
+public let kContentTabbarHeight = kScreenHeight - kNavBarTotalHeight
+///视图的内容安全高度包含tabbar
+public let kContentSafeTabbarHeight = kScreenHeight - kNavBarTotalHeight - kSafeTabBarHeight
+///视图的内容高度不包含tabbar/navigationbar
+public let kContentHeight = kScreenHeight - kNavBarTotalHeight - kTabBarTotalHeight
+
+/// 是否为x系列
+let kIsIphoneX = isIphoneX()
+///navBar的高度
+func navBarTotalHeight () -> CGFloat {
+    return isIphoneX() ? 88.0 : 64.0
+}
+///tabBar高度
+func tabBarTotalHeight() -> CGFloat {
+    return isIphoneX() ? 83.0 : 49.0
+}
+///tabbar安全高度
+func safeTabBarHeight() -> CGFloat {
+    return isIphoneX() ? 34.0 : 0.0
+}
+///是不是.iPhoneX,.iPhoneXr,.iPhoneXs,.iPhoneXsMax
+private func isIphoneX() -> Bool {
+    
+    let groupOfAllowedDevices: [Device] = [.iPhoneX,.iPhoneXr,.iPhoneXs,.iPhoneXsMax,.simulator(.iPhoneX),.simulator(.iPhoneXr),.simulator(.iPhoneXs),.simulator(.iPhoneXsMax)]
+    let device = Device()
+    if device.isOneOf(groupOfAllowedDevices) {
+        return true
+    }else {
+        return false
+    }
+}
+
+//MARK: - 返回本地图片
+/// 返回本地图片
+///
+/// - Parameter name: 图片名字
+/// - Returns: 图片
+func kImage(name :String) -> UIImage? {
+    return UIImage(named: name)
+}
+
+//MARK: - 返回url图片
+/// 返回url图片
+///
+/// - Parameter name: 图片url
+/// - Returns: 图片
+func kURLImage(name :String) -> URL? {
+    return URL(string: name)
+}
+
+//MARK: - 返回一个颜色
+/// 返回一个颜色
+///
+/// - Parameters:
+///   - r: 红色
+///   - g: 黄
+///   - b: 蓝色
+/// - Returns: 颜色
+func kRGBColor(r:Float , g:Float , b:Float) -> UIColor {
+    return UIColor(red: (CGFloat(r/255.0)), green: (CGFloat(g/255.0)), blue: (CGFloat(b/255.0)), alpha: 1.0)
+}
+
+//MARK: - 返回一个颜色
+/// 返回一个颜色
+///
+/// - Parameters:
+///   - r: 红色
+///   - g: 黄
+///   - b: 蓝色
+///   - a: 透明度
+/// - Returns: 颜色
+func kRGBAColor(r:Float , g:Float , b:Float, a:Float) -> UIColor {
+    return UIColor(red: (CGFloat(r/255.0)), green: (CGFloat(g/255.0)), blue: (CGFloat(b/255.0)), alpha: CGFloat(a))
+}
+
+
+
+/// 代码延迟运行
+///
+/// - Parameters:
+///   - delayTime: 延时时间。比如:.seconds(5)、.milliseconds(500)
+///   - qosClass: 要使用的全局QOS类(默认为 nil,表示主线程)
+///   - closure: 延迟运行的代码
+func delay(by delayTime: TimeInterval, qosClass: DispatchQoS.QoSClass? = nil,
+           _ closure: @escaping () -> Void) {
+    let dispatchQueue = qosClass != nil ? DispatchQueue.global(qos: qosClass!) : .main
+    dispatchQueue.asyncAfter(deadline: DispatchTime.now() + delayTime, execute: closure)
+}
+
+func getCurrentVC() -> UIViewController {
+    let keywindow = (UIApplication.shared.delegate as! AppDelegate).window//UIApplication.shared.keyWindow使用此有时会崩溃
+    let firstView: UIView = (keywindow?.subviews.first)!
+    let secondView: UIView = firstView.subviews.first!
+    var vc = viewForController(view: secondView)!
+    vc = ((vc as! UITabBarController).selectedViewController! as! UINavigationController).visibleViewController!
+
+    return vc
+}
+
+private func viewForController(view:UIView)->UIViewController?{
+    var next:UIView? = view
+    repeat{
+        if let nextResponder = next?.next, nextResponder is UIViewController {
+            return (nextResponder as! UIViewController)
+        }
+        next = next?.superview
+    }while next != nil
+    return nil
+}

+ 9 - 0
RainbowPlanet/RainbowPlanet/Define/EnumMacro.swift

@@ -0,0 +1,9 @@
+//
+//  EnumMacro.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/11/17.
+//  Copyright © 2018 南鑫林. All rights reserved.
+//
+
+import Foundation

+ 81 - 0
RainbowPlanet/RainbowPlanet/Define/FontMacro.swift

@@ -0,0 +1,81 @@
+//
+//  FontMacro.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/12/11.
+//  Copyright © 2018 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+let kBoldFont10 = UIFont.boldSystemFont(ofSize: 10)
+let kBoldFont11 = UIFont.boldSystemFont(ofSize: 11)
+let kBoldFont12 = UIFont.boldSystemFont(ofSize: 12)
+let kBoldFont13 = UIFont.boldSystemFont(ofSize: 13)
+let kBoldFont14 = UIFont.boldSystemFont(ofSize: 14)
+let kBoldFont15 = UIFont.boldSystemFont(ofSize: 15)
+let kBoldFont16 = UIFont.boldSystemFont(ofSize: 16)
+let kBoldFont17 = UIFont.boldSystemFont(ofSize: 17)
+let kBoldFont18 = UIFont.boldSystemFont(ofSize: 18)
+let kBoldFont19 = UIFont.boldSystemFont(ofSize: 19)
+let kBoldFont20 = UIFont.boldSystemFont(ofSize: 20)
+let kBoldFont21 = UIFont.boldSystemFont(ofSize: 21)
+let kBoldFont22 = UIFont.boldSystemFont(ofSize: 22)
+let kBoldFont30 = UIFont.boldSystemFont(ofSize: 30)
+let kBoldFont36 = UIFont.boldSystemFont(ofSize: 36)
+let kBoldFont40 = UIFont.boldSystemFont(ofSize: 40)
+
+let kMediumFont10 = UIFont(name: "PingFang-SC-Medium", size: 10)
+let kMediumFont11 = UIFont(name: "PingFang-SC-Medium", size: 11)
+let kMediumFont12 = UIFont(name: "PingFang-SC-Medium", size: 12)
+let kMediumFont13 = UIFont(name: "PingFang-SC-Medium", size: 13)
+let kMediumFont14 = UIFont(name: "PingFang-SC-Medium", size: 14)
+let kMediumFont15 = UIFont(name: "PingFang-SC-Medium", size: 15)
+let kMediumFont16 = UIFont(name: "PingFang-SC-Medium", size: 16)
+let kMediumFont17 = UIFont(name: "PingFang-SC-Medium", size: 17)
+let kMediumFont18 = UIFont(name: "PingFang-SC-Medium", size: 18)
+let kMediumFont24 = UIFont(name: "PingFang-SC-Medium", size: 24)
+let kMediumFont25 = UIFont(name: "PingFang-SC-Medium", size: 25)
+let kMediumFont27 = UIFont(name: "PingFang-SC-Medium", size: 27)
+let kMediumFont30 = UIFont(name: "PingFang-SC-Medium", size: 30)
+let kMediumFont35 = UIFont(name: "PingFang-SC-Medium", size: 35)
+
+let kRegularFont12 = UIFont(name: "PingFang-SC-Regular", size: 12)
+let kRegularFont13 = UIFont(name: "PingFang-SC-Regular", size: 13)
+let kRegularFont14 = UIFont(name: "PingFang-SC-Regular", size: 14)
+let kRegularFont15 = UIFont(name: "PingFang-SC-Regular", size: 15)
+let kRegularFont16 = UIFont(name: "PingFang-SC-Regular", size: 16)
+let kRegularFont17 = UIFont(name: "PingFang-SC-Regular", size: 17)
+let kRegularFont18 = UIFont(name: "PingFang-SC-Regular", size: 18)
+
+let kDINMEDIUMFont10 = UIFont(name: "DIN-MEDIUM", size: 10)
+let kDINMEDIUMFont11 = UIFont(name: "DIN-MEDIUM", size: 11)
+let kDINMEDIUMFont12 = UIFont(name: "DIN-MEDIUM", size: 12)
+let kDINMEDIUMFont13 = UIFont(name: "DIN-MEDIUM", size: 13)
+let kDINMEDIUMFont14 = UIFont(name: "DIN-MEDIUM", size: 14)
+let kDINMEDIUMFont15 = UIFont(name: "DIN-MEDIUM", size: 15)
+let kDINMEDIUMFont16 = UIFont(name: "DIN-MEDIUM", size: 16)
+let kDINMEDIUMFont17 = UIFont(name: "DIN-MEDIUM", size: 17)
+let kDINMEDIUMFont18 = UIFont(name: "DIN-MEDIUM", size: 18)
+let kDINMEDIUMFont19 = UIFont(name: "DIN-MEDIUM", size: 19)
+let kDINMEDIUMFont20 = UIFont(name: "DIN-MEDIUM", size: 20)
+let kDINMEDIUMFont21 = UIFont(name: "DIN-MEDIUM", size: 21)
+let kDINMEDIUMFont22 = UIFont(name: "DIN-MEDIUM", size: 22)
+let kDINMEDIUMFont23 = UIFont(name: "DIN-MEDIUM", size: 23)
+let kDINMEDIUMFont24 = UIFont(name: "DIN-MEDIUM", size: 24)
+let kDINMEDIUMFont25 = UIFont(name: "DIN-MEDIUM", size: 25)
+let kDINMEDIUMFont26 = UIFont(name: "DIN-MEDIUM", size: 26)
+let kDINMEDIUMFont27 = UIFont(name: "DIN-MEDIUM", size: 27)
+let kDINMEDIUMFont28 = UIFont(name: "DIN-MEDIUM", size: 28)
+let kDINMEDIUMFont29 = UIFont(name: "DIN-MEDIUM", size: 29)
+let kDINMEDIUMFont30 = UIFont(name: "DIN-MEDIUM", size: 30)
+let kDINMEDIUMFont31 = UIFont(name: "DIN-MEDIUM", size: 31)
+let kDINMEDIUMFont32 = UIFont(name: "DIN-MEDIUM", size: 32)
+let kDINMEDIUMFont33 = UIFont(name: "DIN-MEDIUM", size: 33)
+let kDINMEDIUMFont34 = UIFont(name: "DIN-MEDIUM", size: 34)
+let kDINMEDIUMFont35 = UIFont(name: "DIN-MEDIUM", size: 35)
+let kDINMEDIUMFont36 = UIFont(name: "DIN-MEDIUM", size: 36)
+let kDINMEDIUMFont37 = UIFont(name: "DIN-MEDIUM", size: 37)
+let kDINMEDIUMFont38 = UIFont(name: "DIN-MEDIUM", size: 38)
+let kDINMEDIUMFont39 = UIFont(name: "DIN-MEDIUM", size: 39)
+let kDINMEDIUMFont40 = UIFont(name: "DIN-MEDIUM", size: 40)

+ 14 - 0
RainbowPlanet/RainbowPlanet/Define/HTMLURLMacro.swift

@@ -0,0 +1,14 @@
+//
+//  HTMLURLMacro.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/10/17.
+//  Copyright © 2018 南鑫林. All rights reserved.
+//
+
+import Foundation
+
+/// 给我们我们评分
+let kAppStoreReview = "https://itunes.apple.com/cn/app/1455804911?action=write-review"
+
+

+ 13 - 0
RainbowPlanet/RainbowPlanet/Define/NotificationCenterMacro.swift

@@ -0,0 +1,13 @@
+//
+//  NotificationCenterMacro.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/1/4.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import Foundation
+
+
+/// 定位
+let kLocationModelChangeNotificationName = Notification.Name(rawValue: "LocationModelChange")

+ 42 - 0
RainbowPlanet/RainbowPlanet/Define/RainbowPlanet-Bridging-Header.h

@@ -0,0 +1,42 @@
+//
+//  RainbowPlanet-Bridging-Header.h
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+#ifndef RainbowPlanet_Bridging_Header_h
+#define RainbowPlanet_Bridging_Header_h
+
+//提示框
+#import <MBProgressHUD/MBProgressHUD.h>
+//支付宝支付
+#import <AlipaySDK/AlipaySDK.h>
+
+#import <JXCategoryView/JXCategoryView.h>
+
+//微信支付
+#import "WXApi.h"
+
+
+//空白页面占位图
+#import <LYEmptyView/LYEmptyViewHeader.h>
+
+//友盟
+#import <UMCommon/UMCommon.h>
+#import <UMPush/UMessage.h>
+#import <UMShare/UMShare.h>
+#import <UMAnalytics/MobClick.h>
+#import <UMCommonLog/UMCommonLogHeaders.h>
+#import <UShareUI/UShareUI.h>
+
+//百度定位
+#import <BMKLocationkit/BMKLocationComponent.h>
+
+//高德定位
+#import <AMapFoundationKit/AMapFoundationKit.h>
+#import <AMapLocationKit/AMapLocationKit.h>
+
+
+#endif /* RainbowPlanet_Bridging_Header_h */

+ 40 - 0
RainbowPlanet/RainbowPlanet/Define/ThirdPartyMacro.swift

@@ -0,0 +1,40 @@
+//
+//  ThirdPartyMacro.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/7/13.
+//  Copyright © 2018年 南鑫林. All rights reserved.
+//
+
+import Foundation
+
+
+//MARK: - UMeng
+let kUMengAppKey  = "5c984a7f0cafb2332300000f"
+let kUMengAppSecret  = "lpx7kstlnlrxmimo5gfyzvtscrtguhw8"
+
+//MARK: - QQ跟安卓用同一个
+let kQQAppKey =  "101565722"
+let kQQAppSecret = "dfe6f96762ed0dbc3ad52dc06d0eda9b"
+
+//MARK: - 微信
+let kWeiXinAppKey  = "wx163e76382d53654b"
+let kWeiXinAppSecret = "1a915228304ea2e45eda9d2af5a64b84"
+
+//MARK: - 微博
+let kWeiboAppKey  = "4123861024"
+let kWeiboAppSecret  = "79d36bfe6b75638ece14d5d852e785c4"
+
+//MARK: - 百度地图
+let kBaiduMapAppKey  = "v7wFjrAQdlaBVC50CjwuRESC3Lu0xkhj"
+
+//MARK: - 高德地图
+let kAMapAppKey  = "daae215db1937220769796457b8d0327"
+
+
+//MARK: - aliPay
+
+let kAliPayManagerAppKey  = "2019032763726287"
+
+
+

BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/alipay_msp_back@2x.png


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/alipay_msp_refresh@2x.png


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/bar@2x.png


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/bridge.js


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/refresh@2x.png


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/refresh_click@2x.png


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/shutdown@2x.png


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.bundle/shutdown_click@2x.png


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/AlipaySDK


BIN
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/AlipaySDK-inside-Info.plist


+ 33 - 0
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/Headers/APayAuthInfo.h

@@ -0,0 +1,33 @@
+//
+//  APAuthInfo.h
+//  APAuth
+//
+//  Created by antfin on 17-10-24.
+//  Copyright (c) 2017年 AntFin. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface APayAuthInfo : NSObject
+
+@property(nonatomic, copy)NSString *appID;
+@property(nonatomic, copy)NSString *pid;
+@property(nonatomic, copy)NSString *redirectUri;
+
+/**
+ *  初始化AuthInfo
+ *
+ *  @param appIDStr     应用ID
+ *  @param pidStr       商户ID   可不填
+ *  @param uriStr       授权的应用回调地址  比如:alidemo://auth
+ *
+ *  @return authinfo实例
+ */
+- (id)initWithAppID:(NSString *)appIDStr
+                pid:(NSString *)pidStr
+        redirectUri:(NSString *)uriStr;
+
+- (NSString *)description;
+- (NSString *)wapDescription;
+
+@end

+ 203 - 0
RainbowPlanet/RainbowPlanet/Lib/AlipaySDK/AlipaySDK.framework/Headers/AlipaySDK.h

@@ -0,0 +1,203 @@
+//
+//  AlipaySDK.h
+//  AlipaySDK
+//
+//  Created by antfin on 17-10-24.
+//  Copyright (c) 2017年 AntFin. All rights reserved.
+//
+
+
+////////////////////////////////////////////////////////
+///////////////// 支付宝标准版本支付SDK ///////////////////
+/////////// version:15.6.0  motify:2019.02.26///////////
+////////////////////////////////////////////////////////
+
+#import <UIKit/UIKit.h>
+#import "APayAuthInfo.h"
+
+typedef void(^CompletionBlock)(NSDictionary *resultDic);
+
+typedef enum {
+    ALIPAY_TIDFACTOR_IMEI,
+    ALIPAY_TIDFACTOR_IMSI,
+    ALIPAY_TIDFACTOR_TID,
+    ALIPAY_TIDFACTOR_CLIENTKEY,
+    ALIPAY_TIDFACTOR_VIMEI,
+    ALIPAY_TIDFACTOR_VIMSI,
+    ALIPAY_TIDFACTOR_CLIENTID,
+    ALIPAY_TIDFACTOR_APDID,
+    ALIPAY_TIDFACTOR_MAX
+} AlipayTidFactor;
+
+@interface AlipaySDK : NSObject
+
+/**
+ *  创建支付单例服务
+ *
+ *  @return 返回单例对象
+ */
++ (AlipaySDK *)defaultService;
+
+/**
+ *  用于设置SDK使用的window,如果没有自行创建window无需设置此接口
+ */
+@property (nonatomic, weak) UIWindow *targetWindow;
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////支付宝支付相关接口/////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  支付接口
+ *
+ *  @param orderStr        支付订单信息字串
+ *  @param schemeStr       调用支付的app注册在info.plist中的scheme
+ *  @param completionBlock 支付结果回调Block,用于wap支付结果回调
+                           跳转支付宝支付时只有当processOrderWithPaymentResult接口的completionBlock为nil时会使用这个bolock
+ */
+- (void)payOrder:(NSString *)orderStr
+      fromScheme:(NSString *)schemeStr
+        callback:(CompletionBlock)completionBlock;
+
+/**
+ *  支付接口 v2
+ *
+ *  @param orderStr        支付订单信息字串
+ *  @param dynamicLaunch   是否使用动态配置策略跳转支付宝支付
+ *  @param schemeStr       调用支付的app注册在info.plist中的scheme
+ *  @param completionBlock 支付结果回调Block,用于wap支付结果回调
+ 跳转支付宝支付时只有当processOrderWithPaymentResult接口的completionBlock为nil时会使用这个bolock
+ */
+- (void)payOrder:(NSString *)orderStr
+   dynamicLaunch:(BOOL)dynamicLaunch
+      fromScheme:(NSString *)schemeStr
+        callback:(CompletionBlock)completionBlock;
+
+/**
+ *  处理支付宝app支付后跳回商户app携带的支付结果Url
+ *
+ *  @param resultUrl        支付宝app返回的支付结果url
+ *  @param completionBlock  支付结果回调 为nil时默认使用支付接口的completionBlock
+ */
+- (void)processOrderWithPaymentResult:(NSURL *)resultUrl
+                      standbyCallback:(CompletionBlock)completionBlock;
+
+/**
+ *  获取交易token。
+ *
+ *  @return 交易token,若无则为空。
+ */
+- (NSString *)fetchTradeToken;
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////支付宝授权 2.0 相关接口////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  快登授权2.0
+ *
+ *  @param infoStr          授权请求信息字串
+ *  @param schemeStr        调用授权的app注册在info.plist中的scheme
+ *  @param completionBlock  授权结果回调,若在授权过程中,调用方应用被系统终止,则此block无效,
+                            需要调用方在appDelegate中调用processAuth_V2Result:standbyCallback:方法获取授权结果
+ */
+- (void)auth_V2WithInfo:(NSString *)infoStr
+             fromScheme:(NSString *)schemeStr
+               callback:(CompletionBlock)completionBlock;
+
+/**
+ *  处理支付宝app授权后跳回商户app携带的授权结果Url
+ *
+ *  @param resultUrl        支付宝app返回的授权结果url
+ *  @param completionBlock  授权结果回调
+ */
+- (void)processAuth_V2Result:(NSURL *)resultUrl
+             standbyCallback:(CompletionBlock)completionBlock;
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////支付宝授权 1.0 相关接口////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ *  快登授权
+ *  @param authInfo         授权相关信息
+ *  @param completionBlock  授权结果回调,若在授权过程中,调用方应用被系统终止,则此block无效,
+                            需要调用方在appDelegate中调用processAuth_V2Result:standbyCallback:方法获取授权结果
+ */
+- (void)authWithInfo:(APayAuthInfo *)authInfo
+            callback:(CompletionBlock)completionBlock;
+
+/**
+ *  处理支付宝app授权后跳回商户app携带的授权结果Url
+ *
+ *  @param resultUrl        支付宝app返回的授权结果url
+ *  @param completionBlock  授权结果回调
+ */
+- (void)processAuthResult:(NSURL *)resultUrl
+          standbyCallback:(CompletionBlock)completionBlock;
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////支付宝 h5 支付转 native 支付接口////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ *  从h5链接中获取订单串并支付接口(自版本15.4.0起,推荐使用该接口)
+ *
+ *  @param urlStr     拦截的 url string
+ *
+ *  @return YES为成功获取订单信息并发起支付流程;NO为无法获取订单信息,输入url是普通url
+ */
+- (BOOL)payInterceptorWithUrl:(NSString *)urlStr
+                   fromScheme:(NSString *)schemeStr
+                     callback:(CompletionBlock)completionBlock;
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////支付宝 tid 相关信息获取接口/////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  获取当前tid相关信息
+ *
+ *  @return tid相关信息
+ */
+- (NSString*)queryTidFactor:(AlipayTidFactor)factor;
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////支付宝支付环境相关信息接口//////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  是否已经使用过
+ *
+ *  @return YES为已经使用过,NO反之
+ */
+- (BOOL)isLogined;
+
+/**
+ *  获取当前版本号
+ *
+ *  @return 当前版本字符串
+ */
+- (NSString *)currentVersion;
+
+/**
+ *  測試所用,realse包无效
+ *
+ *  @param url  测试环境
+ */
+- (void)setUrl:(NSString *)url;
+
+/**
+ *  支付前主动更新本地配置
+ *
+ *  @param block 更新请求结果回调
+ */
+- (void)fetchSdkConfigWithBlock:(void(^)(BOOL success))block;
+@end

+ 98 - 0
RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/README.txt

@@ -0,0 +1,98 @@
+重要!
+SDK1.8.4
+1. 调整分享图片大小限制
+2. 新增openBusinessView接口
+
+SDK1.8.3
+1. SDK增加调起微信刷卡支付接口
+2. SDK增加小程序订阅消息接口
+3. 修复小程序订阅消息接口没有resp的问题
+
+SDK1.8.2
+1. SDK增加开发票授权 WXInvoiceAuthInsert
+2. SDK增加非税接口   WXNontaxPay
+3. SDK增加医保接口   WXPayInsurance
+4. 更换MTA库
+
+SDK1.8.1
+1. SDK打开小程序支持指定版本(体验,开发,正式版)
+2. SDK分享小程序支持指定版本(体验,开发,正式版)
+3. SDK支持输出log日志
+
+SDK1.8.0
+1. SDK支持打开小程序
+2. SDK分享小程序支持shareTicket
+
+SDK1.7.9
+1. SDK订阅一次性消息
+
+SDK1.7.8
+1 SDK分享小程序支持大图
+
+SDK1.7.7
+1 增加SDK分享小程序
+2 增加选择发票接口
+
+SDK1.7.6
+1. 提高稳定性
+1 修复mta崩溃
+2  新增接口支持开发者关闭mta数据统计上报
+
+SDK1.7.5
+1. 提高稳定性
+2. 加快registerApp接口启动速度
+
+SDK1.7.4
+1. 更新支持iOS启用 ATS(App Transport Security)
+2. 需要在工程中链接CFNetwork.framework
+3. 在工程配置中的”Other Linker Flags”中加入”-Objc -all_load”
+
+SDK1.7.3
+1. 增强稳定性,适配iOS10
+2. 修复小于32K的jpg格式缩略图设置失败的问题
+
+SDK1.7.2
+1. 修复因CTTeleponyNetworkInfo引起的崩溃问题
+
+SDK1.7.1
+1. 支持兼容ipv6(提升稳定性)
+2. xCode Version 7.3.1 (7D1014) 编译
+
+SDK1.7
+1. 支持兼容ipv6
+2. 修复若干问题增强稳定性
+
+SDK1.6.3
+1. xCode7.2 构建的sdk包。
+2. 请使用xCode7.2进行编译。
+3. 需要在Build Phases中Link  Security.framework
+4. 修复若干小问题。
+
+SDK1.6.2
+1、xCode7.1 构建的sdk包
+2、请使用xCode7.1进行编译
+
+SDK1.6.1
+1、修复armv7s下,bitcode可能编译不过
+2、解决warning
+
+SDK1.6
+1、iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。
+受此影响,当你的应用在iOS 9中需要使用微信SDK的相关能力(分享、收藏、支付、登录等)时,需要在“Info.plist”里增加如下代码:
+<key>LSApplicationQueriesSchemes</key>
+<array>
+<string>weixin</string>
+</array>
+<key>NSAppTransportSecurity</key>
+<dict>
+<key>NSAllowsArbitraryLoads</key>
+<true/>
+</dict>
+2、开发者需要在工程中链接上 CoreTelephony.framework
+3、解决bitcode编译不过问题
+
+SDK1.5
+1、废弃safeSendReq:接口,使用sendReq:即可。
+2、新增+(BOOL) sendAuthReq:(SendAuthReq*) req viewController : (UIViewController*) viewController delegate:(id<WXApiDelegate>) delegate;
+支持未安装微信情况下Auth,具体见WXApi.h接口描述
+3、微信开放平台新增了微信模块用户统计功能,便于开发者统计微信功能模块的用户使用和活跃情况。开发者需要在工程中链接上:SystemConfiguration.framework,libz.dylib,libsqlite3.0.dylib。

+ 196 - 0
RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/WXApi.h

@@ -0,0 +1,196 @@
+//
+//  WXApi.h
+//  所有Api接口
+//
+//  Created by Wechat on 12-2-28.
+//  Copyright (c) 2012年 Tencent. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "WXApiObject.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+#pragma mark - WXApiDelegate
+/*! @brief 接收并处理来自微信终端程序的事件消息
+ *
+ * 接收并处理来自微信终端程序的事件消息,期间微信界面会切换到第三方应用程序。
+ * WXApiDelegate 会在handleOpenURL:delegate:中使用并触发。
+ */
+@protocol WXApiDelegate <NSObject>
+@optional
+
+/*! @brief 收到一个来自微信的请求,第三方应用程序处理完后调用sendResp向微信发送结果
+ *
+ * 收到一个来自微信的请求,异步处理完成后必须调用sendResp发送处理结果给微信。
+ * 可能收到的请求有GetMessageFromWXReq、ShowMessageFromWXReq等。
+ * @param req 具体请求内容,是自动释放的
+ */
+- (void)onReq:(BaseReq*)req;
+
+
+
+/*! @brief 发送一个sendReq后,收到微信的回应
+ *
+ * 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
+ * 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
+ * @param resp具体的回应内容,是自动释放的
+ */
+- (void)onResp:(BaseResp*)resp;
+
+@end
+
+#pragma mark - WXApiLogDelegate
+
+@protocol WXApiLogDelegate <NSObject>
+
+- (void)onLog:(NSString*)log logLevel:(WXLogLevel)level;
+
+@end
+
+#pragma mark - WXApi
+
+/*! @brief 微信Api接口函数类
+ *
+ * 该类封装了微信终端SDK的所有接口
+ */
+@interface WXApi : NSObject
+
+/*! @brief WXApi的成员函数,向微信终端程序注册第三方应用。
+ *
+ * 需要在每次启动第三方应用程序时调用。第一次调用后,会在微信的可用应用列表中出现,默认开启MTA数据上报。
+ * iOS7及以上系统需要调起一次微信才会出现在微信的可用应用列表中。
+ * @attention 请保证在主线程中调用此函数
+ * @param appid 微信开发者ID
+ * @param typeFlag 应用支持打开的文件类型
+ * @return 成功返回YES,失败返回NO。
+ */
++ (BOOL)registerApp:(NSString *)appid;
+
+/*! @brief WXApi的成员函数,向微信终端程序注册第三方应用。
+ *
+ * 需要在每次启动第三方应用程序时调用。第一次调用后,会在微信的可用应用列表中出现。
+ * iOS7及以上系统需要调起一次微信才会出现在微信的可用应用列表中。
+ * @attention 请保证在主线程中调用此函数
+ * @param appid 微信开发者ID
+ * @param isEnableMTA 是否支持MTA数据上报
+ * @return 成功返回YES,失败返回NO。
+ */
++ (BOOL)registerApp:(NSString *)appid enableMTA:(BOOL)isEnableMTA;
+
+
+/*! @brief WXApi的成员函数,向微信终端程序注册应用支持打开的文件类型。
+ *
+ * 需要在每次启动第三方应用程序时调用。调用后并第一次成功分享数据到微信后,会在微信的可用应用列表中出现。
+ * @see registerApp
+ * @param typeFlag 应用支持打开的数据类型, enAppSupportContentFlag枚举类型 “|” 操作后结果
+ */
++ (void)registerAppSupportContentFlag:(UInt64)typeFlag;
+
+
+
+/*! @brief 处理微信通过URL启动App时传递的数据
+ *
+ * 需要在 application:openURL:sourceApplication:annotation:或者application:handleOpenURL中调用。
+ * @param url 微信启动第三方应用时传递过来的URL
+ * @param delegate  WXApiDelegate对象,用来接收微信触发的消息。
+ * @return 成功返回YES,失败返回NO。
+ */
++ (BOOL)handleOpenURL:(NSURL *)url delegate:(nullable id<WXApiDelegate>)delegate;
+
+
+
+/*! @brief 检查微信是否已被用户安装
+ *
+ * @return 微信已安装返回YES,未安装返回NO。
+ */
++ (BOOL)isWXAppInstalled;
+
+
+
+/*! @brief 判断当前微信的版本是否支持OpenApi
+ *
+ * @return 支持返回YES,不支持返回NO。
+ */
++ (BOOL)isWXAppSupportApi;
+
+
+
+/*! @brief 获取微信的itunes安装地址
+ *
+ * @return 微信的安装地址字符串。
+ */
++ (NSString *)getWXAppInstallUrl;
+
+
+
+/*! @brief 获取当前微信SDK的版本号
+ *
+ * @return 返回当前微信SDK的版本号
+ */
++ (NSString *)getApiVersion;
+
+
+
+/*! @brief 打开微信
+ *
+ * @return 成功返回YES,失败返回NO。
+ */
++ (BOOL)openWXApp;
+
+
+
+/*! @brief 发送请求到微信,等待微信返回onResp
+ *
+ * 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持以下类型
+ * SendAuthReq、SendMessageToWXReq、PayReq等。
+ * @param req 具体的发送请求,在调用函数后,请自己释放。
+ * @return 成功返回YES,失败返回NO。
+ */
++ (BOOL)sendReq:(BaseReq*)req;
+
+/*! @brief 发送Auth请求到微信,支持用户没安装微信,等待微信返回onResp
+ *
+ * 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持SendAuthReq类型。
+ * @param req 具体的发送请求,在调用函数后,请自己释放。
+ * @param viewController 当前界面对象。
+ * @param delegate  WXApiDelegate对象,用来接收微信触发的消息。
+ * @return 成功返回YES,失败返回NO。
+ */
++ (BOOL)sendAuthReq:(SendAuthReq*)req viewController:(UIViewController*)viewController delegate:(nullable id<WXApiDelegate>)delegate;
+
+
+/*! @brief 收到微信onReq的请求,发送对应的应答给微信,并切换到微信界面
+ *
+ * 函数调用后,会切换到微信的界面。第三方应用程序收到微信onReq的请求,异步处理该请求,完成后必须调用该函数。可能发送的相应有
+ * GetMessageFromWXResp、ShowMessageFromWXResp等。
+ * @param resp 具体的应答内容,调用函数后,请自己释放
+ * @return 成功返回YES,失败返回NO。
+ */
++ (BOOL)sendResp:(BaseResp*)resp;
+
+
+/*! @brief WXApi的成员函数,接受微信的log信息。byBlock
+    注意1:SDK会强引用这个block,注意不要导致内存泄漏,注意不要导致内存泄漏
+    注意2:调用过一次startLog by block之后,如果再调用一次任意方式的startLoad,会释放上一次logBlock,不再回调上一个logBlock
+ *
+ *  @param level 打印log的级别
+ *  @param logBlock 打印log的回调block
+ */
++ (void)startLogByLevel:(WXLogLevel)level logBlock:(WXLogBolock)logBlock;
+
+/*! @brief WXApi的成员函数,接受微信的log信息。byDelegate 
+    注意1:sdk会弱引用这个delegate,这里可加任意对象为代理,不需要与WXApiDelegate同一个对象
+    注意2:调用过一次startLog by delegate之后,再调用一次任意方式的startLoad,不会再回调上一个logDelegate对象
+ *  @param level 打印log的级别
+ *  @param logDelegate 打印log的回调代理,
+ */
++ (void)startLogByLevel:(WXLogLevel)level logDelegate:(id<WXApiLogDelegate>)logDelegate;
+
+/*! @brief 停止打印log,会清理block或者delegate为空,释放block
+ *  @param 
+ */
++ (void)stopLog;
+@end
+
+NS_ASSUME_NONNULL_END

Разлика између датотеке није приказан због своје велике величине
+ 1101 - 0
RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/WXApiObject.h


+ 68 - 0
RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/WechatAuthSDK.h

@@ -0,0 +1,68 @@
+//
+//  WechatAuthSDK.h
+//  WechatAuthSDK
+//
+//  Created by 李凯 on 13-11-29.
+//  Copyright (c) 2013年 Tencent. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+enum  AuthErrCode {
+    WechatAuth_Err_Ok = 0,  //Auth成功
+    WechatAuth_Err_NormalErr = -1,  //普通错误
+    WechatAuth_Err_NetworkErr = -2, //网络错误
+    WechatAuth_Err_GetQrcodeFailed = -3,    //获取二维码失败
+    WechatAuth_Err_Cancel = -4,     //用户取消授权
+    WechatAuth_Err_Timeout = -5,    //超时
+};
+
+@protocol WechatAuthAPIDelegate<NSObject>
+@optional
+
+- (void)onAuthGotQrcode:(UIImage *)image;  //得到二维码
+- (void)onQrcodeScanned;    //二维码被扫描
+- (void)onAuthFinish:(int)errCode AuthCode:(nullable NSString *)authCode;    //成功登录
+
+@end
+
+@interface WechatAuthSDK : NSObject{
+    NSString *_sdkVersion;
+    __weak id<WechatAuthAPIDelegate> _delegate;
+}
+
+@property(nonatomic, weak, nullable) id<WechatAuthAPIDelegate> delegate;
+@property(nonatomic, readonly) NSString *sdkVersion;   //authSDK版本号
+
+/*! @brief 发送登录请求,等待WechatAuthAPIDelegate回调
+ *
+ * @param appId 微信开发者ID
+ * @param nonceStr 一个随机的尽量不重复的字符串,用来使得每次的signature不同
+ * @param timeStamp 时间戳
+ * @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔
+ * @param signature 签名
+ * @param schemeData 会在扫码后拼在scheme后
+ * @return 成功返回YES,失败返回NO
+    注:该实现只保证同时只有一个Auth在运行,Auth未完成或未Stop再次调用Auth接口时会返回NO。
+ */
+
+- (BOOL)Auth:(NSString *)appId
+    nonceStr:(NSString *)nonceStr
+   timeStamp:(NSString *)timeStamp
+       scope:(NSString *)scope
+   signature:(NSString *)signature
+  schemeData:(nullable NSString *)schemeData;
+
+
+/*! @brief 暂停登录请求
+ *
+ * @return 成功返回YES,失败返回NO。
+ */
+- (BOOL)StopAuth;
+
+@end
+
+NS_ASSUME_NONNULL_END

BIN
RainbowPlanet/RainbowPlanet/Lib/WeChatSDK/libWeChatSDK.a


+ 26 - 0
RainbowPlanet/RainbowPlanet/Manager/IQKeyboardManagerSwiftManager/IQKeyboardManagerSwiftManager.swift

@@ -0,0 +1,26 @@
+//
+//  IQKeyboardManagerSwiftManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/21.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import IQKeyboardManagerSwift
+
+public class IQKeyboardManagerSwiftManager: NSObject {
+    private static let _sharedInstance = IQKeyboardManagerSwiftManager()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> IQKeyboardManagerSwiftManager {
+        return _sharedInstance
+    }
+
+    func initIQKeyboardManagerSwift() {
+        IQKeyboardManager.shared.enable = true
+        IQKeyboardManager.shared.enableAutoToolbar = false
+        IQKeyboardManager.shared.shouldResignOnTouchOutside = true
+    }
+}

+ 121 - 0
RainbowPlanet/RainbowPlanet/Manager/MapManager/AMapManager/AMapLocationModel.swift

@@ -0,0 +1,121 @@
+//
+//  AMapLocationModel.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/28.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class AMapLocationModel: NSObject,NSCoding {
+
+    private static let _sharedInstance = AMapLocationModel()
+
+    override init() {} // 私有化init方法
+
+    class func shared() -> AMapLocationModel {
+        return _sharedInstance
+    }
+
+    /// 纬度
+    var latitude : String = "34.20207981"
+
+    /// 经度
+    var longitude : String = "108.95623806"
+
+    /// 国家
+    var country : String = "中国"
+
+    /// 省份
+    var province : String = "陕西省"
+
+    /// 市
+    var city : String = "西安市"
+
+    /// 区/县
+    var district : String = "雁塔区"
+
+    /// 街道
+    var street : String = "翠华南路"
+
+    /// 详细描述
+    var poiName : String = "华侨城天鹅堡4期"
+
+    /// AOIName
+    var aoiName : String = ""
+
+    /// 编号
+    var number : String = "62号"
+
+    /// 城市Code
+    var citycode : String = "029"
+
+    /// adcode
+    var adcode : String = "610113"
+
+    /// 地址格式化
+    var formattedAddress : String = "陕西省西安市雁塔区翠华南路靠近华侨城天鹅堡4期"
+
+    /// 归档
+    ///
+    /// - Parameter aCoder: 归档值
+    func encode(with aCoder: NSCoder) {
+        aCoder.encode(self.latitude, forKey:"latitude")
+        aCoder.encode(self.longitude, forKey:"longitude")
+        aCoder.encode(self.country, forKey:"country")
+        aCoder.encode(self.province, forKey:"province")
+        aCoder.encode(self.city, forKey:"city")
+        aCoder.encode(self.district, forKey:"district")
+        aCoder.encode(self.street, forKey:"street")
+        aCoder.encode(self.poiName, forKey:"poiName")
+        aCoder.encode(self.aoiName, forKey:"aoiName")
+        aCoder.encode(self.number, forKey:"number")
+        aCoder.encode(self.citycode, forKey:"citycode")
+        aCoder.encode(self.adcode, forKey:"adcode")
+        aCoder.encode(self.formattedAddress, forKey:"formattedAddress")
+    }
+    
+    /// 反归档
+    ///
+    /// - Parameter decoder: 反编码值
+    required init?(coder aDecoder: NSCoder) {
+        self.latitude = aDecoder.decodeObject(forKey: "latitude") as! String
+        self.longitude = aDecoder.decodeObject(forKey: "longitude") as! String
+        self.country = aDecoder.decodeObject(forKey: "country") as! String
+        self.province = aDecoder.decodeObject(forKey: "province") as! String
+        self.city = aDecoder.decodeObject(forKey: "city") as! String
+        self.district = aDecoder.decodeObject(forKey: "district") as! String
+        self.street = aDecoder.decodeObject(forKey: "street") as! String
+        self.poiName = aDecoder.decodeObject(forKey: "poiName") as! String
+        self.aoiName = aDecoder.decodeObject(forKey: "aoiName") as! String
+        self.number = aDecoder.decodeObject(forKey: "number") as! String
+        self.citycode = aDecoder.decodeObject(forKey: "citycode") as! String
+        self.adcode = aDecoder.decodeObject(forKey: "adcode") as! String
+        self.formattedAddress = aDecoder.decodeObject(forKey: "formattedAddress") as! String
+    }
+
+    /// 获取定位信息
+    ///
+    /// - Returns: 定位模型
+    public func getLocationModel() -> AMapLocationModel? {
+        //自定义对象读取
+        let modelData = UserDefaults.standard.data(forKey: "AMapLocationModel")
+        var locationModel = AMapLocationModel()
+        if modelData != nil {
+            locationModel = NSKeyedUnarchiver.unarchiveObject(with: modelData!) as! AMapLocationModel
+        }
+        return locationModel
+    }
+
+    /// 存储定位信息
+    ///
+    /// - Parameter locationModel: 定位模型
+    public func setLocationModel(locationModel:AMapLocationModel) -> Void {
+        //实例对象转换成Data
+        let modelData = NSKeyedArchiver.archivedData(withRootObject: locationModel)
+        //存储Data对象
+        UserDefaults.standard.set(modelData, forKey: "AMapLocationModel")
+    }
+
+}

+ 201 - 0
RainbowPlanet/RainbowPlanet/Manager/MapManager/AMapManager/AMapManager.swift

@@ -0,0 +1,201 @@
+//
+//  AMapManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/27.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class AMapManager: NSObject {
+    private static let _sharedInstance = AMapManager()
+
+    private override init() {} // 私有化init方法
+
+    typealias LocationModelBlock = (_ locationModel: AMapLocationModel) -> Void
+
+    class func shared() -> AMapManager {
+        return _sharedInstance
+    }
+
+    var locationModel = AMapLocationModel.shared().getLocationModel()
+
+    public func initAMap() -> Void {
+        AMapServices.shared().apiKey = kAMapAppKey
+        requestLocation(isSoughSingleLocation: true, isAccurateSingleLocation: false) { [weak self] (locationModel) in
+            self?.locationModel = locationModel
+        }
+    }
+
+    private lazy var locationManager: AMapLocationManager = {
+        // 注意: locationManager为该类的属性
+        let locationManager = AMapLocationManager()
+        locationManager.locatingWithReGeocode = true
+        return locationManager
+    }()
+
+    /// 粗单次定位
+    private func soughSingleLocation() {
+        //   带逆地理信息的一次定位(返回坐标和地址信息)
+        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
+        //   定位超时时间,最低2s,此处设置为2s
+        locationManager.locationTimeout = 2
+        //   逆地理请求超时时间,最低2s,此处设置为2s
+        locationManager.reGeocodeTimeout = 2
+    }
+
+    /// 精准单次定位
+    private func accurateSingleLocation() {
+        //   带逆地理信息的一次定位(返回坐标和地址信息)
+        locationManager.desiredAccuracy = kCLLocationAccuracyBest
+        //   定位超时时间,最低2s,此处设置为10s
+        locationManager.locationTimeout = 10
+        //   逆地理请求超时时间,最低2s,此处设置为10s
+        locationManager.reGeocodeTimeout = 10
+        locationManager.distanceFilter = 10
+    }
+
+    private func isSoughAccurateSingle(isSoughSingleLocation:Bool = false, isAccurateSingleLocation:Bool = false)  {
+
+        //粗单次定位
+        if isSoughSingleLocation {
+            soughSingleLocation()
+        }
+
+        //精准单次定位
+        if isAccurateSingleLocation {
+            soughSingleLocation()
+        }
+        
+    }
+
+    /// 请求单次定位
+    ///
+    /// - Parameters:
+    ///   - isSoughSingleLocation:
+    ///   - isAccurateSingleLocation: 粗单次定位 默认不调用
+    ///   - locationModelBlock: 精准单次定位 默认不调用
+    public func requestLocation(isSoughSingleLocation:Bool = false, isAccurateSingleLocation:Bool = false, locationModelBlock:@escaping LocationModelBlock) {
+
+
+        //粗单次定位
+        if isSoughSingleLocation {
+            soughSingleLocation()
+        }
+
+        //精准单次定位
+        if isAccurateSingleLocation {
+            soughSingleLocation()
+        }
+
+        locationManager.requestLocation(withReGeocode: true, completionBlock: {[weak self] (location: CLLocation?, reGeocode: AMapLocationReGeocode?, error: Error?) in
+
+            if let error = error {
+                let error = error as NSError
+
+                if error.code == AMapLocationErrorCode.locateFailed.rawValue {
+                    //定位错误:此时location和regeocode没有返回值,不进行annotation的添加
+                    NXLLog("定位错误:{\(error.code) - \(error.localizedDescription)};")
+                    return
+                } else if error.code == AMapLocationErrorCode.reGeocodeFailed.rawValue
+                    || error.code == AMapLocationErrorCode.timeOut.rawValue
+                    || error.code == AMapLocationErrorCode.cannotFindHost.rawValue
+                    || error.code == AMapLocationErrorCode.badURL.rawValue
+                    || error.code == AMapLocationErrorCode.notConnectedToInternet.rawValue
+                    || error.code == AMapLocationErrorCode.cannotConnectToHost.rawValue {
+                    //逆地理错误:在带逆地理的单次定位中,逆地理过程可能发生错误,此时location有返回值,regeocode无返回值,进行annotation的添加
+                    NXLLog("逆地理错误:{\(error.code) - \(error.localizedDescription)};")
+                } else {
+                    //没有错误:location有返回值,regeocode是否有返回值取决于是否进行逆地理操作,进行annotation的添加
+                }
+            }
+
+            self?.locationModel = self?.savelocationModel(location: location, reGeocode: reGeocode)
+            locationModelBlock(self?.locationModel ?? AMapLocationModel.shared().getLocationModel()!)
+        })
+    }
+
+    /// 后台定位
+    public func backgroundLocation()  {
+
+        locationManager.delegate = self
+        locationManager.distanceFilter = 100
+        //iOS 9(不包含iOS 9) 之前设置允许后台定位参数,保持不会被系统挂起
+        locationManager.pausesLocationUpdatesAutomatically = false
+
+        //iOS 9(包含iOS 9)之后新特性:将允许出现这种场景,同一app中多个locationmanager:一些只能在前台定位,另一些可在后台定位,并可随时禁止其后台定位。
+        if UIDevice.current.systemVersion._bridgeToObjectiveC().doubleValue >= 9.0 {
+            locationManager.pausesLocationUpdatesAutomatically = true
+        }
+
+        //开始持续定位
+        locationManager.startUpdatingLocation()
+    }
+
+    /// 持续定位
+    public func continuedLocation()  {
+
+        locationManager.delegate = self
+        locationManager.distanceFilter = 100
+        //iOS 9(包含iOS 9)之后新特性:将允许出现这种场景,同一app中多个locationmanager:一些只能在前台定位,另一些可在后台定位,并可随时禁止其后台定位。
+        if UIDevice.current.systemVersion._bridgeToObjectiveC().doubleValue >= 9.0 {
+            locationManager.pausesLocationUpdatesAutomatically = true
+        }
+
+        //开始持续定位
+        locationManager.startUpdatingLocation()
+    }
+
+    /// 停止定位
+    public func stopUpdatingLocation()  {
+        locationManager.stopUpdatingLocation()
+    }
+
+    public func savelocationModel(location: CLLocation!, reGeocode: AMapLocationReGeocode?) -> AMapLocationModel  {
+        if let location = location {
+            NXLLog("location:\(location)")
+            locationModel?.longitude = String(describing: location.coordinate.longitude)
+            locationModel?.latitude = String(describing: location.coordinate.latitude)
+        }
+
+        if let reGeocode = reGeocode {
+            NXLLog("reGeocode:\(reGeocode)")
+            /// 国家
+            locationModel?.country = reGeocode.country ?? ""
+            /// 省份
+            locationModel?.province = reGeocode.province ?? ""
+            /// 市
+            locationModel?.city = reGeocode.city ?? ""
+            /// 区/县
+            locationModel?.district = reGeocode.district ?? ""
+            /// 街道
+            locationModel?.street = reGeocode.street ?? ""
+            /// 详细描述
+            locationModel?.poiName = reGeocode.poiName ?? ""
+            /// AOIName
+            locationModel?.aoiName = reGeocode.aoiName ?? ""
+            /// 编号
+            locationModel?.number = reGeocode.number ?? ""
+            /// 城市Code
+            locationModel?.citycode = reGeocode.citycode ?? ""
+            /// adcode
+            locationModel?.adcode = reGeocode.adcode ?? ""
+            /// 地址格式化
+            locationModel?.formattedAddress = reGeocode.formattedAddress ?? ""
+        }
+        AMapLocationModel.shared().setLocationModel(locationModel: locationModel!)
+        return locationModel!
+    }
+
+}
+
+// MARK: - 持续定位/后台定位
+extension AMapManager: AMapLocationManagerDelegate {
+
+    func amapLocationManager(_ manager: AMapLocationManager!, didUpdate location: CLLocation!, reGeocode: AMapLocationReGeocode?) {
+        NXLLog("location:{lat:\(location.coordinate.latitude); lon:\(location.coordinate.longitude); accuracy:\(location.horizontalAccuracy);};");
+        locationModel = savelocationModel(location: location, reGeocode: reGeocode)
+    }
+
+}

+ 147 - 0
RainbowPlanet/RainbowPlanet/Manager/MapManager/BaiduMapManager/BaiduMapManager.swift

@@ -0,0 +1,147 @@
+//
+//  BaiduMapManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/10/17.
+//  Copyright © 2018 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+public class BaiduMapManager: NSObject {
+
+    private static let _sharedInstance = BaiduMapManager()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> BaiduMapManager {
+        return _sharedInstance
+    }
+
+    typealias LocationModelBlock = (_ locationModel: LocationModel) -> Void
+
+    var locationModel = LocationModel.shared().getLocationModel()
+
+    public func initBaiduMap() -> Void {
+        BMKLocationAuth.sharedInstance()?.checkPermision(withKey: kBaiduMapAppKey, authDelegate: self)
+        initLocation()
+    }
+
+    /// 单次定位
+    func initLocation() {
+        locationManager.requestLocation(withReGeocode: true, withNetworkState: true) { [weak self] location, state, error in
+            if (error != nil) {
+                LocationModel.shared().setLocationModel(locationModel: (self?.locationModel!)!)
+                return
+            } else {
+                if let location = location {
+                    if let location = location.location {
+                        self?.locationModel?.latitude = String(describing: location.coordinate.latitude)
+                        self?.locationModel?.longitude = String(describing: location.coordinate.longitude)
+                    }
+                    if let rgcData = location.rgcData {
+                        self?.locationModel?.cityCode = rgcData.cityCode ?? ""
+                        self?.locationModel?.province = rgcData.province ?? ""
+                        self?.locationModel?.city = rgcData.city ?? ""
+                        self?.locationModel?.district = rgcData.district ?? ""
+                        self?.locationModel?.street = rgcData.street ?? ""
+                        self?.locationModel?.locationdescribe = rgcData.locationDescribe ?? ""
+                    }
+                    LocationModel.shared().setLocationModel(locationModel: (self?.locationModel!)!)
+                }
+            }
+            self?.locationModel = LocationModel.shared().getLocationModel()
+        }
+    }
+
+    /// 单次定位
+    func initLocation(locationModelBlock:@escaping LocationModelBlock) -> Void {
+
+        locationManager.requestLocation(withReGeocode: true, withNetworkState: true) { [weak self] location, state, error in
+            if (error != nil) {
+                LocationModel.shared().setLocationModel(locationModel:(self?.locationModel!)!)
+                return
+            } else {
+                if let location = location {
+                    if let location = location.location {
+                        self?.locationModel?.latitude = String(describing: location.coordinate.latitude)
+                        self?.locationModel?.longitude = String(describing: location.coordinate.longitude)
+                    }
+                    if let rgcData = location.rgcData {
+                        self?.locationModel?.cityCode = rgcData.cityCode ?? ""
+                        self?.locationModel?.province = rgcData.province ?? ""
+                        self?.locationModel?.city = rgcData.city ?? ""
+                        self?.locationModel?.district = rgcData.district ?? ""
+                        self?.locationModel?.street = rgcData.street ?? ""
+                        self?.locationModel?.locationdescribe = rgcData.locationDescribe ?? ""
+                    }
+                    LocationModel.shared().setLocationModel(locationModel:  (self?.locationModel!)!)
+                }
+            }
+            self?.locationModel = LocationModel.shared().getLocationModel()
+            locationModelBlock((self?.locationModel!)!)
+        }
+    }
+
+    private lazy var locationManager: BMKLocationManager = {
+        let locationManager = BMKLocationManager.init()
+        //设置delegate
+        locationManager.delegate = self
+        //设置返回位置的坐标系类型
+        locationManager.coordinateType = BMKLocationCoordinateType.BMK09LL
+        //设置距离过滤参数
+        locationManager.distanceFilter = kCLDistanceFilterNone
+        //设置预期精度参数
+        locationManager.desiredAccuracy = kCLLocationAccuracyBest
+        //设置应用位置类型
+        locationManager.activityType = CLActivityType.automotiveNavigation
+        //设置是否自动停止位置更新
+        locationManager.pausesLocationUpdatesAutomatically = false
+        //设置是否允许后台定位
+        locationManager.allowsBackgroundLocationUpdates = true
+        //设置位置获取超时时间
+        locationManager.locationTimeout = 10
+        //设置获取地址信息超时时间
+        locationManager.reGeocodeTimeout = 10
+        return locationManager
+    }()
+
+
+
+}
+
+
+// MARK: - 定位代理
+extension BaiduMapManager:BMKLocationManagerDelegate {
+
+    ///  当定位发生错误时,会调用代理的此方法。
+    public func bmkLocationManager(_ manager: BMKLocationManager, didFailWithError error: Error?) {
+        NXLLog("定位错误");
+
+    }
+
+    /// 定位权限状态改变时回调函数
+    public func bmkLocationManager(_ manager: BMKLocationManager, didChange status: CLAuthorizationStatus) {
+        NXLLog("定位权限改变时候的回调");
+        initLocation { (locationModel) in
+
+        }
+    }
+}
+
+
+// MARK: - 定位授权
+extension BaiduMapManager: BMKLocationAuthDelegate {
+
+    public func onCheckPermissionState(_ iError: BMKLocationAuthErrorCode) {
+        if (0 == iError.rawValue) {
+            NXLLog("授权成功");
+            initLocation { (locationModel) in
+
+            }
+        } else {
+            NXLLog("授权失败 \(iError)");
+            LocationModel.shared().setLocationModel(locationModel: locationModel!)
+        }
+    }
+}

+ 119 - 0
RainbowPlanet/RainbowPlanet/Manager/MapManager/BaiduMapManager/LocationModel.swift

@@ -0,0 +1,119 @@
+//
+//  LocationModel.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/10/17.
+//  Copyright © 2018 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class LocationModel: NSObject,NSCoding {
+
+    private static let _sharedInstance = LocationModel()
+
+    override init() {} // 私有化init方法
+
+    class func shared() -> LocationModel {
+        return _sharedInstance
+    }
+
+    /// 纬度
+    var latitude : String = "34.20840377740726"
+    /// 经度
+    var longitude : String = "108.96265686107972"
+    ///国家名字属性
+    var country = "中国"
+    ///国家编码属性
+    var countryCode = "0"
+    ///省份名字属性
+    var province = "陕西省"
+    ///城市名字属性
+    var city = "西安市"
+    ///区名字属性
+    var district = "雁塔区"
+    ///街道名字属性
+    var street = "翠华路"
+    ///街道号码属性
+    var streetNumber = "0"
+    ///城市编码属性
+    var cityCode = "233"
+    ///行政区划编码属性
+    var adCode = "610113"
+    ///位置语义化结果的定位点在什么地方周围的描述信息
+    var locationdescribe = "在西安北大科技园曲江创客大街园区附近"
+    
+    /// 反归档
+    ///
+    /// - Parameter decoder: 反编码值
+    required init?(coder aDecoder: NSCoder) {
+        self.latitude = aDecoder.decodeObject(forKey: "latitude") as? String ?? ""
+        self.longitude = aDecoder.decodeObject(forKey: "longitude") as? String ?? ""
+        self.country = aDecoder.decodeObject(forKey: "country") as? String ?? ""
+        self.countryCode = aDecoder.decodeObject(forKey: "countryCode") as? String ?? ""
+        self.province = aDecoder.decodeObject(forKey: "province") as? String ?? ""
+        self.city = aDecoder.decodeObject(forKey: "city") as? String ?? ""
+        self.district = aDecoder.decodeObject(forKey: "district") as? String ?? ""
+        self.street = aDecoder.decodeObject(forKey: "street") as? String ?? ""
+        self.streetNumber = aDecoder.decodeObject(forKey: "streetNumber") as? String ?? ""
+        self.cityCode = aDecoder.decodeObject(forKey: "cityCode") as? String ?? ""
+        self.adCode = aDecoder.decodeObject(forKey: "adCode") as? String ?? ""
+        self.locationdescribe = aDecoder.decodeObject(forKey: "locationdescribe") as? String ?? ""
+
+    }
+
+    /// 归档
+    ///
+    /// - Parameter aCoder: 归档值
+    func encode(with aCoder: NSCoder) {
+        aCoder.encode(self.latitude, forKey:"latitude")
+        aCoder.encode(self.longitude, forKey:"longitude")
+        aCoder.encode(self.country, forKey:"country")
+        aCoder.encode(self.countryCode, forKey:"countryCode")
+        aCoder.encode(self.province, forKey:"province")
+        aCoder.encode(self.city, forKey:"city")
+        aCoder.encode(self.district, forKey:"district")
+        aCoder.encode(self.street, forKey:"locationDescribe")
+        aCoder.encode(self.streetNumber, forKey:"streetNumber")
+        aCoder.encode(self.cityCode, forKey:"cityCode")
+        aCoder.encode(self.adCode, forKey:"adCode")
+        aCoder.encode(self.locationdescribe, forKey:"locationdescribe")
+
+    }
+
+    /// 存储定位信息
+    ///
+    /// - Parameter locationModel: 定位模型
+    func setLocationModel(locationModel:LocationModel) -> Void {
+        //实例对象转换成Data
+        let modelData = NSKeyedArchiver.archivedData(withRootObject: locationModel)
+        //存储Data对象
+        UserDefaults.standard.set(modelData, forKey: kLocationModelCache)
+    }
+
+
+    /// 获取定位信息
+    ///
+    /// - Returns: 定位模型
+    func getLocationModel() -> LocationModel? {
+        //自定义对象读取
+        let modelData = UserDefaults.standard.data(forKey: kLocationModelCache)
+        var locationModel = LocationModel()
+        if modelData != nil {
+            locationModel = NSKeyedUnarchiver.unarchiveObject(with: modelData!) as! LocationModel
+        }
+        toString()
+        return locationModel
+    }
+
+    func toString() {
+        let str = self.country +
+            self.province +
+            self.city +
+            self.district +
+            self.street +
+            self.locationdescribe
+        NXLLog(str)
+    }
+
+}

+ 111 - 0
RainbowPlanet/RainbowPlanet/Manager/PayManager/AlipayManager/AlipayManager.swift

@@ -0,0 +1,111 @@
+//
+//  AlipayManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class AlipayManager: NSObject {
+    private static let _sharedInstance = AlipayManager()
+
+    private override init() {
+
+    }
+    
+    class func shared() -> AlipayManager {
+        return _sharedInstance
+    }
+
+    typealias SuccessPayBlock = () -> Void
+    var successPayBlock : SuccessPayBlock?
+
+    typealias FailPayBlock = () -> Void
+    var failPayBlock : FailPayBlock?
+
+
+    /// 支付宝支付
+    ///
+    /// - Parameters:
+    ///   - orderString: 支付订单
+    ///   - scheme: 项目scheme
+    ///   - successPayBlock: 成功回调
+    ///   - failPayBlock: 失败回调
+    func alipay(orderString : String,scheme:String = "rainbowplanet",successPayBlock : @escaping SuccessPayBlock,failPayBlock: @escaping FailPayBlock) {
+        self.successPayBlock = successPayBlock;
+        self.failPayBlock = failPayBlock;
+        //唤起支付宝支付页面
+        AlipaySDK.defaultService().payOrder(orderString, fromScheme: scheme, callback: {  [weak self] (result) in
+            let result = result as! Dictionary<String, Any>
+            self?.dealWithAlipyResult(result: result)
+        })
+    }
+
+    func dealWithAlipyResult(result:Dictionary<String, Any>) {
+
+        let alipayResultModel = AlipayResultModel(JSON: result )
+
+        switch  alipayResultModel?.resultStatus {
+        // 订单支付成功
+        case "9000":
+            if let successPayBlock = self.successPayBlock {
+                successPayBlock()
+                SwiftProgressHUD.shared().showSuccess("订单支付成功")
+            }
+            break
+        // 正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
+        case "8000":
+            if let failPayBlock = self.failPayBlock {
+                failPayBlock()
+                SwiftProgressHUD.shared().showText("正在处理中")
+            }
+            break
+        // 用户中途取消
+        case "6001":
+            if let failPayBlock = self.failPayBlock {
+                failPayBlock()
+                SwiftProgressHUD.shared().showText(alipayResultModel?.memo ?? "用户中途取消")
+            }
+            break
+        // 网络连接出错
+        case "6002":
+            if let failPayBlock = self.failPayBlock {
+                failPayBlock()
+                SwiftProgressHUD.shared().showText(alipayResultModel?.memo ?? "网络连接出错")
+            }
+            break
+        // 支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
+        case "6004":
+
+            if let failPayBlock = self.failPayBlock {
+                failPayBlock()
+                SwiftProgressHUD.shared().showText(alipayResultModel?.memo ?? "支付结果未知")
+            }
+            break
+        // 重复请求
+        case "5000":
+            if let failPayBlock = self.failPayBlock {
+                failPayBlock()
+                SwiftProgressHUD.shared().showText(alipayResultModel?.memo ?? "重复请求")
+            }
+            break
+        // 订单支付失败
+        case "4000":
+
+            if let failPayBlock = self.failPayBlock {
+                failPayBlock()
+                SwiftProgressHUD.shared().showText(alipayResultModel?.memo ?? "订单支付失败")
+            }
+            break
+        default:
+
+            if let failPayBlock = self.failPayBlock {
+                failPayBlock()
+                SwiftProgressHUD.shared().showText(alipayResultModel?.memo ?? "系统异常")
+            }
+            break
+        }
+    }
+}

+ 203 - 0
RainbowPlanet/RainbowPlanet/Manager/PayManager/AlipayManager/AlipayResultModel.swift

@@ -0,0 +1,203 @@
+//
+//	AlipayResultModel
+//	Model file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
+
+import Foundation 
+import ObjectMapper
+
+
+class AlipayResultModel : NSObject, NSCoding, Mappable{
+
+	var memo : String?
+	var result : ResultModel?
+	var resultStatus : String?
+
+	class func newInstance(map: Map) -> Mappable?{
+		return AlipayResultModel()
+	}
+	required init?(map: Map){}
+	private override init(){}
+
+	func mapping(map: Map)
+	{
+		memo <- map["memo"]
+		result <- map["result"]
+		resultStatus <- map["resultStatus"]
+		
+	}
+
+    /**
+    * NSCoding required initializer.
+    * Fills the data from the passed decoder
+    */
+    @objc required init(coder aDecoder: NSCoder)
+	{
+         memo = aDecoder.decodeObject(forKey: "memo") as? String
+         result = aDecoder.decodeObject(forKey: "result") as? ResultModel
+         resultStatus = aDecoder.decodeObject(forKey: "resultStatus") as? String
+
+	}
+
+    /**
+    * NSCoding required method.
+    * Encodes mode properties into the decoder
+    */
+    @objc func encode(with aCoder: NSCoder)
+	{
+		if memo != nil{
+			aCoder.encode(memo, forKey: "memo")
+		}
+		if result != nil{
+			aCoder.encode(result, forKey: "result")
+		}
+		if resultStatus != nil{
+			aCoder.encode(resultStatus, forKey: "resultStatus")
+		}
+
+	}
+
+}
+
+class ResultModel : NSObject, NSCoding, Mappable{
+
+    var alipayTradeAppPayResponse : AlipayTradeAppPayResponseMdoel?
+    var sign : String?
+    var signType : String?
+
+
+    class func newInstance(map: Map) -> Mappable?{
+        return ResultModel()
+    }
+    required init?(map: Map){}
+    private override init(){}
+
+    func mapping(map: Map)
+    {
+        alipayTradeAppPayResponse <- map["alipay_trade_app_pay_response"]
+        sign <- map["sign"]
+        signType <- map["sign_type"]
+
+    }
+
+    /**
+     * NSCoding required initializer.
+     * Fills the data from the passed decoder
+     */
+    @objc required init(coder aDecoder: NSCoder)
+    {
+        alipayTradeAppPayResponse = aDecoder.decodeObject(forKey: "alipay_trade_app_pay_response") as? AlipayTradeAppPayResponseMdoel
+        sign = aDecoder.decodeObject(forKey: "sign") as? String
+        signType = aDecoder.decodeObject(forKey: "sign_type") as? String
+
+    }
+
+    /**
+     * NSCoding required method.
+     * Encodes mode properties into the decoder
+     */
+    @objc func encode(with aCoder: NSCoder)
+    {
+        if alipayTradeAppPayResponse != nil{
+            aCoder.encode(alipayTradeAppPayResponse, forKey: "alipay_trade_app_pay_response")
+        }
+        if sign != nil{
+            aCoder.encode(sign, forKey: "sign")
+        }
+        if signType != nil{
+            aCoder.encode(signType, forKey: "sign_type")
+        }
+
+    }
+
+}
+
+class AlipayTradeAppPayResponseMdoel : NSObject, NSCoding, Mappable{
+
+    var appId : String?
+    var charset : String?
+    var code : String?
+    var msg : String?
+    var outTradeNo : String?
+    var sellerId : String?
+    var timestamp : String?
+    var totalAmount : String?
+    var tradeNo : String?
+
+
+    class func newInstance(map: Map) -> Mappable?{
+        return AlipayTradeAppPayResponseMdoel()
+    }
+    required init?(map: Map){}
+    private override init(){}
+
+    func mapping(map: Map)
+    {
+        appId <- map["app_id"]
+        charset <- map["charset"]
+        code <- map["code"]
+        msg <- map["msg"]
+        outTradeNo <- map["out_trade_no"]
+        sellerId <- map["seller_id"]
+        timestamp <- map["timestamp"]
+        totalAmount <- map["total_amount"]
+        tradeNo <- map["trade_no"]
+
+    }
+
+    /**
+     * NSCoding required initializer.
+     * Fills the data from the passed decoder
+     */
+    @objc required init(coder aDecoder: NSCoder)
+    {
+        appId = aDecoder.decodeObject(forKey: "app_id") as? String
+        charset = aDecoder.decodeObject(forKey: "charset") as? String
+        code = aDecoder.decodeObject(forKey: "code") as? String
+        msg = aDecoder.decodeObject(forKey: "msg") as? String
+        outTradeNo = aDecoder.decodeObject(forKey: "out_trade_no") as? String
+        sellerId = aDecoder.decodeObject(forKey: "seller_id") as? String
+        timestamp = aDecoder.decodeObject(forKey: "timestamp") as? String
+        totalAmount = aDecoder.decodeObject(forKey: "total_amount") as? String
+        tradeNo = aDecoder.decodeObject(forKey: "trade_no") as? String
+
+    }
+
+    /**
+     * NSCoding required method.
+     * Encodes mode properties into the decoder
+     */
+    @objc func encode(with aCoder: NSCoder)
+    {
+        if appId != nil{
+            aCoder.encode(appId, forKey: "app_id")
+        }
+        if charset != nil{
+            aCoder.encode(charset, forKey: "charset")
+        }
+        if code != nil{
+            aCoder.encode(code, forKey: "code")
+        }
+        if msg != nil{
+            aCoder.encode(msg, forKey: "msg")
+        }
+        if outTradeNo != nil{
+            aCoder.encode(outTradeNo, forKey: "out_trade_no")
+        }
+        if sellerId != nil{
+            aCoder.encode(sellerId, forKey: "seller_id")
+        }
+        if timestamp != nil{
+            aCoder.encode(timestamp, forKey: "timestamp")
+        }
+        if totalAmount != nil{
+            aCoder.encode(totalAmount, forKey: "total_amount")
+        }
+        if tradeNo != nil{
+            aCoder.encode(tradeNo, forKey: "trade_no")
+        }
+
+    }
+
+}
+
+

+ 83 - 0
RainbowPlanet/RainbowPlanet/Manager/PayManager/PayManager/PayManager.swift

@@ -0,0 +1,83 @@
+//
+//  PayManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class PayManager: NSObject {
+    private static let _sharedInstance = PayManager()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> PayManager {
+        return _sharedInstance
+    }
+
+    typealias SuccessPayBlock = () -> Void
+    var successPayBlock : SuccessPayBlock?
+
+    typealias FailPayBlock = () -> Void
+    var failPayBlock : FailPayBlock?
+
+
+    /// 支付宝支付
+    ///
+    /// - Parameters:
+    ///   - orderString: 订单编号
+    ///   - successPayBlock: 回调成功处理
+    ///   - failPayBlock: 回调失败处理
+    func alipay(orderString: String , scheme: String = "rainbowplanet",successPayBlock : @escaping SuccessPayBlock,failPayBlock: @escaping FailPayBlock) {
+        AlipayManager.shared().alipay(orderString: orderString,scheme:scheme, successPayBlock: { [weak self] in
+            self?.successPayBlock = successPayBlock
+            successPayBlock()
+        }) {  [weak self] in
+            self?.failPayBlock = failPayBlock
+            failPayBlock()
+        }
+    }
+
+
+    /// 微信支付
+    ///
+    /// - Parameters:
+    ///   - wechatpayOrderModel: 订单信息
+    ///   - successPayBlock: 回调成功处理
+    ///   - failPayBlock: 回调失败处理
+    func weixinpay(wechatpayOrderModel:WeChatpayOrderModel,successPayBlock : @escaping SuccessPayBlock,failPayBlock: @escaping FailPayBlock) {
+        WeChatpayManager.shared().weixinPay(wechatpayOrderModel: wechatpayOrderModel, successPayBlock: { [weak self] in
+            self?.successPayBlock = successPayBlock
+            successPayBlock()
+        }) { [weak self] in
+            self?.failPayBlock = failPayBlock
+            failPayBlock()
+        }
+    }
+
+
+    /// 回调处理
+    ///
+    /// - Parameter url:
+    /// - Returns:
+    func handleOpen(url:URL) -> Bool {
+
+        if url.host == "safepay" { //支付宝
+            //跳转支付宝钱包进行支付,处理支付结果
+            AlipaySDK.defaultService()?.processOrder(withPaymentResult: url, standbyCallback: { (result) in
+                let result = result as! Dictionary<String, Any>
+                AlipayManager.shared().dealWithAlipyResult(result: result)
+            })
+            return true
+        }
+
+        if url.absoluteString.contains("pay"){//微信
+            return WXApi.handleOpen(url, delegate:WeChatpayManager.shared())
+        }
+
+        return false
+    }
+
+}

+ 93 - 0
RainbowPlanet/RainbowPlanet/Manager/PayManager/WeChatpayManager/WeChatpayManager.swift

@@ -0,0 +1,93 @@
+//
+//  WeChatpayManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/8.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class WeChatpayManager: NSObject {
+    private static let _sharedInstance = WeChatpayManager()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> WeChatpayManager {
+        return _sharedInstance
+    }
+
+    typealias SuccessPayBlock = () -> Void
+    var successPayBlock : SuccessPayBlock?
+
+    typealias FailPayBlock = () -> Void
+    var failPayBlock : FailPayBlock?
+
+    /** 是否注册了微信APP */
+    var hasRegisteWeChat: Bool = false
+
+    func weixinPay(wechatpayOrderModel : WeChatpayOrderModel,successPayBlock : @escaping SuccessPayBlock,failPayBlock: @escaping FailPayBlock) {
+        self.successPayBlock = successPayBlock;
+        self.failPayBlock = failPayBlock;
+
+        if (!hasRegisteWeChat) {
+            hasRegisteWeChat = WXApi.registerApp(kWeiXinAppKey)
+        }
+        if (!WXApi.isWXAppInstalled()) {
+            SwiftProgressHUD.shared().showWarning("您尚未安装微信,请选择其它支付方式")
+            return
+        }
+
+        let payReq = PayReq.init()
+        payReq.openID = wechatpayOrderModel.appid
+        payReq.partnerId = wechatpayOrderModel.partnerid
+        payReq.prepayId = wechatpayOrderModel.prepayid
+        payReq.package = wechatpayOrderModel.package
+        payReq.nonceStr = wechatpayOrderModel.noncestr
+        payReq.timeStamp = UInt32(wechatpayOrderModel.timestamp)!
+        payReq.sign = wechatpayOrderModel.sign
+        WXApi.send(payReq)
+    }
+
+}
+
+extension WeChatpayManager : WXApiDelegate {
+
+    func onResp(_ resp: BaseResp) {
+        //  微信支付回调
+        if resp.isKind(of: PayResp.self)
+        {
+            switch resp.errCode
+            {
+            // 成功 展示成功页面
+            case 0 :
+                if let successPayBlock = self.successPayBlock {
+                    successPayBlock()
+                    SwiftProgressHUD.shared().showSuccess("订单支付成功")
+                }
+                break
+            // 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
+            case -1 :
+                if let failPayBlock = self.failPayBlock {
+                    failPayBlock()
+                    SwiftProgressHUD.shared().showError("支付异常:请重新支付")
+                }
+                break
+            // 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP。
+            case -2 :
+                if let failPayBlock = self.failPayBlock {
+                    failPayBlock()
+                    SwiftProgressHUD.shared().showError("用户取消")
+                }
+                break
+            //  支付失败
+            default:
+                if let failPayBlock = self.failPayBlock {
+                    failPayBlock()
+                    SwiftProgressHUD.shared().showError("支付失败,请重新支付")
+                }
+                break
+            }
+        }
+    }
+}

+ 46 - 0
RainbowPlanet/RainbowPlanet/Manager/PayManager/WeChatpayManager/WeChatpayOrderModel.swift

@@ -0,0 +1,46 @@
+//
+//	RootClass.swift
+//	Model file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
+
+import Foundation 
+import ObjectMapper
+
+
+class WeChatpayOrderModel : NSObject, Mappable{
+
+
+    /// 微信开放平台审核通过的应用APPID 应用ID
+	var appid : String = ""
+    /// 随机字符串 随机字符串,不长于32位。
+	var noncestr : String = ""
+    /// 随机字符串 随机字符串,不长于32位。
+	var package: String = ""
+    /// 微信商户Id
+	var partnerid : String = ""
+    /// 微信返回的支付交易会话ID 预支付交易会话ID(订单编号)
+    var prepayid : String = ""
+    /// 签名
+	var sign : String = ""
+    /// 时间戳
+	var timestamp : String = ""
+
+
+	class func newInstance(map: Map) -> Mappable?{
+		return WeChatpayOrderModel()
+	}
+	required init?(map: Map){}
+	private override init(){}
+
+	func mapping(map: Map)
+	{
+		appid <- map["appid"]
+		noncestr <- map["noncestr"]
+		package <- map["package"]
+		partnerid <- map["partnerid"]
+		prepayid <- map["prepayid"]
+		sign <- map["sign"]
+		timestamp <- map["timestamp"]
+		
+	}
+
+}

+ 17 - 0
RainbowPlanet/RainbowPlanet/Manager/UMManager/UMLoginModel.swift

@@ -0,0 +1,17 @@
+//
+//  UMLoginModel.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/4/10.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class UMLoginModel: NSObject {
+    var open_id : String = ""
+    var union_id : String = ""
+    var avatar : String = ""
+    var username : String = ""
+    var gender : Int = 0
+}

+ 398 - 0
RainbowPlanet/RainbowPlanet/Manager/UMManager/UMManager.swift

@@ -0,0 +1,398 @@
+//
+//  UMManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/7.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+public enum ShareType {
+    case text
+    case image
+    case webPage
+}
+
+public var _entity : UMessageRegisterEntity?
+
+public class UMManager: NSObject {
+    private static let sharedInstance = UMManager()
+    private override init() {} // 私有化init方法
+
+    /// 单例
+    ///
+    /// - Returns: UMShareManager对象
+    public class func shared() -> UMManager {
+        return sharedInstance
+    }
+
+    /// 友盟初始化
+    public func initUM(launchOptions:[UIApplication.LaunchOptionsKey: Any]?) -> Void {
+        //公共
+        common()
+        //推送
+        push(launchOptions: launchOptions)
+        //分享
+        share()
+    }
+}
+
+// MARK: 公共
+public extension UMManager {
+    ///公共
+    func common() -> Void {
+
+        //将自动采集页面信息
+        //        MobClick.setAutoPageEnabled(true)
+        //开发者需要显式的调用此函数,日志系统才能工作
+        UMCommonLogManager.setUp()
+        //打开加密传输
+        UMConfigure.setEncryptEnabled(true)
+        //设置打开日志
+        UMConfigure.setLogEnabled(false)
+        //设置Key
+        UMConfigure.initWithAppkey(kUMengAppKey, channel: "App Store")
+
+        //开启Crash收集
+        MobClick.setCrashReportEnabled(true)
+        //默认为普通应用场景,目前还支持游戏统计场景
+        MobClick.setScenarioType(eScenarioType.E_UM_NORMAL)
+        //获得集成测试需要device_id
+        let deice_id = UMConfigure.deviceIDForIntegration()
+        if deice_id != nil {
+            NXLLog("服务器端成功返回deviceID:\(deice_id!)");
+        }else {
+            NXLLog("服务器端还没有返回deviceID");
+        }
+    }
+}
+
+// MARK: 推送
+public extension UMManager {
+
+    ///推送
+    func push(launchOptions:[UIApplication.LaunchOptionsKey: Any]?) -> Void {
+
+        _entity = UMessageRegisterEntity.init()
+        //type是对推送的几个参数的选择,可以选择一个或者多个。默认是三个全部打开,即:声音,弹窗,角标
+        _entity?.types = Int(UInt8(UMessageAuthorizationOptions.badge.rawValue)|UInt8(UMessageAuthorizationOptions.alert.rawValue)|UInt8(UMessageAuthorizationOptions.sound.rawValue))
+
+        if #available(iOS 8.0, *) {
+            if #available(iOS 10.0, *) {
+
+                let action1_ios10 = UNNotificationAction(identifier: "action1_identifier", title: "打开应用", options: UNNotificationActionOptions.foreground)
+                let action2_ios10 = UNNotificationAction(identifier: "action2_identifier", title: "忽略", options: UNNotificationActionOptions.foreground)
+
+                let category1_ios10 = UNNotificationCategory(identifier: "category1", actions: [action1_ios10,action2_ios10], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
+                //UNNotificationCategoryOptionNone
+                //UNNotificationCategoryOptionCustomDismissAction  清除通知被触发会走通知的代理方法
+                //UNNotificationCategoryOptionAllowInCarPlay       适用于行车模式
+                let categories = NSSet(objects: category1_ios10)
+                _entity?.categories = (categories as! Set<AnyHashable>)
+                UNUserNotificationCenter.current().delegate = self
+
+            } else {
+                let action1 = UIMutableUserNotificationAction.init()
+                action1.identifier = "action1_identifier"
+                action1.title = "打开应用"
+                action1.activationMode = UIUserNotificationActivationMode.foreground;//当点击的时候启动程序
+
+                let action2 = UIMutableUserNotificationAction.init()
+                action2.identifier = "action2_identifier"
+                action2.title = "忽略"
+                action2.activationMode = UIUserNotificationActivationMode.background;//当点击的时候不启动程序,在后台处理
+                action2.isAuthenticationRequired = true;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略;
+                action2.isDestructive = true;
+
+                let actionCategory1 = UIMutableUserNotificationCategory.init()
+                actionCategory1.identifier = "category1"//这组动作的唯一标示
+                actionCategory1.setActions([action1,action2], for: UIUserNotificationActionContext.default)
+                let categories = NSSet(objects: actionCategory1)
+                _entity?.categories = (categories as! Set<AnyHashable>)
+
+            }
+        }
+
+        UMessage.registerForRemoteNotifications(launchOptions: launchOptions, entity: _entity) { (granted, error) in
+
+            if granted {
+
+            }else {
+
+            }
+        }
+        UMessage.setBadgeClear(true)//设置是否允许SDK自动清空角标
+        UMessage.openDebugMode(true)
+        UMessage.setWebViewClassString("UMWebViewController")
+        UMessage.addLaunch()
+    }
+}
+
+// MARK: 分享
+public extension UMManager {
+    /// 分享设置
+    func share() -> Void {
+        /*
+         设置微信的appKey和appSecret
+         [微信平台从U-Share 4/5升级说明]http://dev.umeng.com/social/ios/%E8%BF%9B%E9%98%B6%E6%96%87%E6%A1%A3#1_1
+         */
+        UMSocialManager.default().setPlaform(UMSocialPlatformType.wechatSession, appKey: kWeiXinAppKey, appSecret: kWeiXinAppSecret, redirectURL: nil)
+        /* 设置分享到QQ互联的appID
+         * U-Share SDK为了兼容大部分平台命名,统一用appKey和appSecret进行参数设置,而QQ平台仅需将appID作为U-Share的appKey参数传进即可。
+         100424468.no permission of union id
+         [QQ/QZone平台集成说明]http://dev.umeng.com/social/ios/%E8%BF%9B%E9%98%B6%E6%96%87%E6%A1%A3#1_3
+         */
+        UMSocialManager.default().setPlaform(UMSocialPlatformType.QQ, appKey: kQQAppKey, appSecret: kQQAppSecret, redirectURL: nil)
+        /*
+         设置新浪的appKey和appSecret
+         [新浪微博集成说明]http://dev.umeng.com/social/ios/%E8%BF%9B%E9%98%B6%E6%96%87%E6%A1%A3#1_2
+         */
+        UMSocialManager.default().setPlaform(UMSocialPlatformType.sina, appKey: kWeiboAppKey, appSecret: kWeiboAppSecret, redirectURL: "https://sns.whalecloud.com/sina2/callback")
+
+        /*
+         * 移除相应平台的分享,如微信收藏
+         */
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.alipaySession)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.yixinSession)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.yixinTimeLine)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.laiWangSession)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.sms)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.email)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.renren)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.facebook)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.twitter)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.douban)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.kakaoTalk)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.pinterest)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.line)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.linkedin )
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.flickr)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.tumblr)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.instagram)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.whatsapp)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.dingDing)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.youDaoNote)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.everNote)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.googlePlus)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.pocket)
+
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.dropBox)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.vKontakte)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.faceBookMessenger)
+        UMSocialManager.default()?.removePlatformProvider(with: UMSocialPlatformType.tim)
+    }
+
+    /// 分享面板
+    ///
+    /// - Parameters:
+    ///   - shareType: 平台
+    ///   - viewController: 控制器
+    ///   - text: 分享文本
+    ///   - thumbImage: 缩略图
+    ///   - shareImage: 分享图
+    ///   - title: 标题
+    ///   - descr: 内容描述
+    ///   - webpageUrl: 链接地址
+    func UMSocialUI(shareType:ShareType, viewController:UIViewController,text:String,thumbImage:Any,shareImage:Any,title:String,descr:String,webpageUrl:String) -> Void {
+
+        UMSocialUIManager.showShareMenuViewInWindow(platformSelectionBlock: {[weak self] platformType, userInfo in
+            switch shareType {
+            case .text:
+                self?.shareText(to: platformType, viewController: viewController,text: text)
+                break
+            case .image:
+                self?.shareImage(to: platformType, viewController: viewController,thumbImage: thumbImage,shareImage: shareImage)
+                break
+            case .webPage:
+                self?.shareWebPage(to: platformType, viewController: viewController,title: title,descr: descr, thumbImage: thumbImage,webpageUrl: webpageUrl)
+                break
+            }
+        })
+    }
+
+    /// 分享文本
+    ///
+    /// - Parameters:
+    ///   - platformType: 平台
+    ///   - viewController: 控制器
+    ///   - text: 分享文本
+    func shareText(to platformType: UMSocialPlatformType,viewController:UIViewController,text:String) {
+        //创建分享消息对象
+        let messageObject = UMSocialMessageObject()
+        //设置文本
+        messageObject.text = text
+
+        //调用分享接口
+        UMSocialManager.default().share(to: platformType, messageObject: messageObject, currentViewController: viewController) { data, error in
+            if error != nil {
+                if let anError = error {
+                    NXLLog("************Share fail with error \(anError)*********")
+                }
+            } else {
+                if let aData = data {
+                    NXLLog("response data is \(aData)")
+                }
+            }
+        }
+    }
+
+    /// 分享图片
+    ///
+    /// - Parameters:
+    ///   - platformType: 平台
+    ///   - viewController: 控制器
+    ///   - thumbImage: 缩略图
+    ///   - shareImage: 分享图
+    func shareImage(to platformType: UMSocialPlatformType,viewController:UIViewController,thumbImage:Any,shareImage:Any) {
+        //创建分享消息对象
+        let messageObject = UMSocialMessageObject()
+
+        //创建图片内容对象
+        let shareObject = UMShareImageObject()
+        //如果有缩略图,则设置缩略图
+        shareObject.thumbImage = thumbImage
+        shareObject.shareImage = shareImage
+
+        //分享消息对象设置分享内容对象
+        messageObject.shareObject = shareObject
+
+        //调用分享接口
+        UMSocialManager.default().share(to: platformType, messageObject: messageObject, currentViewController: viewController) { data, error in
+            if error != nil {
+                if let anError = error {
+                    NXLLog("************Share fail with error \(anError)*********")
+                }
+            } else {
+                if let aData = data {
+                    NXLLog("response data is \(aData)")
+                }
+            }
+        }
+    }
+
+    /// 分享网页
+    ///
+    /// - Parameters:
+    ///   - platformType: 平台
+    ///   - viewController: 控制器
+    ///   - title: 标题
+    ///   - descr: 内容描述
+    ///   - thumbImage: 缩略图
+    ///   - webpageUrl: 链接地址
+    func shareWebPage(to platformType: UMSocialPlatformType,viewController:UIViewController,title:String,descr:String,thumbImage:Any,webpageUrl:String) {
+        //创建分享消息对象
+        let messageObject = UMSocialMessageObject()
+
+        //创建网页内容对象
+        let shareObject = UMShareWebpageObject.shareObject(withTitle: title, descr: descr, thumImage: thumbImage)
+        //设置网页地址
+        shareObject!.webpageUrl = webpageUrl
+
+        //分享消息对象设置分享内容对象
+        messageObject.shareObject = shareObject
+
+        //调用分享接口
+        UMSocialManager.default().share(to: platformType, messageObject: messageObject, currentViewController: viewController) { data, error in
+            if error != nil {
+                if let anError = error {
+                    NXLLog("************Share fail with error \(anError)*********")
+                }
+            } else {
+                if let aData = data {
+                    NXLLog("response data is \(aData)")
+                }
+            }
+        }
+    }
+}
+
+// MARK: 第三方登录
+extension UMManager {
+    /// 第三方登录
+    ///
+    /// - Parameter platformType: 平台
+    func loginGetUserInfo(platformType: UMSocialPlatformType,callBack: @escaping (UMLoginModel) -> (Void)) {
+
+        let isInstall = UMSocialManager.default()?.isInstall(platformType)
+        if isInstall!  { //验证
+            UMSocialManager.default().getUserInfo(with: platformType, currentViewController: nil) { result, error in
+
+                if error != nil {
+                    SwiftProgressHUD.shared().showText("授权失败,请重新登录")
+                } else {
+
+                    let resp = result as? UMSocialUserInfoResponse
+
+                    let loginModel = UMLoginModel()
+                    // 第三方登录数据(为空表示平台未提供)
+                    // 授权数据
+                    if let anUid = resp?.uid {
+                        NXLLog(" uid: \(anUid)")
+                        loginModel.union_id = anUid
+                    }
+                    if let anOpenid = resp?.openid {
+                        NXLLog(" openid: \(anOpenid)")
+                        loginModel.open_id = anOpenid
+                    }
+
+                    // 用户数据
+                    if let aName = resp?.name {
+                        NXLLog(" name: \(aName)")
+                        loginModel.username = aName
+                    }
+                    if let anIconurl = resp?.iconurl {
+                        NXLLog(" iconurl: \(anIconurl)")
+                        loginModel.avatar = anIconurl
+                    }
+                    if let aGender = resp?.unionGender {
+                        NXLLog(" gender: \(aGender)")
+                        if aGender == "男" {
+                            loginModel.gender = 1
+                        }else if aGender == "女" {
+                            loginModel.gender = 2
+                        }
+                    }
+                    callBack(loginModel)
+                }
+            }
+        }
+    else {
+            if platformType == .wechatSession {
+                SwiftProgressHUD.shared().showText("微信未安装/n请您安装微信程序")
+            }
+        }
+    }
+}
+
+
+@available(iOS 10.0, *)
+// MARK: - UNUserNotificationCenterDelegate
+extension UMManager:UNUserNotificationCenterDelegate {
+    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
+        let userInfo = notification.request.content.userInfo
+
+        if (notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self))! {
+            UMessage.setAutoAlert(true)
+            //应用处于前台时的远程推送接受
+            //必须加这句代码
+            UMessage.didReceiveRemoteNotification(userInfo)
+
+        }else {
+            //应用处于前台时的本地推送接受
+        }
+        completionHandler(UNNotificationPresentationOptions(rawValue: UNNotificationPresentationOptions.sound.rawValue|UNNotificationPresentationOptions.alert.rawValue|UNNotificationPresentationOptions.badge.rawValue))
+    }
+
+    public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
+        let userInfo = response.notification.request.content.userInfo
+        if (response.notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self))! {
+            UMessage.setAutoAlert(true)
+            //应用处于前台时的远程推送接受
+            //必须加这句代码
+            UMessage.didReceiveRemoteNotification(userInfo)
+        }else {
+            //应用处于前台时的本地推送接受
+        }
+    }
+}

+ 39 - 0
RainbowPlanet/RainbowPlanet/Modules/MineModule/Mine/ViewController/MineViewController.swift

@@ -0,0 +1,39 @@
+//
+//  MineViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/7.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+
+class MineViewController: BaseViewController {
+
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        MobClick.beginLogPageView("MineViewController:我的页面")
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        MobClick.endLogPageView("MineViewController:我的页面")
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+    }
+
+    @IBAction func weixinLogin(_ sender: UIButton) {
+//        UMManager.shared().loginGetUserInfo(platformType: UMSocialPlatformType.sina)
+        
+    }
+
+    @IBAction func UMSharedAction(_ sender: UIButton) {
+        UMManager.shared().UMSocialUI(shareType: ShareType.text, viewController: self, text: "test", thumbImage: "", shareImage: "", title: "", descr: "", webpageUrl: "")
+    }
+    @IBAction func OnceLogin(_ UIButton: Any) {
+        
+    }
+}

+ 53 - 0
RainbowPlanet/RainbowPlanet/Modules/MineModule/Mine/ViewController/MineViewController.xib

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MineViewController" customModule="RainbowPlanet" customModuleProvider="target">
+            <connections>
+                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4Kp-SH-yHy">
+                    <rect key="frame" x="135" y="124" width="62" height="30"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                    <state key="normal" title="微信登录"/>
+                    <connections>
+                        <action selector="weixinLogin:" destination="-1" eventType="touchUpInside" id="141-hl-LnN"/>
+                    </connections>
+                </button>
+                <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WQK-xB-nCF">
+                    <rect key="frame" x="135" y="178" width="62" height="30"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                    <state key="normal" title="友盟分享"/>
+                    <connections>
+                        <action selector="UMSharedAction:" destination="-1" eventType="touchUpInside" id="MIc-i4-atv"/>
+                    </connections>
+                </button>
+                <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iD1-wa-R3r">
+                    <rect key="frame" x="135" y="238" width="62" height="30"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                    <state key="normal" title="一键登录"/>
+                    <connections>
+                        <action selector="OnceLogin:" destination="-1" eventType="touchUpInside" id="YxS-OX-VMu"/>
+                        <action selector="UMSharedAction:" destination="-1" eventType="touchUpInside" id="YwI-Ji-B6B"/>
+                    </connections>
+                </button>
+            </subviews>
+            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
+        </view>
+    </objects>
+</document>

+ 294 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/BindPhoneNumber/ViewController/BindPhoneNumberViewController.swift

@@ -0,0 +1,294 @@
+//
+//  BindPhoneNumberViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/22.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+import RxCocoa
+
+class BindPhoneNumberViewController: BaseViewController {
+
+    /// 手机号
+    var phoneNumber : String = ""
+
+    ///
+    var sms : String = ""
+
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        MobClick.beginLogPageView("BindPhoneNumberViewController:绑定手机号页面")
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        MobClick.endLogPageView("BindPhoneNumberViewController:绑定手机号页面")
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        navigationBar.onClickLeftButton = { [weak self] in
+            self?.dismissToRootViewController(animated: true, completion:nil)
+        }
+        setupViews()
+        setupLayouts()
+    }
+
+    override  func setupViews() {
+        view.addSubview(bindPhoneNumberLabel)
+        view.addSubview(bindPhoneNumberInfoLabel)
+
+        view.addSubview(phoneNumberBgView)
+        phoneNumberBgView.addSubview(linePhoneNumberLabel)
+        phoneNumberBgView.addSubview(phoneAreaCodeLabel)
+        phoneNumberBgView.addSubview(phoneAreaCodeIconImageView)
+        phoneNumberBgView.addSubview(phoneNumberTextField)
+
+        view.addSubview(smsBgView)
+        smsBgView.addSubview(linesmsLabel)
+        smsBgView.addSubview(smsButton)
+        smsBgView.addSubview(smsTextField)
+
+        view.addSubview(bindPhoneNumberButton)
+
+    }
+
+    override func setupLayouts() {
+        bindPhoneNumberLabel.snp.makeConstraints { (make) in
+            make.top.equalToSuperview().offset(76 + kNavBarTotalHeight)
+            make.left.equalToSuperview().offset(40)
+        }
+        bindPhoneNumberInfoLabel.snp.makeConstraints { (make) in
+            make.top.equalTo(bindPhoneNumberLabel.snp.bottom).offset(6)
+            make.left.equalTo(bindPhoneNumberLabel)
+        }
+        phoneNumberBgView.snp.makeConstraints { (make) in
+            make.left.equalToSuperview().offset(38)
+            make.right.equalToSuperview().offset(-38)
+            make.top.equalTo(bindPhoneNumberInfoLabel.snp.bottom).offset(27)
+            make.height.equalTo(48)
+        }
+        linePhoneNumberLabel.snp.makeConstraints { (make) in
+            make.left.right.bottom.equalToSuperview()
+            make.height.equalTo(1)
+        }
+
+        phoneAreaCodeLabel.snp.makeConstraints { (make) in
+            make.top.equalToSuperview().offset(6)
+            make.left.equalToSuperview().offset(4)
+            make.bottom.equalToSuperview()
+        }
+
+        phoneAreaCodeIconImageView.snp.makeConstraints { (make) in
+            make.centerY.equalTo(phoneAreaCodeLabel)
+            make.left.equalTo(phoneAreaCodeLabel.snp.right).offset(4)
+            make.width.equalTo(9)
+        }
+
+        phoneNumberTextField.snp.makeConstraints { (make) in
+            make.left.equalTo(phoneAreaCodeIconImageView.snp.right).offset(15)
+            make.top.bottom.equalTo(phoneAreaCodeLabel)
+            make.width.equalTo(kScreenWidth-76-35-phoneAreaCodeLabel.width)
+        }
+
+        smsBgView.snp.makeConstraints { (make) in
+            make.left.height.right.equalTo(phoneNumberBgView)
+            make.top.equalTo(phoneNumberBgView.snp.bottom)
+        }
+        linesmsLabel.snp.makeConstraints { (make) in
+            make.left.right.bottom.equalToSuperview()
+            make.height.equalTo(1)
+        }
+
+        smsButton.snp.makeConstraints { (make) in
+            make.bottom.equalToSuperview().offset(-8)
+            make.height.equalTo(30)
+            make.right.equalToSuperview().offset(-4)
+        }
+        smsTextField.snp.makeConstraints { (make) in
+            make.bottom.top.equalTo(smsButton)
+            make.left.equalTo(phoneAreaCodeLabel)
+            make.width.equalTo(kScreenWidth-76-30-smsButton.width)
+        }
+
+        bindPhoneNumberButton.snp.makeConstraints { (make) in
+            make.top.equalTo(smsBgView.snp.bottom).offset(35)
+            make.height.equalTo(44)
+            make.right.equalToSuperview().offset(-38)
+            make.left.equalToSuperview().offset(38)
+        }
+    }
+
+    private lazy var bindPhoneNumberLabel: UILabel = {
+        let bindPhoneNumberLabel = UILabel()
+        bindPhoneNumberLabel.text = "绑定手机号"
+        bindPhoneNumberLabel.textColor = k333333Color
+        bindPhoneNumberLabel.font = kBoldFont22
+        return bindPhoneNumberLabel
+    }()
+
+    private lazy var bindPhoneNumberInfoLabel: UILabel = {
+        let bindPhoneNumberInfoLabel = UILabel()
+        bindPhoneNumberInfoLabel.text = "为了账号安全,请绑定手机"
+        bindPhoneNumberInfoLabel.textColor = k666666Color
+        bindPhoneNumberInfoLabel.font = kRegularFont12
+        return bindPhoneNumberInfoLabel
+    }()
+
+    private lazy var phoneNumberBgView: UIView = {
+        let phoneNumberBgView = UIView()
+        return phoneNumberBgView
+    }()
+
+    private lazy var linePhoneNumberLabel: UILabel = {
+        let linePhoneNumberLabel = UILabel()
+        linePhoneNumberLabel.backgroundColor = ke6e6e6Color
+        return linePhoneNumberLabel
+    }()
+
+    private lazy var phoneAreaCodeLabel: UILabel = {
+        let phoneAreaCodeLabel = UILabel()
+        phoneAreaCodeLabel.text = "+86"
+        phoneAreaCodeLabel.textColor = k333333Color
+        phoneAreaCodeLabel.font = kRegularFont16
+        phoneAreaCodeLabel.sizeToFit()
+        phoneAreaCodeLabel.addTapGesture(1, target: self, action: #selector(phoneAreaCodeAction))
+        return phoneAreaCodeLabel
+    }()
+
+    private lazy var phoneAreaCodeIconImageView : UIImageView = {
+        let phoneAreaCodeIconImageView = UIImageView()
+        phoneAreaCodeIconImageView.image = kImage(name: "navigaitionbar_back_black")
+        phoneAreaCodeIconImageView.addTapGesture(1, target: self, action: #selector(phoneAreaCodeAction))
+        return phoneAreaCodeIconImageView
+    }()
+
+    private lazy var phoneNumberTextField : UITextField = {
+        let phoneNumberTextField = UITextField()
+        phoneNumberTextField.placeholder = "手机号码"
+        phoneNumberTextField.borderStyle = .none
+        phoneNumberTextField.textColor = k666666Color
+        phoneNumberTextField.font = kRegularFont16
+        phoneNumberTextField.clearButtonMode = .whileEditing
+        phoneNumberTextField.sizeToFit()
+        phoneNumberTextField.keyboardType = .numberPad
+        phoneNumberTextField.rx.text.changed.subscribe(onNext: { [weak self] (text) in
+            self?.phoneNumberTextField.text = String(text?.prefix(11) ?? "") as String
+            self?.phoneNumber = self?.phoneNumberTextField.text ?? ""
+            self?.observableString()
+        }).disposed(by: disposeBag)
+        return phoneNumberTextField
+    }()
+
+    private lazy var smsBgView: UIView = {
+        let smsBgView = UIView()
+        return smsBgView
+    }()
+
+    private lazy var linesmsLabel: UILabel = {
+        let linesmsLabel = UILabel()
+        linesmsLabel.backgroundColor = ke6e6e6Color
+        return linesmsLabel
+    }()
+
+    private lazy var smsButton: CountdownButton = {
+        let smsButton = CountdownButton(type: UIButton.ButtonType.custom)
+        smsButton.normalText = "  获取验证码  "
+        smsButton.disabledText = "  seconds后重新获取  "
+        smsButton.setTitle(smsButton.normalText, for: UIControl.State.normal)
+        smsButton.setTitle(smsButton.disabledText, for: UIControl.State.disabled)
+        smsButton.setTitleColor(kED3934Color, for: UIControl.State.normal)
+        smsButton.setTitleColor(k333333Color, for: UIControl.State.disabled)
+        smsButton.titleLabel?.font = kRegularFont12
+        smsButton.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.center
+        smsButton.sizeToFit()
+        smsButton.normalBorderColor = kED3934Color
+        smsButton.normalBorderWidth = 0.5
+        smsButton.normalCornerRadius = 15
+        smsButton.normalBackgroundColor = UIColor.white
+        smsButton.disabledBorderColor = ke6e6e6Color
+        smsButton.disabledBorderWidth = 0.5
+        smsButton.disabledCornerRadius = 15
+        smsButton.disabledBackgroundColor = ke6e6e6Color
+        smsButton.maxSecond = 60
+        smsButton.updateNormal()
+        smsButton.addTarget(self, action: #selector(smsAction), for: UIControl.Event.touchUpInside)
+        return smsButton
+    }()
+
+    private lazy var smsTextField : UITextField = {
+        let smsTextField = UITextField()
+        smsTextField.placeholder = "验证码"
+        smsTextField.borderStyle = .none
+        smsTextField.textColor = k666666Color
+        smsTextField.font = kRegularFont16
+        smsTextField.sizeToFit()
+        smsTextField.keyboardType = .numberPad
+        smsTextField.rx.text.changed.subscribe(onNext: { [weak self] (text) in
+            self?.smsTextField.text = String(text?.prefix(6) ?? "") as String
+            self?.sms = self?.smsTextField.text ?? ""
+            self?.observableString()
+        }).disposed(by: disposeBag)
+
+        return smsTextField
+    }()
+
+    private lazy var bindPhoneNumberButton: UIButton = {
+        let bindPhoneNumberButton = UIButton(type: UIButton.ButtonType.custom)
+        bindPhoneNumberButton.setTitle("立即绑定", for: UIControl.State.normal)
+        bindPhoneNumberButton.setTitleColor(kffffffColor, for: UIControl.State.normal)
+        bindPhoneNumberButton.setTitleColor(k666666Color, for: UIControl.State.disabled)
+        bindPhoneNumberButton.setBackgroundImage(UIImage.imageWithColor(color: kDisabledButtonColor), for: UIControl.State.disabled)
+        bindPhoneNumberButton.setBackgroundImage(UIImage.imageWithColor(color: kEnabledButtonColor), for: UIControl.State.normal)
+        bindPhoneNumberButton.titleLabel?.font = kRegularFont18
+        bindPhoneNumberButton.cornerRadius = 22
+        bindPhoneNumberButton.masksToBounds = true
+        bindPhoneNumberButton.isEnabled = false
+        bindPhoneNumberButton.addTarget(self, action: #selector(bindPhoneNumberAction), for: UIControl.Event.touchUpInside)
+        return bindPhoneNumberButton
+    }()
+
+}
+
+
+// MARK: - action
+extension BindPhoneNumberViewController {
+
+    /// 区域号选择
+    @objc func phoneAreaCodeAction() {
+        let vc = PhoneCountryAreaViewController()
+        vc.phoneCountryAreaVCCloSure = { [weak self] (phoneCountryAreaMdoel:PhoneCountryAreaMdoel) in
+            self?.phoneAreaCodeLabel.text = phoneCountryAreaMdoel.countryCode
+        }
+        self.present(vc, animated: true) {
+
+        }
+    }
+
+    /// 获取验证
+    @objc func smsAction() {
+        smsButton.countdown = true
+    }
+
+    /// 立即绑定
+    @objc func bindPhoneNumberAction() {
+//        SwiftProgressHUD.shared().showText("手机号绑定成功")
+        self.dismissToRootViewController(animated: true) {
+        }
+    }
+
+    func observableString() {
+        Observable.combineLatest(Observable.just(phoneNumber), Observable.just(sms)) { (textValue1, textValue2) -> Bool in
+            let textValue1 = String(textValue1.prefix(11)) as String
+            let textValue2 = String(textValue2.prefix(6)) as String
+            let isSuccess = (textValue1.count == 11) && (textValue2.count == 6)
+            return isSuccess
+            }.subscribe(onNext: {
+                [weak self] isEmpty in
+                self?.bindPhoneNumberButton.isEnabled = isEmpty
+            }).disposed(by: self.disposeBag)
+    }
+}

+ 106 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PasswordLogin/ViewController/PasswordLoginViewController.swift

@@ -0,0 +1,106 @@
+//
+//  PasswordLoginViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/27.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+import RxCocoa
+
+class PasswordLoginViewController: BaseViewController {
+
+    @IBOutlet weak var phoneAreaCodeButton: UIButton!
+
+    @IBOutlet weak var phoneNumberTextField: UITextField!
+
+    @IBOutlet weak var passwordField: UITextField!
+
+    @IBOutlet weak var passwordLoginPhoneButton: UIButton!
+
+
+    /// 手机号
+    var phoneNumber : String = ""
+
+    ///
+    var password : String = ""
+
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        MobClick.beginLogPageView("PasswordLoginViewController:手机密码登录")
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        MobClick.endLogPageView("PasswordLoginViewController:手机密码登录")
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupViews()
+    }
+
+    override func setupViews() {
+
+        navigationBar.wr_setRightButton(title: "验证码登录", titleColor: k333333Color)
+        navigationBar.onClickRightButton = { [weak self] in
+            self?.present(VerificationPhoneViewController(), animated: true, completion: {
+
+            })
+        }
+        
+        passwordLoginPhoneButton.setTitleColor(kffffffColor, for: UIControl.State.normal)
+        passwordLoginPhoneButton.setTitleColor(k666666Color, for: UIControl.State.disabled)
+        passwordLoginPhoneButton.setBackgroundImage(UIImage.imageWithColor(color: kDisabledButtonColor), for: UIControl.State.disabled)
+        passwordLoginPhoneButton.setBackgroundImage(UIImage.imageWithColor(color: kEnabledButtonColor), for: UIControl.State.normal)
+        passwordLoginPhoneButton.titleLabel?.font = kRegularFont18
+        passwordLoginPhoneButton.cornerRadius = 22
+        passwordLoginPhoneButton.masksToBounds = true
+        passwordLoginPhoneButton.isEnabled = false
+
+        phoneNumberTextField.rx.text.changed.subscribe(onNext: { [weak self] (text) in
+            self?.phoneNumberTextField.text = String(text?.prefix(11) ?? "") as String
+            self?.phoneNumber = self?.phoneNumberTextField.text ?? ""
+            self?.observableString()
+        }).disposed(by: disposeBag)
+
+        passwordField.rx.text.changed.subscribe(onNext: { [weak self] (text) in
+            self?.passwordField.text = String(text?.prefix(6) ?? "") as String
+            self?.password = self?.passwordField.text ?? ""
+            self?.observableString()
+        }).disposed(by: disposeBag)
+    }
+
+    func observableString() {
+        Observable.combineLatest(Observable.just(phoneNumber), Observable.just(password)) { (textValue1, textValue2) -> Bool in
+            let textValue1 = String(textValue1.prefix(11)) as String
+            let textValue2 = String(textValue2.prefix(6)) as String
+            let isSuccess = (textValue1.count == 11) && (textValue2.count == 6)
+            return isSuccess
+            }.subscribe(onNext: {
+                [weak self] isEmpty in
+                self?.passwordLoginPhoneButton.isEnabled = isEmpty
+            }).disposed(by: self.disposeBag)
+    }
+
+    @IBAction func phoneAreaCodeAction(_ sender: UIButton) {
+        let vc = PhoneCountryAreaViewController()
+        vc.phoneCountryAreaVCCloSure = { [weak self] (phoneCountryAreaMdoel:PhoneCountryAreaMdoel) in
+            self?.phoneAreaCodeButton.setTitle(phoneCountryAreaMdoel.countryCode, for: UIControl.State.normal)
+        }
+        self.present(vc, animated: true) {
+
+        }
+    }
+
+    /// 登录
+    @IBAction  func verificationPhoneNumberAction() {
+        SwiftProgressHUD.shared().showText("手机号绑定成功")
+
+        self.dismissToRootViewController(animated: true) {
+        }
+    }
+
+}

+ 132 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PasswordLogin/ViewController/PasswordLoginViewController.xib

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PasswordLoginViewController" customModule="RainbowPlanet" customModuleProvider="target">
+            <connections>
+                <outlet property="passwordField" destination="Rnr-8g-3v3" id="yq7-oN-KpK"/>
+                <outlet property="passwordLoginPhoneButton" destination="h0N-yi-WZR" id="AH6-31-QKN"/>
+                <outlet property="phoneAreaCodeButton" destination="OQA-ID-bcU" id="OfC-DA-09c"/>
+                <outlet property="phoneNumberTextField" destination="MDi-IA-MsI" id="C5h-fC-yp0"/>
+                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="手机密码登录" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GbB-x9-TI1">
+                    <rect key="frame" x="40" y="174" width="134" height="26.5"/>
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OQA-ID-bcU">
+                    <rect key="frame" x="40" y="255.5" width="30" height="23"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="23" id="LZV-4G-O6h"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                    <state key="normal" title="+86">
+                        <color key="titleColor" red="0.1529239714" green="0.1529521942" blue="0.15291777249999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </state>
+                    <connections>
+                        <action selector="phoneAreaCodeAction:" destination="-1" eventType="touchUpInside" id="bsi-lt-2t3"/>
+                    </connections>
+                </button>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AXC-eT-swR">
+                    <rect key="frame" x="74" y="256" width="9" height="22"/>
+                    <state key="normal" image="navigaitionbar_back_black"/>
+                </button>
+                <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="手机号" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="MDi-IA-MsI">
+                    <rect key="frame" x="96" y="257" width="278" height="20"/>
+                    <constraints>
+                        <constraint firstAttribute="width" relation="greaterThanOrEqual" id="bg6-oq-PrE"/>
+                    </constraints>
+                    <nil key="textColor"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                    <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
+                </textField>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="exQ-CF-oWP">
+                    <rect key="frame" x="38" y="287" width="338" height="1"/>
+                    <color key="backgroundColor" red="0.96070033310000003" green="0.96083813910000004" blue="0.96067017320000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="1" id="lih-lw-uxO"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="请输入密码" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="Rnr-8g-3v3">
+                    <rect key="frame" x="40" y="301" width="332" height="30"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="30" id="pMg-Cq-a8e"/>
+                    </constraints>
+                    <nil key="textColor"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                    <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
+                </textField>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aWg-xg-QGQ">
+                    <rect key="frame" x="38" y="341" width="338" height="1"/>
+                    <color key="backgroundColor" red="0.96070033310000003" green="0.96083813910000004" blue="0.96067017320000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="1" id="hew-BM-VMD"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="h0N-yi-WZR">
+                    <rect key="frame" x="38" y="377" width="338" height="44"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="44" id="aib-bd-jwC"/>
+                    </constraints>
+                    <state key="normal" title="登录"/>
+                    <state key="disabled" title="登录">
+                        <color key="titleColor" red="0.4078049064" green="0.4078676403" blue="0.40779113769999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </state>
+                    <connections>
+                        <action selector="verificationPhoneNumberAction" destination="-1" eventType="touchUpInside" id="zc0-b1-kb8"/>
+                    </connections>
+                </button>
+            </subviews>
+            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <constraints>
+                <constraint firstItem="h0N-yi-WZR" firstAttribute="trailing" secondItem="aWg-xg-QGQ" secondAttribute="trailing" id="1jZ-Qm-yVi"/>
+                <constraint firstItem="aWg-xg-QGQ" firstAttribute="top" secondItem="Rnr-8g-3v3" secondAttribute="bottom" constant="10" id="778-qx-cZ4"/>
+                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Rnr-8g-3v3" secondAttribute="trailing" constant="42" id="94g-Kl-QCN"/>
+                <constraint firstItem="h0N-yi-WZR" firstAttribute="top" secondItem="aWg-xg-QGQ" secondAttribute="bottom" constant="35" id="E4f-A0-WrM"/>
+                <constraint firstItem="Rnr-8g-3v3" firstAttribute="top" secondItem="exQ-CF-oWP" secondAttribute="bottom" constant="13" id="EaJ-o6-C8O"/>
+                <constraint firstItem="h0N-yi-WZR" firstAttribute="leading" secondItem="aWg-xg-QGQ" secondAttribute="leading" id="Noq-H2-q2f"/>
+                <constraint firstItem="AXC-eT-swR" firstAttribute="leading" secondItem="OQA-ID-bcU" secondAttribute="trailing" constant="4" id="Q1l-fI-vx0"/>
+                <constraint firstItem="Rnr-8g-3v3" firstAttribute="leading" secondItem="OQA-ID-bcU" secondAttribute="leading" id="S6D-Vw-1Hc"/>
+                <constraint firstItem="aWg-xg-QGQ" firstAttribute="trailing" secondItem="exQ-CF-oWP" secondAttribute="trailing" id="Sh8-kU-lSZ"/>
+                <constraint firstItem="MDi-IA-MsI" firstAttribute="centerY" secondItem="OQA-ID-bcU" secondAttribute="centerY" id="TL8-Uf-Kcd"/>
+                <constraint firstItem="AXC-eT-swR" firstAttribute="centerY" secondItem="OQA-ID-bcU" secondAttribute="centerY" id="ViO-so-Whh"/>
+                <constraint firstItem="exQ-CF-oWP" firstAttribute="trailing" secondItem="MDi-IA-MsI" secondAttribute="trailing" constant="2" id="bJG-lm-gVN"/>
+                <constraint firstItem="exQ-CF-oWP" firstAttribute="top" secondItem="MDi-IA-MsI" secondAttribute="bottom" constant="10" id="cFX-e1-XH7"/>
+                <constraint firstItem="GbB-x9-TI1" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="130" id="eVF-IZ-Ild"/>
+                <constraint firstItem="aWg-xg-QGQ" firstAttribute="leading" secondItem="exQ-CF-oWP" secondAttribute="leading" id="ei7-KZ-tpz"/>
+                <constraint firstItem="OQA-ID-bcU" firstAttribute="top" secondItem="GbB-x9-TI1" secondAttribute="bottom" constant="55" id="gVG-EI-lBG"/>
+                <constraint firstItem="exQ-CF-oWP" firstAttribute="leading" secondItem="OQA-ID-bcU" secondAttribute="leading" constant="-2" id="lG3-vP-aeb"/>
+                <constraint firstAttribute="trailing" secondItem="exQ-CF-oWP" secondAttribute="trailing" constant="38" id="lbF-Oa-ubT"/>
+                <constraint firstItem="GbB-x9-TI1" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="40" id="qjN-sk-EPu"/>
+                <constraint firstItem="OQA-ID-bcU" firstAttribute="leading" secondItem="GbB-x9-TI1" secondAttribute="leading" id="r9K-a9-49y"/>
+                <constraint firstItem="MDi-IA-MsI" firstAttribute="leading" secondItem="AXC-eT-swR" secondAttribute="trailing" constant="13" id="uTH-r9-h3y"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="navigaitionbar_back_black" width="9" height="17"/>
+    </resources>
+</document>

+ 128 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/Model/PhoneCountryAreaListMdoel.swift

@@ -0,0 +1,128 @@
+//
+//	PhoneCountryAreaListMdoel.swift
+//	Model file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
+
+import Foundation 
+import SwiftyJSON
+
+
+class PhoneCountryAreaListMdoel : NSObject, NSCoding{
+
+	var countrys : [PhoneCountryAreaMdoel]!
+
+
+	/**
+	 * Instantiate the instance using the passed json values to set the properties values
+	 */
+	init(fromJson json: JSON!){
+		if json.isEmpty{
+			return
+		}
+		countrys = [PhoneCountryAreaMdoel]()
+		let countrysArray = json["countrys"].arrayValue
+		for countrysJson in countrysArray{
+			let value = PhoneCountryAreaMdoel(fromJson: countrysJson)
+			countrys.append(value)
+		}
+	}
+
+	/**
+	 * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
+	 */
+	func toDictionary() -> [String:Any]
+	{
+		var dictionary = [String:Any]()
+		if countrys != nil{
+			var dictionaryElements = [[String:Any]]()
+			for countrysElement in countrys {
+				dictionaryElements.append(countrysElement.toDictionary())
+			}
+			dictionary["countrys"] = dictionaryElements
+		}
+		return dictionary
+	}
+
+    /**
+    * NSCoding required initializer.
+    * Fills the data from the passed decoder
+    */
+    @objc required init(coder aDecoder: NSCoder)
+	{
+         countrys = aDecoder.decodeObject(forKey: "countrys") as? [PhoneCountryAreaMdoel]
+
+	}
+
+    /**
+    * NSCoding required method.
+    * Encodes mode properties into the decoder
+    */
+    func encode(with aCoder: NSCoder)
+	{
+		if countrys != nil{
+			aCoder.encode(countrys, forKey: "countrys")
+		}
+
+	}
+
+}
+
+class PhoneCountryAreaMdoel : NSObject, NSCoding{
+
+    var country : String!
+    var countryCode : String!
+
+
+    /**
+     * Instantiate the instance using the passed json values to set the properties values
+     */
+    init(fromJson json: JSON!){
+        if json.isEmpty{
+            return
+        }
+        country = json["country"].stringValue
+        countryCode = json["countryCode"].stringValue
+    }
+
+    /**
+     * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
+     */
+    func toDictionary() -> [String:Any]
+    {
+        var dictionary = [String:Any]()
+        if country != nil{
+            dictionary["country"] = country
+        }
+        if countryCode != nil{
+            dictionary["countryCode"] = countryCode
+        }
+        return dictionary
+    }
+
+    /**
+     * NSCoding required initializer.
+     * Fills the data from the passed decoder
+     */
+    @objc required init(coder aDecoder: NSCoder)
+    {
+        country = aDecoder.decodeObject(forKey: "country") as? String
+        countryCode = aDecoder.decodeObject(forKey: "countryCode") as? String
+
+    }
+
+    /**
+     * NSCoding required method.
+     * Encodes mode properties into the decoder
+     */
+    func encode(with aCoder: NSCoder)
+    {
+        if country != nil{
+            aCoder.encode(country, forKey: "country")
+        }
+        if countryCode != nil{
+            aCoder.encode(countryCode, forKey: "countryCode")
+        }
+
+    }
+
+}
+

+ 30 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/View/PhoneCountryAreaSectionHeaderView.swift

@@ -0,0 +1,30 @@
+//
+//  PhoneCountryAreaSectionHeaderView.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/23.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class PhoneCountryAreaSectionHeaderView: BaseView {
+    override func setupViews() {
+        super.setupViews()
+        addSubview(titleLabel)
+    }
+    override func setupLayouts() {
+        titleLabel.snp.makeConstraints { (make) in
+            make.centerY.equalToSuperview()
+            make.left.equalToSuperview().offset(20)
+        }
+    }
+
+    private lazy var titleLabel: UILabel = {
+        let titleLabel = UILabel()
+        titleLabel.text = "选择国家和地区"
+        titleLabel.textColor = k333333Color
+        titleLabel.font = kBoldFont22
+        return titleLabel
+    }()
+}

+ 13 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/View/PhoneCountryAreaSectionView.swift

@@ -0,0 +1,13 @@
+//
+//  PhoneCountryAreaSectionView.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/23.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class PhoneCountryAreaSectionHeaderView: UIView {
+
+}

+ 102 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/View/PhoneCountryAreaTableViewCell.swift

@@ -0,0 +1,102 @@
+//
+//  PhoneCountryAreaTableViewCell.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/23.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class PhoneCountryAreaTableViewCell: UITableViewCell {
+
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        // Initialization code
+    }
+
+    override func setSelected(_ selected: Bool, animated: Bool) {
+        super.setSelected(selected, animated: animated)
+
+        // Configure the view for the selected state
+    }
+
+    class func cellWith(tableView:UITableView,indexPath:IndexPath) -> PhoneCountryAreaTableViewCell {
+        let ID = "PhoneCountryAreaTableViewCell"
+        tableView.register(PhoneCountryAreaTableViewCell.self, forCellReuseIdentifier: ID)
+        let cell : PhoneCountryAreaTableViewCell = tableView.dequeueReusableCell(withIdentifier: ID, for: indexPath) as! PhoneCountryAreaTableViewCell
+        cell.indexPath = indexPath
+        return cell
+    }
+
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        setupViews()
+        setupLayouts()
+    }
+
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    //MRAK: - 设置View
+    private func setupViews() {
+        self.selectionStyle = .none
+        addSubview(countryLabel)
+        addSubview(countryCodeLabel)
+        addSubview(lineLabel)
+    }
+
+    private func setupLayouts() {
+        countryLabel.snp.makeConstraints { (make) in
+            make.centerY.equalToSuperview()
+            make.left.equalTo(20)
+        }
+        countryCodeLabel.snp.makeConstraints { (make) in
+            make.centerY.equalToSuperview()
+            make.right.equalTo(-20)
+        }
+        lineLabel.snp.makeConstraints { (make) in
+            make.bottom.equalToSuperview()
+            make.right.equalTo(-16)
+            make.left.equalTo(16)
+            make.height.equalTo(1)
+        }
+    }
+
+    private lazy var countryLabel: UILabel = {
+        let countryLabel = UILabel()
+        countryLabel.textColor = k333333Color
+        countryLabel.font = kRegularFont18
+        return countryLabel
+    }()
+
+    private lazy var countryCodeLabel: UILabel = {
+        let countryCodeLabel = UILabel()
+        countryCodeLabel.textColor = k333333Color
+        countryCodeLabel.font = kRegularFont18
+        return countryCodeLabel
+    }()
+
+    private lazy var lineLabel: UILabel = {
+        let lineLabel = UILabel()
+        lineLabel.backgroundColor = ke6e6e6Color
+        lineLabel.font = kRegularFont18
+        return lineLabel
+    }()
+
+    var indexPath: IndexPath? {
+        didSet {
+
+        }
+    }
+
+    var phoneCountryAreaMdoel : PhoneCountryAreaMdoel? {
+        didSet {
+            self.countryLabel.text = phoneCountryAreaMdoel?.country ?? ""
+            self.countryCodeLabel.text = phoneCountryAreaMdoel?.countryCode ?? ""
+        }
+    }
+
+
+}

Разлика између датотеке није приказан због своје велике величине
+ 105 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/PhoneCountryArea/ViewController/PhoneCountryAreaViewController.swift


+ 72 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/RegisterLogin/View/RegisterLoginView.swift

@@ -0,0 +1,72 @@
+//
+//  RegisterLoginView.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/4/16.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class RegisterLoginView: BaseView {
+
+    typealias WeiXinLoginBlock = () -> Void
+    var weiXinLoginBlock : WeiXinLoginBlock?
+
+    override func setupViews() {
+        addSubview(iconImageView)
+        addSubview(weiXinLoginButton)
+        addSubview(phoneNumberLoginButton)
+    }
+
+    override func setupLayouts() {
+        iconImageView.snp.makeConstraints { (make) in
+            make.top.equalToSuperview().offset(96 + kNavBarTotalHeight)
+            make.centerX.equalToSuperview()
+        }
+        weiXinLoginButton.snp.makeConstraints { (make) in
+            make.top.equalTo(iconImageView.snp.bottom).offset(70)
+            make.left.equalToSuperview().offset(38)
+            make.right.equalToSuperview().offset(-38)
+            make.height.equalTo(44)
+        }
+        phoneNumberLoginButton.snp.makeConstraints { (make) in
+            make.top.equalTo(weiXinLoginButton.snp.bottom).offset(14)
+            make.right.equalTo(weiXinLoginButton)
+        }
+        phoneNumberLoginButton.layoutButton(edgeInsetsStyle: ButtonEdgeInsetsStyle.right, imageTitleSpace: 4)
+    }
+
+
+    private lazy var iconImageView: UIImageView = {
+        let iconImageView = UIImageView()
+        iconImageView.image = kImage(name: "icon")
+        return iconImageView
+    }()
+
+    private lazy var weiXinLoginButton: UIButton = {
+        let weiXinLoginButton = UIButton(type: UIButton.ButtonType.custom)
+        weiXinLoginButton.setTitle("微信一键登录", for: UIControl.State.normal)
+        weiXinLoginButton.titleLabel?.font = kRegularFont17
+        weiXinLoginButton.setBackgroundImage(UIImage.imageWithColor(color: kEnabledButtonColor), for: UIControl.State.normal)
+        weiXinLoginButton.setTitleColor(kEnabledTitleColor, for: UIControl.State.normal)
+        weiXinLoginButton.layer.cornerRadius = 22
+        weiXinLoginButton.layer.masksToBounds = true
+        weiXinLoginButton.rx.tap.subscribe(onNext: { [weak self] in
+            if let weiXinLoginBlock = self?.weiXinLoginBlock {
+                weiXinLoginBlock()
+            }
+        }).disposed(by: disposeBag)
+        return weiXinLoginButton
+    }()
+
+    private lazy var phoneNumberLoginButton: UIButton = {
+        let phoneNumberLoginButton = UIButton(type: UIButton.ButtonType.custom)
+        phoneNumberLoginButton.setTitle("使用用手机登录", for: UIControl.State.normal)
+        phoneNumberLoginButton.titleLabel?.font = kRegularFont13
+        phoneNumberLoginButton.setImage(UIImage(named: "navigaitionbar_back_blue"), for: UIControl.State.normal)
+        phoneNumberLoginButton.setTitleColor(k666666Color, for: UIControl.State.normal)
+        return phoneNumberLoginButton
+    }()
+
+}

+ 51 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/RegisterLogin/ViewController/RegisterLoginViewController.swift

@@ -0,0 +1,51 @@
+//
+//  RegisterLoginViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/22.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class RegisterLoginViewController: BaseViewController {
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupViews()
+        setupLayouts()
+    }
+
+    override func setupViews() {
+        view.backgroundColor = UIColor.white
+        navigationBar.wr_setLeftButton(title: "", titleColor: UIColor.clear)
+        navigationBar.onClickLeftButton = nil
+        view.addSubview(registerLoginView)
+    }
+
+    override func setupLayouts() {
+        registerLoginView.snp.makeConstraints { (make) in
+            make.edges.equalToSuperview()
+        }
+    }
+
+    private lazy var registerLoginView: RegisterLoginView = {
+        let registerLoginView = RegisterLoginView()
+        registerLoginView.weiXinLoginBlock = { [weak self] in
+            UMManager.shared().loginGetUserInfo(platformType: UMSocialPlatformType.wechatSession) { (loginModel) -> (Void) in
+                SwiftMoyaNetWorkServiceUser.shared().userWeiXinRegisterApi(open_id: loginModel.open_id, union_id: loginModel.union_id, avatar: loginModel.avatar, username: loginModel.username, gender: loginModel.gender, completion: { (data) -> (Void) in
+                    if self?.presentingViewController != nil {
+                        self?.dismiss(animated: true, completion: {
+                            kAppDelegate.setTabbarController()
+                        })
+                    } else {
+                        kAppDelegate.setTabbarController()
+                    }
+
+                })
+            }
+        }
+        return registerLoginView
+    }()
+
+}

+ 132 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/VerificationPhone/ViewController/VerificationPhoneViewController.swift

@@ -0,0 +1,132 @@
+//
+//  VerificationPhoneViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/27.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+import RxCocoa
+
+class VerificationPhoneViewController: BaseViewController {
+
+    @IBOutlet weak var phoneAreaCodeButton: UIButton!
+
+    @IBOutlet weak var smsButton: CountdownButton!
+
+    @IBOutlet weak var verificationPhoneButton: UIButton!
+
+    @IBOutlet weak var phoneNumberTextField: UITextField!
+
+    @IBOutlet weak var smsTextField: UITextField!
+
+    /// 手机号
+    var phoneNumber : String = ""
+
+    ///
+    var sms : String = ""
+
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        MobClick.beginLogPageView("VerificationPhoneViewController:验证手机页面")
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        MobClick.endLogPageView("VerificationPhoneViewController:验证手机页面")
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupViews()
+    }
+
+    override func setupViews() {
+
+        navigationBar.wr_setRightButton(title: "手机密码登录", titleColor: k333333Color)
+        navigationBar.onClickRightButton = {[weak self] in
+            self?.present(PasswordLoginViewController(), animated: true, completion: {
+                
+            })
+        }
+
+        smsButton.normalText = "  获取验证码  "
+        smsButton.disabledText = "  seconds后重新获取  "
+        smsButton.setTitle(smsButton.normalText, for: UIControl.State.normal)
+        smsButton.setTitle(smsButton.disabledText, for: UIControl.State.disabled)
+        smsButton.setTitleColor(kED3934Color, for: UIControl.State.normal)
+        smsButton.setTitleColor(k333333Color, for: UIControl.State.disabled)
+        smsButton.titleLabel?.font = kRegularFont12
+        smsButton.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.center
+        smsButton.sizeToFit()
+        smsButton.normalBorderColor = kED3934Color
+        smsButton.normalBorderWidth = 0.5
+        smsButton.normalCornerRadius = 15
+        smsButton.normalBackgroundColor = UIColor.white
+        smsButton.disabledBorderColor = ke6e6e6Color
+        smsButton.disabledBorderWidth = 0.5
+        smsButton.disabledCornerRadius = 15
+        smsButton.disabledBackgroundColor = ke6e6e6Color
+        smsButton.maxSecond = 60
+        smsButton.updateNormal()
+
+        verificationPhoneButton.setTitleColor(kffffffColor, for: UIControl.State.normal)
+        verificationPhoneButton.setTitleColor(k666666Color, for: UIControl.State.disabled)
+        verificationPhoneButton.setBackgroundImage(UIImage.imageWithColor(color: kDisabledButtonColor), for: UIControl.State.disabled)
+        verificationPhoneButton.setBackgroundImage(UIImage.imageWithColor(color: kEnabledButtonColor), for: UIControl.State.normal)
+        verificationPhoneButton.titleLabel?.font = kRegularFont18
+        verificationPhoneButton.cornerRadius = 22
+        verificationPhoneButton.masksToBounds = true
+        verificationPhoneButton.isEnabled = false
+
+        phoneNumberTextField.rx.text.changed.subscribe(onNext: { [weak self] (text) in
+            self?.phoneNumberTextField.text = String(text?.prefix(11) ?? "") as String
+            self?.phoneNumber = self?.phoneNumberTextField.text ?? ""
+            self?.observableString()
+        }).disposed(by: disposeBag)
+
+        smsTextField.rx.text.changed.subscribe(onNext: { [weak self] (text) in
+            self?.smsTextField.text = String(text?.prefix(6) ?? "") as String
+            self?.sms = self?.smsTextField.text ?? ""
+            self?.observableString()
+        }).disposed(by: disposeBag)
+    }
+
+    func observableString() {
+        Observable.combineLatest(Observable.just(phoneNumber), Observable.just(sms)) { (textValue1, textValue2) -> Bool in
+            let textValue1 = String(textValue1.prefix(11)) as String
+            let textValue2 = String(textValue2.prefix(6)) as String
+            let isSuccess = (textValue1.count == 11) && (textValue2.count == 6)
+            return isSuccess
+            }.subscribe(onNext: {
+                [weak self] isEmpty in
+                self?.verificationPhoneButton.isEnabled = isEmpty
+            }).disposed(by: self.disposeBag)
+    }
+
+
+    @IBAction func phoneAreaCodeAction(_ sender: UIButton) {
+        let vc = PhoneCountryAreaViewController()
+        vc.phoneCountryAreaVCCloSure = { [weak self] (phoneCountryAreaMdoel:PhoneCountryAreaMdoel) in
+            self?.phoneAreaCodeButton.setTitle(phoneCountryAreaMdoel.countryCode, for: UIControl.State.normal)
+        }
+        self.present(vc, animated: true) {
+
+        }
+    }
+
+    @IBAction func smsAction(_ sender: CountdownButton) {
+        smsButton.countdown = true
+    }
+
+    /// 立即验证
+    @IBAction  func verificationPhoneNumberAction() {
+
+        self.dismissToRootViewController(animated: true) {
+
+        }
+    }
+
+}

+ 160 - 0
RainbowPlanet/RainbowPlanet/Modules/RegisterLoginModule/VerificationPhone/ViewController/VerificationPhoneViewController.xib

@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="VerificationPhoneViewController" customModule="RainbowPlanet" customModuleProvider="target">
+            <connections>
+                <outlet property="phoneAreaCodeButton" destination="IOo-UT-Wma" id="DqP-7u-scX"/>
+                <outlet property="phoneNumberTextField" destination="hok-U6-Jpp" id="xPM-cW-2ET"/>
+                <outlet property="smsButton" destination="3hc-O5-000" id="aeh-ze-CuL"/>
+                <outlet property="smsTextField" destination="4bp-Bn-Pg2" id="Nan-o3-2rd"/>
+                <outlet property="verificationPhoneButton" destination="gwS-rH-oAP" id="9Pz-40-bzD"/>
+                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="验证手机" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RVj-0q-UUy">
+                    <rect key="frame" x="40" y="164" width="89.5" height="26.5"/>
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="为了账号安全,请验证手机" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CWG-xW-WkB">
+                    <rect key="frame" x="40" y="196.5" width="138.5" height="14.5"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                    <color key="textColor" red="0.52544218301773071" green="0.52552098035812378" blue="0.52542495727539062" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IOo-UT-Wma">
+                    <rect key="frame" x="40" y="254" width="30" height="23"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="23" id="KeH-GN-gZa"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                    <state key="normal" title="+86">
+                        <color key="titleColor" red="0.15292397141456604" green="0.15295219421386719" blue="0.1529177725315094" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </state>
+                    <connections>
+                        <action selector="phoneAreaCodeAction:" destination="-1" eventType="touchUpInside" id="5Dr-bU-k3T"/>
+                    </connections>
+                </button>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pqj-XU-gBa">
+                    <rect key="frame" x="74" y="254.5" width="9" height="22"/>
+                    <state key="normal" image="navigaitionbar_back_black"/>
+                    <connections>
+                        <action selector="phoneAreaCodeAction:" destination="-1" eventType="touchUpInside" id="z3d-bP-hH4"/>
+                    </connections>
+                </button>
+                <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="手机号" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hok-U6-Jpp">
+                    <rect key="frame" x="96" y="255.5" width="280" height="20"/>
+                    <constraints>
+                        <constraint firstAttribute="width" relation="greaterThanOrEqual" id="LQm-b8-Gks"/>
+                    </constraints>
+                    <nil key="textColor"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                    <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
+                </textField>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6ZA-jb-dcL">
+                    <rect key="frame" x="38" y="285.5" width="340" height="1"/>
+                    <color key="backgroundColor" red="0.96070033311843872" green="0.96083813905715942" blue="0.96067017316818237" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="1" id="rmF-nQ-4ra"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3hc-O5-000" customClass="CountdownButton" customModule="RainbowPlanet" customModuleProvider="target">
+                    <rect key="frame" x="280" y="299.5" width="92" height="30"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="30" id="fbN-gR-CKn"/>
+                        <constraint firstAttribute="width" relation="greaterThanOrEqual" id="xIQ-4L-d3G"/>
+                    </constraints>
+                    <state key="normal" title="获取验证码">
+                        <color key="titleColor" red="0.94900625944137573" green="0.42618435621261597" blue="0.41407948732376099" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </state>
+                    <connections>
+                        <action selector="smsAction:" destination="-1" eventType="touchUpInside" id="SKh-eq-YyC"/>
+                    </connections>
+                </button>
+                <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="验证码" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="4bp-Bn-Pg2">
+                    <rect key="frame" x="40" y="299.5" width="230" height="30"/>
+                    <nil key="textColor"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                    <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
+                </textField>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="baU-2G-k7g">
+                    <rect key="frame" x="38" y="339.5" width="340" height="1"/>
+                    <color key="backgroundColor" red="0.96070033310000003" green="0.96083813910000004" blue="0.96067017320000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="1" id="l1O-Wr-e3D"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gwS-rH-oAP">
+                    <rect key="frame" x="38" y="375.5" width="340" height="44"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="44" id="PKv-Lc-VaO"/>
+                    </constraints>
+                    <state key="normal" title="立即验证">
+                        <color key="titleColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </state>
+                    <state key="disabled" title="立即验证">
+                        <color key="titleColor" red="0.40780490636825562" green="0.40786764025688171" blue="0.4077911376953125" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </state>
+                    <connections>
+                        <action selector="verificationPhoneNumberAction" destination="-1" eventType="touchUpInside" id="gUg-Rk-GL6"/>
+                    </connections>
+                </button>
+            </subviews>
+            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <constraints>
+                <constraint firstItem="gwS-rH-oAP" firstAttribute="trailing" secondItem="baU-2G-k7g" secondAttribute="trailing" id="0cg-I6-XTh"/>
+                <constraint firstItem="baU-2G-k7g" firstAttribute="leading" secondItem="6ZA-jb-dcL" secondAttribute="leading" id="0nt-qu-Qwb"/>
+                <constraint firstItem="4bp-Bn-Pg2" firstAttribute="centerY" secondItem="3hc-O5-000" secondAttribute="centerY" id="2xX-cw-F5R"/>
+                <constraint firstItem="gwS-rH-oAP" firstAttribute="leading" secondItem="baU-2G-k7g" secondAttribute="leading" id="6R7-UO-qWT"/>
+                <constraint firstItem="IOo-UT-Wma" firstAttribute="top" secondItem="CWG-xW-WkB" secondAttribute="bottom" constant="43" id="7qV-La-yWE"/>
+                <constraint firstItem="IOo-UT-Wma" firstAttribute="leading" secondItem="CWG-xW-WkB" secondAttribute="leading" id="8UG-A8-rWc"/>
+                <constraint firstItem="RVj-0q-UUy" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="40" id="8by-Jk-bHB"/>
+                <constraint firstItem="pqj-XU-gBa" firstAttribute="leading" secondItem="IOo-UT-Wma" secondAttribute="trailing" constant="4" id="Ayn-Fx-82Q"/>
+                <constraint firstItem="baU-2G-k7g" firstAttribute="top" secondItem="3hc-O5-000" secondAttribute="bottom" constant="10" id="EoG-qx-mPV"/>
+                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="3hc-O5-000" secondAttribute="trailing" constant="42" id="IOf-bJ-uQU"/>
+                <constraint firstItem="CWG-xW-WkB" firstAttribute="leading" secondItem="RVj-0q-UUy" secondAttribute="leading" id="ORj-bn-i8M"/>
+                <constraint firstItem="hok-U6-Jpp" firstAttribute="centerY" secondItem="IOo-UT-Wma" secondAttribute="centerY" id="S6A-zY-CIb"/>
+                <constraint firstItem="6ZA-jb-dcL" firstAttribute="leading" secondItem="IOo-UT-Wma" secondAttribute="leading" constant="-2" id="WZ1-MZ-u2s"/>
+                <constraint firstItem="hok-U6-Jpp" firstAttribute="leading" secondItem="pqj-XU-gBa" secondAttribute="trailing" constant="13" id="X84-L3-iPS"/>
+                <constraint firstItem="baU-2G-k7g" firstAttribute="trailing" secondItem="6ZA-jb-dcL" secondAttribute="trailing" id="azb-Qd-CQu"/>
+                <constraint firstItem="6ZA-jb-dcL" firstAttribute="top" secondItem="hok-U6-Jpp" secondAttribute="bottom" constant="10" id="bEa-Ce-A7m"/>
+                <constraint firstItem="4bp-Bn-Pg2" firstAttribute="height" secondItem="3hc-O5-000" secondAttribute="height" id="eHb-mv-uMb"/>
+                <constraint firstItem="gwS-rH-oAP" firstAttribute="top" secondItem="baU-2G-k7g" secondAttribute="bottom" constant="35" id="fCl-it-zlI"/>
+                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="hok-U6-Jpp" secondAttribute="trailing" constant="38" id="fGk-ro-dz3"/>
+                <constraint firstItem="pqj-XU-gBa" firstAttribute="centerY" secondItem="IOo-UT-Wma" secondAttribute="centerY" id="hg4-hm-Q8E"/>
+                <constraint firstItem="CWG-xW-WkB" firstAttribute="top" secondItem="RVj-0q-UUy" secondAttribute="bottom" constant="6" id="im9-YW-sRV"/>
+                <constraint firstItem="RVj-0q-UUy" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="120" id="n0M-J5-xrN"/>
+                <constraint firstItem="6ZA-jb-dcL" firstAttribute="trailing" secondItem="hok-U6-Jpp" secondAttribute="trailing" constant="2" id="rVw-ZK-91G"/>
+                <constraint firstItem="3hc-O5-000" firstAttribute="leading" secondItem="4bp-Bn-Pg2" secondAttribute="trailing" constant="10" id="vQy-sH-Z0j"/>
+                <constraint firstItem="3hc-O5-000" firstAttribute="top" secondItem="6ZA-jb-dcL" secondAttribute="bottom" constant="13" id="xA5-W9-EQv"/>
+                <constraint firstItem="4bp-Bn-Pg2" firstAttribute="leading" secondItem="IOo-UT-Wma" secondAttribute="leading" id="zUo-Wo-gk2"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
+            <point key="canvasLocation" x="147.82608695652175" y="35.491071428571423"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="navigaitionbar_back_black" width="9" height="17"/>
+    </resources>
+</document>

+ 29 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingCartModule/ShoppingCart/ViewController/ShoppingCartViewController.swift

@@ -0,0 +1,29 @@
+//
+//  ShoppingCartViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/7.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class ShoppingCartViewController: BaseViewController {
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        // Do any additional setup after loading the view.
+    }
+
+    /*
+    // MARK: - Navigation
+
+    // In a storyboard-based application, you will often want to do a little preparation before navigation
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        // Get the new view controller using segue.destination.
+        // Pass the selected object to the new view controller.
+    }
+    */
+
+}

+ 36 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingCartModule/ShoppingCart/ViewController/ShoppingCartViewController.xib

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ShoppingCartViewController" customModule="RainbowPlanet" customModuleProvider="target">
+            <connections>
+                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="6MV-62-dMb">
+                    <rect key="frame" x="128" y="179" width="97" height="30"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                    <nil key="textColor"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                    <textInputTraits key="textInputTraits"/>
+                </textField>
+            </subviews>
+            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
+            <point key="canvasLocation" x="-14" y="54"/>
+        </view>
+    </objects>
+</document>

+ 174 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/ShoppingMallNavigationBarView.swift

@@ -0,0 +1,174 @@
+//
+//  ShoppingMallNavigationBarView.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/12.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import RxSwift
+import RxCocoa
+class ShoppingMallNavigationBarView: BaseView {
+
+
+    /// 头像
+    typealias AvatarActionBlock = () -> Void
+    var avatarActionBlock : AvatarActionBlock?
+
+    /// 地址
+    typealias AddressActionBlock = () -> Void
+    var addressActionBlock : AddressActionBlock?
+
+    /// 搜索
+    typealias SearchActionBlock = () -> Void
+    var searchActionBlock : SearchActionBlock?
+
+    /// 搜索
+    typealias MessageActionBlock = () -> Void
+    var messageActionBlock : MessageActionBlock?
+
+
+    override func setupViews() {
+        backgroundColor = .white
+        addSubview(avatarButton)
+        addSubview(addressButton)
+        addressButton.addSubview(addressLabel)
+        addressButton.addSubview(goImageView)
+        addSubview(searchButton)
+        addSubview(messageButton)
+        searchButton.addSubview(searchIconImageView)
+        searchButton.addSubview(searchTitleLabel)
+
+    }
+
+    override func setupLayouts() {
+        avatarButton.snp.makeConstraints { (make) in
+            make.top.equalToSuperview().offset(kSafeStatusBarHeight)
+            make.leading.equalToSuperview().offset(10)
+            make.size.equalTo(20)
+        }
+        addressButton.snp.makeConstraints { (make) in
+            make.top.bottom.equalTo(avatarButton)
+            make.left.equalTo(avatarButton.snp.right).offset(5)
+            make.right.equalToSuperview()
+        }
+        addressLabel.snp.makeConstraints { (make) in
+            make.centerY.equalToSuperview()
+            make.left.equalToSuperview()
+            make.width.lessThanOrEqualTo(kScreenWidth-65)
+        }
+        goImageView.snp.makeConstraints { (make) in
+            make.left.equalTo(addressLabel.snp.right).offset(5)
+            make.centerY.equalToSuperview()
+            make.size.equalTo(15)
+        }
+        searchButton.snp.makeConstraints { (make) in
+            make.left.equalTo(avatarButton)
+            make.bottom.equalToSuperview().offset(-2)
+            make.width.equalTo(kScreenWidth-45)
+            make.top.equalTo(goImageView.snp.bottom).offset(2)
+        }
+
+        searchIconImageView.snp.makeConstraints { (make) in
+            make.left.equalToSuperview().offset(10)
+            make.size.equalTo(10)
+            make.centerY.equalToSuperview()
+        }
+
+        searchTitleLabel.snp.makeConstraints { (make) in
+            make.left.equalTo(searchIconImageView.snp.right).offset(5)
+            make.right.equalToSuperview().offset(-5)
+            make.centerY.equalToSuperview()
+        }
+
+        messageButton.snp.makeConstraints { (make) in
+            make.right.equalToSuperview().offset(-10)
+            make.centerY.equalTo(searchButton)
+            make.size.equalTo(15)
+        }
+
+
+    }
+
+    private lazy var avatarButton: UIButton = {
+        let avatarButton = UIButton(type: .custom)
+        avatarButton.setImage(kImage(name: "shop"), for: UIControl.State.normal)
+        avatarButton.rx.tap.subscribe(onNext: {
+            [weak self] in
+            if let avatarActionBlock = self?.avatarActionBlock {
+                avatarActionBlock()
+            }
+        }).disposed(by: disposeBag)
+        return avatarButton
+    }()
+
+    private lazy var addressButton: UIButton = {
+        let addressButton = UIButton(type: .custom)
+        addressButton.rx.tap.subscribe(onNext: {
+            [weak self] in
+            if let addressActionBlock = self?.addressActionBlock {
+                addressActionBlock()
+            }
+        }).disposed(by: disposeBag)
+        return addressButton
+    }()
+
+    private lazy var addressLabel: UILabel = {
+        let addressLabel = UILabel()
+        addressLabel.textColor = UIColor.black
+        addressLabel.font = kMediumFont14
+        addressLabel.lineBreakMode = .byTruncatingTail
+        addressLabel.numberOfLines = 1
+        addressLabel.text = "正在定位"
+        return addressLabel
+    }()
+
+    private lazy var goImageView: UIImageView = {
+        let goImageView = UIImageView(image: kImage(name: "shop"))
+        return goImageView
+    }()
+
+    private lazy var messageButton: UIButton = {
+        let messageButton = UIButton(type: .custom)
+        messageButton.setImage(kImage(name: "shop"), for: UIControl.State.normal)
+        messageButton.rx.tap.subscribe(onNext: {
+            [weak self] in
+            if let messageActionBlock = self?.messageActionBlock {
+                messageActionBlock()
+            }
+        }).disposed(by: disposeBag)
+        return messageButton
+    }()
+
+    private lazy var searchButton: UIButton = {
+        let searchButton = UIButton(type: .custom)
+        searchButton.layer.borderColor = UIColor.lightGray.cgColor
+        searchButton.layer.borderWidth = 1
+        searchButton.layer.cornerRadius = 12
+        searchButton.layer.masksToBounds = true
+        searchButton.rx.tap.subscribe(onNext: {
+            [weak self] in
+            if let searchActionBlock = self?.searchActionBlock {
+                searchActionBlock()
+            }
+        }).disposed(by: disposeBag)
+        return searchButton
+    }()
+
+    private lazy var searchIconImageView: UIImageView = {
+        let searchIconImageView = UIImageView(image: kImage(name: "navigaitionbar_back_blue"))
+        return searchIconImageView
+    }()
+
+    private lazy var searchTitleLabel: UILabel = {
+        let searchTitleLabel = UILabel()
+        searchTitleLabel.textColor = UIColor.black
+        searchTitleLabel.font = kMediumFont14
+        searchTitleLabel.lineBreakMode = .byTruncatingTail
+        searchTitleLabel.numberOfLines = 1
+        searchTitleLabel.text = "搜索商品"
+        return searchTitleLabel
+    }()
+
+}

+ 259 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/ShoppingMallView.swift

@@ -0,0 +1,259 @@
+//
+//  ShoppingMallView.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/12.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+let verticalListCategoryViewHeight = 30;   //悬浮categoryView的高度
+let verticalListPinSectionIndex = 1;    //悬浮固定section的index
+
+class ShoppingMallView: BaseView {
+
+
+    typealias CategoryActionBlock = () -> Void
+    var categoryActionBlock : CategoryActionBlock?
+
+    var dataSource = Array<VerticalListSectionModel>()
+
+    var sectionHeaderAttributes = Array<UICollectionViewLayoutAttributes>()
+
+    let headerTitles = ["我的频道", "超级大IP", "热门HOT", "周边衍生", "影视综", "游戏集锦", "搞笑百事"];
+    var imageNames = ["boat", "crab", "lobster", "apple", "carrot", "grape", "watermelon"];
+
+    override func setupViews() {
+        super.setupViews()
+        for (index, title) in headerTitles.enumerated() {
+            let sectionModel = VerticalListSectionModel()
+            sectionModel.sectionTitle = title
+            let randomCount = arc4random()%10 + 5
+            var cellModels = Array<VerticalListCellModel>()
+
+            for _ in 0..<randomCount {
+                let cellModel = VerticalListCellModel()
+                cellModel.imageName = imageNames[index]
+                cellModel.itemName = title
+                cellModels.append(cellModel)
+            }
+            sectionModel.cellModels = cellModels
+            dataSource.append(sectionModel)
+        }
+        addSubview(categoryButton)
+        addSubview(pinCategoryView)
+        addSubview(allCollectionView)
+
+
+    }
+
+
+
+    override func setupLayouts() {
+        categoryButton.snp.makeConstraints { (make) in
+            make.top.equalToSuperview().offset(2)
+            make.right.equalToSuperview().offset(-10)
+            make.size.equalTo(30)
+        }
+        pinCategoryView.snp.makeConstraints { (make) in
+            make.top.equalToSuperview().offset(2)
+            make.right.equalTo(categoryButton.snp.left)
+            make.left.equalToSuperview().offset(10)
+            make.height.equalTo(30)
+        }
+        allCollectionView.snp.makeConstraints { (make) in
+            make.top.equalTo(pinCategoryView.snp.bottom)
+            make.left.right.bottom.equalToSuperview()
+        }
+
+    }
+
+
+    private lazy var categoryButton: UIButton = {
+        let categoryButton = UIButton(type: UIButton.ButtonType.custom)
+        categoryButton.setImage(kImage(name: "shop"), for: UIControl.State.normal)
+        categoryButton.rx.tap.subscribe(onNext: {
+            [weak self] in
+            if let categoryActionBlock = self?.categoryActionBlock {
+                categoryActionBlock()
+            }
+        }).disposed(by: disposeBag)
+        return categoryButton
+    }()
+
+    private lazy var pinCategoryView: JXCategoryTitleView = {
+        let pinCategoryView = JXCategoryTitleView()
+        pinCategoryView.backgroundColor = UIColor.white
+        pinCategoryView.titles = headerTitles
+        pinCategoryView.titleColorGradientEnabled = true
+        pinCategoryView.titleLabelZoomEnabled = true
+        pinCategoryView.titleLabelZoomScale = 1.2
+        let lineView = JXCategoryIndicatorLineView()
+        lineView.lineStyle = .lengthen
+        pinCategoryView.indicators = [lineView];
+        pinCategoryView.delegate = self
+        return pinCategoryView
+    }()
+
+    private lazy var categoryCollectionViewLayout: UICollectionViewFlowLayout = {
+        let categoryCollectionViewLayout = UICollectionViewFlowLayout.init()
+        categoryCollectionViewLayout.scrollDirection = UICollectionView.ScrollDirection.horizontal
+        categoryCollectionViewLayout.estimatedItemSize = CGSize(width: (kScreenWidth-50)/5, height:30)
+        return categoryCollectionViewLayout
+    }()
+
+    private lazy var allCollectionView: UICollectionView = {
+        let allCollectionView = UICollectionView.init(frame: CGRect.zero, collectionViewLayout: allCollectionViewLayout)
+        allCollectionView.backgroundColor = UIColor.white;
+        allCollectionView.delegate = self;
+        allCollectionView.dataSource = self;
+        return allCollectionView
+    }()
+
+    private lazy var allCollectionViewLayout: UICollectionViewFlowLayout = {
+        let allCollectionViewLayout = UICollectionViewFlowLayout.init()
+        allCollectionViewLayout.scrollDirection = UICollectionView.ScrollDirection.vertical
+        //分组头悬停
+//        allCollectionViewLayout.sectionHeadersPinToVisibleBounds = true
+        allCollectionViewLayout.itemSize = CGSize(width: kScreenWidth, height:30)
+        return allCollectionViewLayout
+    }()
+
+}
+
+extension ShoppingMallView : UICollectionViewDelegate,UICollectionViewDataSource {
+
+    func numberOfSections(in collectionView: UICollectionView) -> Int {
+        return dataSource.count
+    }
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return self.dataSource[section].cellModels!.count;
+    }
+
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        let cell = VerticalListCellCollectionViewCell.cellWith(collectionView: collectionView, indexPath: indexPath)
+        let sectionModel = dataSource[indexPath.section]
+        let cellModel: VerticalListCellModel? = sectionModel.cellModels![indexPath.row]
+        cell.itemImageView.image = UIImage(named: cellModel?.imageName ?? "")
+        cell.titleLabel.text = cellModel?.itemName
+        return cell
+    }
+
+    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+
+    }
+
+    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
+        if kind == UICollectionView.elementKindSectionHeader {
+
+            let headerView = VerticalSectionHeaderView.headerWith(collectionView: collectionView, kind:  UICollectionView.elementKindSectionHeader, indexPath: indexPath)
+            let sectionModel = dataSource[indexPath.section]
+            headerView.titleLabel.text = sectionModel.sectionTitle
+            return headerView
+        }
+        return UICollectionReusableView()
+    }
+
+     // 标记一下 CollectionView 的滚动方向,是向上还是向下
+    func scrollViewDidScroll(_ scrollView: UIScrollView) {
+
+        if sectionHeaderAttributes.count <= 0 {
+            var attributes: [AnyHashable] = []
+            var lastHeaderAttri: UICollectionViewLayoutAttributes? = nil
+            for i in 0..<headerTitles.count {
+                let attri: UICollectionViewLayoutAttributes? = allCollectionView.collectionViewLayout.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(item: 0, section: i))
+                if let attri = attri {
+                    attributes.append(attri)
+                }
+                if i == headerTitles.count - 1 {
+                    lastHeaderAttri = attri
+                }
+            }
+            sectionHeaderAttributes = attributes as! [UICollectionViewLayoutAttributes]
+
+            //如果最后一个section条目太少了,会导致滚动最底部,但是却不能触发categoryView选中最后一个item。而且点击最后一个滚动的contentOffset.y也不要弄。所以添加contentInset,让最后一个section滚到最下面能显示完整个屏幕,
+
+            let lastCellAttri: UICollectionViewLayoutAttributes? = allCollectionView.collectionViewLayout.layoutAttributesForItem(at: IndexPath(item: (dataSource[headerTitles.count - 1]).cellModels!.count - 1, section: headerTitles.count - 1))
+            let lastSectionHeight: CGFloat = (lastCellAttri?.frame.maxY)! - (lastHeaderAttri?.frame.minY)!
+
+            let value = CGFloat(bounds.size.height - CGFloat(verticalListCategoryViewHeight)) - lastSectionHeight
+            if value > 0 {
+                allCollectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: value, right: 0)
+            }
+        }
+
+
+        if (!(scrollView.isTracking || scrollView.isDecelerating)) {
+            //不是用户滚动的,比如setContentOffset等方法,引起的滚动不需要处理。
+            return;
+        }
+
+        //用户滚动的才处理
+        //获取categoryView下面一点的所有布局信息,用于知道,当前最上方是显示的哪个section
+        let topRect = CGRect(x: 0, y: scrollView.contentOffset.y + 1, width: bounds.size.width, height: 1)
+        let topAttributes: UICollectionViewLayoutAttributes? = allCollectionView.collectionViewLayout.layoutAttributesForElements(in: topRect)?.first
+        let topSection: Int? = topAttributes?.indexPath.section
+        if topAttributes != nil && topSection! >= 0 {
+            if pinCategoryView.selectedIndex != topSection! {
+                //不相同才切换
+                pinCategoryView.selectItem(at: topSection!)
+            }
+        }
+    }
+}
+
+extension ShoppingMallView:UICollectionViewDelegateFlowLayout {
+
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
+        return CGSize(width: self.bounds.size.width, height: 40)
+    }
+
+
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
+        return CGSize(width: 100, height: 100)
+    }
+
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
+        return 10
+    }
+
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
+        return (self.bounds.size.width - 100 * 3) / 4
+    }
+
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
+        let margin: CGFloat = (self.bounds.size.width - 100 * 3) / 4
+        return UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
+    }
+
+}
+
+
+extension ShoppingMallView: JXCategoryViewDelegate{
+
+    func categoryView(_ categoryView: JXCategoryBaseView!, didClickSelectedItemAt index: Int) {
+        self.collectionViewScrollToTop(section: index, animated: true)
+    }
+
+    //将右侧colletionView的指定分区自动滚动到最顶端
+    func collectionViewScrollToTop(section: Int, animated: Bool) {
+        let headerRect = collectionViewHeaderFrame(section: section)
+        let topOfHeader = CGPoint(x: 0, y: headerRect.origin.y
+            - allCollectionView.contentInset.top)
+        allCollectionView.setContentOffset(topOfHeader, animated: animated)
+    }
+
+    //后获colletionView的指定分区头的高度
+    func collectionViewHeaderFrame(section: Int) -> CGRect {
+        let indexPath = IndexPath(item: 0, section: section)
+        let attributes = allCollectionView.collectionViewLayout
+            .layoutAttributesForSupplementaryView(ofKind:
+                UICollectionView.elementKindSectionHeader, at: indexPath)
+        guard let frameForFirstCell = attributes?.frame else {
+            return .zero
+        }
+        return frameForFirstCell;
+    }
+
+}

+ 62 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalListCellCollectionViewCell.swift

@@ -0,0 +1,62 @@
+//
+//  VerticalListCellCollectionViewCell.swift
+//  Test
+//
+//  Created by 南鑫林 on 2019/3/13.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class VerticalListCellCollectionViewCell: UICollectionViewCell {
+    class func cellWith(collectionView:UICollectionView,indexPath:IndexPath) -> VerticalListCellCollectionViewCell {
+        let ID = "VerticalListCellCollectionViewCell"
+        collectionView.register(VerticalListCellCollectionViewCell.self, forCellWithReuseIdentifier: ID)
+        let cell : VerticalListCellCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: ID, for: indexPath) as! VerticalListCellCollectionViewCell
+        cell.indexPath = indexPath
+        return cell
+    }
+    //MARK: - indexPath
+    var indexPath: IndexPath?{
+        didSet {
+
+        }
+    }
+    //MARK: - 初始化
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        setupViews()
+    }
+
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    //MARK: - 设置view
+    private func setupViews() {
+        contentView.backgroundColor = UIColor.white
+        contentView.layer.cornerRadius = 10
+        contentView.addSubview(titleLabel)
+        contentView.addSubview(itemImageView)
+    }
+
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        self.itemImageView.bounds = CGRect(x: 0, y: 0, width: 50, height: 50)
+        self.itemImageView.center = CGPoint(x: self.bounds.size.width/2, y: 30)
+
+        self.titleLabel.frame = CGRect(x: 0, y: itemImageView.frame.maxY + 5, width:  self.bounds.size.width, height: 30)
+    }
+
+    lazy var titleLabel: UILabel = {
+        let titleLabel = UILabel()
+        titleLabel.textAlignment = .center
+        return titleLabel
+    }()
+
+    lazy var itemImageView: UIImageView = {
+        let itemImageView = UIImageView()
+        return itemImageView
+    }()
+
+}

+ 14 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalListCellModel.swift

@@ -0,0 +1,14 @@
+//
+//  VerticalListCellModel.swift
+//  Test
+//
+//  Created by 南鑫林 on 2019/3/13.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class VerticalListCellModel: NSObject {
+    var imageName : String?
+    var itemName : String?
+}

+ 14 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalListSectionModel.swift

@@ -0,0 +1,14 @@
+//
+//  VerticalListSectionModel.swift
+//  Test
+//
+//  Created by 南鑫林 on 2019/3/13.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class VerticalListSectionModel: NSObject {
+    var sectionTitle : String?
+    var cellModels : Array<VerticalListCellModel>?
+}

+ 55 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/View/VerticalSectionHeaderView.swift

@@ -0,0 +1,55 @@
+//
+//  VerticalSectionHeaderView.swift
+//  Test
+//
+//  Created by 南鑫林 on 2019/3/13.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class VerticalSectionHeaderView: UICollectionReusableView {
+    class func headerWith(collectionView:UICollectionView,kind: String,indexPath: IndexPath) -> VerticalSectionHeaderView {
+        let ID = "VerticalSectionHeaderView"
+        collectionView.register(VerticalSectionHeaderView.self, forSupplementaryViewOfKind: kind, withReuseIdentifier: ID)
+        let headerView : VerticalSectionHeaderView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: ID, for: indexPath) as! VerticalSectionHeaderView
+        headerView.indexPath = indexPath
+        return headerView
+    }
+
+    var indexPath : IndexPath? {
+        didSet {
+
+        }
+    }
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        setupViews()
+    }
+
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    //MARK: - 设置View
+    private func setupViews() {
+        backgroundColor = UIColor(red: 0.94, green: 0.94, blue: 0.94, alpha: 1)
+
+        addSubview(titleLabel)
+    }
+
+    override func layoutSubviews() {
+        super.layoutSubviews()
+
+        titleLabel.sizeToFit()
+        titleLabel.frame = CGRect(x: 16, y: (bounds.size.height - (titleLabel.bounds.size.height)) / 2, width: 200, height: titleLabel.bounds.size.height)
+    }
+
+    lazy var titleLabel: UILabel = {
+        let titleLabel = UILabel()
+        titleLabel.textColor = UIColor.lightGray
+        titleLabel.font = UIFont.systemFont(ofSize: 15)
+        return titleLabel
+    }()
+
+}

+ 89 - 0
RainbowPlanet/RainbowPlanet/Modules/ShoppingMallModule/ShoppingMall/ViewController/ShoppingMallViewController.swift

@@ -0,0 +1,89 @@
+//
+//  ShoppingMallViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/7.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class ShoppingMallViewController: BaseViewController {
+
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        MobClick.beginLogPageView("ShoppingMallViewController:商城页面")
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        MobClick.endLogPageView("ShoppingMallViewController:商城页面")
+    }
+
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupViews()
+        setupLayouts()
+    }
+
+    override func setupViews() {
+        super.setupViews()
+        navigationBar.addSubview(navigationBarView)
+        view.addSubview(shoppingMallView)
+    }
+
+    override func setupLayouts() {
+        navigationBarView.snp.makeConstraints { (make) in
+            make.edges.equalToSuperview()
+        }
+        shoppingMallView.snp.makeConstraints { (make) in
+            make.bottom.left.right.equalToSuperview()
+            make.top.equalTo(navigationBarView.snp.bottom)
+        }
+    }
+
+    private lazy var navigationBarView: ShoppingMallNavigationBarView = {
+        let navigationBarView = ShoppingMallNavigationBarView()
+        /// 头像
+        navigationBarView.avatarActionBlock = {
+            SwiftMoyaNetWorkServiceUser.shared().userLogoutApi()
+        }
+        /// 地址
+        navigationBarView.addressActionBlock = {
+            SwiftMoyaNetWorkServicePay.shared().payAlipayApi(completion: { (data) -> (Void) in
+                PayManager.shared().alipay(orderString: data as! String, successPayBlock: {
+
+                }, failPayBlock: {
+
+                })
+            })
+        }
+        /// 搜索列表
+        navigationBarView.searchActionBlock = {
+            SwiftMoyaNetWorkServicePay.shared().payWeixinpayApi(completion: { (data) -> (Void) in
+                PayManager.shared().weixinpay(wechatpayOrderModel: data as! WeChatpayOrderModel, successPayBlock: {
+
+                }, failPayBlock: {
+
+                })
+            })
+        }
+        /// 消息
+        navigationBarView.messageActionBlock = {
+            self.present(RegisterLoginViewController(), animated: true, completion: nil)
+        }
+        return navigationBarView
+    }()
+
+    private lazy var shoppingMallView: ShoppingMallView = {
+         let shoppingMallView = ShoppingMallView()
+        /// 分类
+        shoppingMallView.categoryActionBlock = {
+
+        }
+        return shoppingMallView
+    }()
+
+}
+

+ 8 - 0
RainbowPlanet/RainbowPlanet/RainbowPlanet.entitlements

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>aps-environment</key>
+	<string>development</string>
+</dict>
+</plist>

+ 54 - 0
RainbowPlanet/RainbowPlanet/Service/Model/RootModel/InfoModel.swift

@@ -0,0 +1,54 @@
+//
+//	InfoModel.swift
+//	Model file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
+
+import Foundation 
+import ObjectMapper
+
+
+class InfoModel : NSObject, NSCoding, Mappable{
+
+    var message : String?
+	var code : Int?
+
+
+	class func newInstance(map: Map) -> Mappable?{
+		return InfoModel()
+	}
+	required init?(map: Map){}
+	private override init(){}
+
+	func mapping(map: Map)
+	{
+		message <- map["message"]
+		code <- map["code"]
+		
+	}
+
+    /**
+    * NSCoding required initializer.
+    * Fills the data from the passed decoder
+    */
+    @objc required init(coder aDecoder: NSCoder)
+	{
+         message = aDecoder.decodeObject(forKey: "message") as? String
+         code = aDecoder.decodeObject(forKey: "code") as? Int
+
+	}
+
+    /**
+    * NSCoding required method.
+    * Encodes mode properties into the decoder
+    */
+    @objc func encode(with aCoder: NSCoder)
+	{
+		if message != nil{
+			aCoder.encode(message, forKey: "message")
+		}
+		if code != nil{
+			aCoder.encode(code, forKey: "code")
+		}
+
+	}
+
+}

+ 78 - 0
RainbowPlanet/RainbowPlanet/Service/Model/RootModel/PaginationModel.swift

@@ -0,0 +1,78 @@
+//
+//	PaginationModel.swift
+//	Model file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
+
+import Foundation 
+import ObjectMapper
+
+
+class PaginationModel : NSObject, NSCoding, Mappable{
+
+	var count : Int?
+	var currentPage : Int?
+	var links : [AnyObject]?
+	var perPage : Int?
+	var total : Int?
+	var totalPages : Int?
+
+
+	class func newInstance(map: Map) -> Mappable?{
+		return PaginationModel()
+	}
+	required init?(map: Map){}
+	private override init(){}
+
+	func mapping(map: Map)
+	{
+		count <- map["count"]
+		currentPage <- map["current_page"]
+		links <- map["links"]
+		perPage <- map["per_page"]
+		total <- map["total"]
+		totalPages <- map["total_pages"]
+		
+	}
+
+    /**
+    * NSCoding required initializer.
+    * Fills the data from the passed decoder
+    */
+    @objc required init(coder aDecoder: NSCoder)
+	{
+         count = aDecoder.decodeObject(forKey: "count") as? Int
+         currentPage = aDecoder.decodeObject(forKey: "current_page") as? Int
+         links = aDecoder.decodeObject(forKey: "links") as? [AnyObject]
+         perPage = aDecoder.decodeObject(forKey: "per_page") as? Int
+         total = aDecoder.decodeObject(forKey: "total") as? Int
+         totalPages = aDecoder.decodeObject(forKey: "total_pages") as? Int
+
+	}
+
+    /**
+    * NSCoding required method.
+    * Encodes mode properties into the decoder
+    */
+    @objc func encode(with aCoder: NSCoder)
+	{
+		if count != nil{
+			aCoder.encode(count, forKey: "count")
+		}
+		if currentPage != nil{
+			aCoder.encode(currentPage, forKey: "current_page")
+		}
+		if links != nil{
+			aCoder.encode(links, forKey: "links")
+		}
+		if perPage != nil{
+			aCoder.encode(perPage, forKey: "per_page")
+		}
+		if total != nil{
+			aCoder.encode(total, forKey: "total")
+		}
+		if totalPages != nil{
+			aCoder.encode(totalPages, forKey: "total_pages")
+		}
+
+	}
+
+}

+ 63 - 0
RainbowPlanet/RainbowPlanet/Service/Model/RootModel/RootModel.swift

@@ -0,0 +1,63 @@
+//
+//    RootModel.swift
+//    Model file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
+
+import Foundation
+import ObjectMapper
+import SwiftyJSON
+
+
+class RootModel : NSObject, NSCoding, Mappable{
+
+    // 0成功,1失败
+    var code : Int?
+    /// #数据载体,单条数据,直接获取。
+    var data : String?
+    /// 提示信息
+    var msg : String?
+
+    class func newInstance(map: Map) -> Mappable?{
+        return RootModel()
+    }
+    required init?(map: Map){}
+    private override init(){}
+
+    func mapping(map: Map)
+    {
+        code <- map["code"]
+        data <- map["data"]
+        msg <- map["msg"]
+
+    }
+
+    /**
+     * NSCoding required initializer.
+     * Fills the data from the passed decoder
+     */
+    @objc required init(coder aDecoder: NSCoder)
+    {
+        code = aDecoder.decodeObject(forKey: "code") as? Int
+        data = aDecoder.decodeObject(forKey: "data") as? String
+        msg = aDecoder.decodeObject(forKey: "msg") as? String
+
+    }
+
+    /**
+     * NSCoding required method.
+     * Encodes mode properties into the decoder
+     */
+    @objc func encode(with aCoder: NSCoder)
+    {
+        if code != nil{
+            aCoder.encode(code, forKey: "code")
+        }
+        if data != nil{
+            aCoder.encode(data, forKey: "data")
+        }
+        if msg != nil{
+            aCoder.encode(msg, forKey: "msg")
+        }
+
+    }
+
+}

+ 128 - 0
RainbowPlanet/RainbowPlanet/Service/Model/UserModel/LoginModel.swift

@@ -0,0 +1,128 @@
+//
+//	LoginModel.swift
+//	Model file generated using JSONExport: https://github.com/Ahmed-Ali/JSONExport
+
+import Foundation 
+import ObjectMapper
+
+
+class LoginModel : NSObject, NSCoding, Mappable{
+
+    private static let _sharedInstance = LoginModel()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> LoginModel {
+        return _sharedInstance
+    }
+
+    var uid : Int?
+    var username : String?
+	var accessToken : String?
+	var avatarurl : String?
+	var gender : Int?
+	var mobile : String?
+	var token : String?
+	var tokenTtl : Int?
+
+
+	class func newInstance(map: Map) -> Mappable?{
+		return LoginModel()
+	}
+	required init?(map: Map){}
+
+	func mapping(map: Map)
+	{
+        uid <- map["uid"]
+        username <- map["username"]
+		accessToken <- map["access_token"]
+		avatarurl <- map["avatarurl"]
+		gender <- map["gender"]
+		mobile <- map["mobile"]
+		token <- map["token"]
+		tokenTtl <- map["token_ttl"]
+		
+	}
+
+    /**
+    * NSCoding required initializer.
+    * Fills the data from the passed decoder
+    */
+    @objc required init(coder aDecoder: NSCoder)
+	{
+         uid = aDecoder.decodeObject(forKey: "uid") as? Int
+         username = aDecoder.decodeObject(forKey: "username") as? String
+         accessToken = aDecoder.decodeObject(forKey: "access_token") as? String
+         avatarurl = aDecoder.decodeObject(forKey: "avatarurl") as? String
+         gender = aDecoder.decodeObject(forKey: "gender") as? Int
+         mobile = aDecoder.decodeObject(forKey: "mobile") as? String
+         token = aDecoder.decodeObject(forKey: "token") as? String
+         tokenTtl = aDecoder.decodeObject(forKey: "token_ttl") as? Int
+
+	}
+
+    /**
+    * NSCoding required method.
+    * Encodes mode properties into the decoder
+    */
+    @objc func encode(with aCoder: NSCoder)
+	{
+        if uid != nil{
+            aCoder.encode(uid, forKey: "uid")
+        }
+        if username != nil{
+            aCoder.encode(uid, forKey: "username")
+        }
+		if accessToken != nil{
+			aCoder.encode(accessToken, forKey: "access_token")
+		}
+		if avatarurl != nil{
+			aCoder.encode(avatarurl, forKey: "avatarurl")
+		}
+		if gender != nil{
+			aCoder.encode(gender, forKey: "gender")
+		}
+		if mobile != nil{
+			aCoder.encode(mobile, forKey: "mobile")
+		}
+		if token != nil{
+			aCoder.encode(token, forKey: "token")
+		}
+		if tokenTtl != nil{
+			aCoder.encode(tokenTtl, forKey: "token_ttl")
+		}
+
+	}
+
+    /// 存储个人信息
+    ///
+    /// - Parameter locationModel: 定位模型
+    func setLoginModel(loginModel:LoginModel) -> Void {
+        //实例对象转换成Data
+        let modelData = NSKeyedArchiver.archivedData(withRootObject: loginModel)
+        //存储Data对象
+        UserDefaults.standard.set(modelData, forKey: "LoginModel")
+        NXLLog("LoginModel存储成功")
+    }
+
+
+    /// 获取个人信息
+    ///
+    /// - Returns: 定位模型
+    func getLoginModel() -> LoginModel? {
+        //自定义对象读取
+        let modelData = UserDefaults.standard.data(forKey: "LoginModel")
+        var model = LoginModel()
+        if modelData != nil {
+            model = NSKeyedUnarchiver.unarchiveObject(with: modelData!) as! LoginModel
+            NXLLog("LoginModel读取成功")
+        }
+        return model
+    }
+
+    /// 移除个人信息
+    func removeLoginModel() {
+        UserDefaults.standard.removeObject(forKey: "LoginModel")
+    }
+
+}

+ 83 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaNetWorkManager/ApiMacro.swift

@@ -0,0 +1,83 @@
+//
+//  ApiMacro.swift
+//  CreaditPayment
+//
+//  Created by 南鑫林 on 2018/7/28.
+//  Copyright © 2018年 南鑫林. All rights reserved.
+//
+
+import Foundation
+
+let kDevelopSever = true
+let kTestSever = false
+let kProductSever = false
+
+// MARK: - 数据服务器
+public func kApiDataPrefix() -> String {
+    if kDevelopSever /** 接口前缀-开发服务器*/ {
+        return "https://api.dev.caihongxingqiu.com"
+    } else if kTestSever /** 接口前缀-测试服务器*/{
+        return ""
+    }else if kProductSever /** 接口前缀-生产服务器*/ {
+        return ""
+    }else {
+        return ""
+    }
+}
+// MARK: - 图片服务器
+public let kApiPicPrefix = ""
+
+
+/// 头部类型
+///
+/// - defaultHeader: 默认
+/// - moreHeader: 更多
+/// - tokenHeader: 带token的头部
+/// - tokenMoreHeader: 带更多,token的头部
+public enum HeaderType {
+    case defaultHeader
+    case moreHeader
+    case tokenHeader
+    case tokenMoreHeader
+}
+
+public func headerParameters(headerType:HeaderType = .defaultHeader) -> Dictionary<String,Any> {
+    var parameters = Dictionary<String,Any>()
+
+    switch headerType {
+    case .defaultHeader:
+        parameters.updateValue("application/x-www-form-urlencoded", forKey: "Content-Type")
+        break
+    case .moreHeader:
+        parameters.updateValue("application/x-www-form-urlencoded", forKey: "Content-Type")
+        parameters.updateValue(AppInfo.vendor, forKey: "vendor")
+        parameters.updateValue(AppInfo.client_name, forKey: "client_name")
+        parameters.updateValue(AppInfo.client_version, forKey: "client_version")
+        parameters.updateValue(AppInfo.os_name, forKey: "os_name")
+        parameters.updateValue(AppInfo.os_version, forKey: "os_version")
+        parameters.updateValue(String(describing: AppInfo.device_name), forKey: "device_name")
+        parameters.updateValue(AppInfo.uuid, forKey: "device_id")
+        parameters.updateValue(AppInfo.ipAddress, forKey: "ip")
+        break
+    case .tokenHeader:
+        parameters.updateValue("application/x-www-form-urlencoded", forKey: "Content-Type")
+        let token = LoginModel.shared().getLoginModel()?.token ?? ""
+        parameters.updateValue(token, forKey: "Authorization")
+        break
+    case .tokenMoreHeader:
+        parameters.updateValue("application/x-www-form-urlencoded", forKey: "Content-Type")
+        parameters.updateValue(AppInfo.vendor, forKey: "vendor")
+        parameters.updateValue(AppInfo.client_name, forKey: "client_name")
+        parameters.updateValue(AppInfo.client_version, forKey: "client_version")
+        parameters.updateValue(AppInfo.os_name, forKey: "os_name")
+        parameters.updateValue(AppInfo.os_version, forKey: "os_version")
+        parameters.updateValue(String(describing: AppInfo.device_name), forKey: "device_name")
+        parameters.updateValue(AppInfo.uuid, forKey: "device_id")
+        parameters.updateValue(AppInfo.ipAddress, forKey: "ip")
+        let token = LoginModel.shared().getLoginModel()?.token ?? ""
+        parameters.updateValue(token, forKey: "Authorization")
+        break
+    }
+
+    return parameters
+}

+ 392 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaNetWorkManager/SwiftMoyaNetWorkManager.swift

@@ -0,0 +1,392 @@
+//
+//  SwiftMoyaNetWorkManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2018/8/7.
+//  Copyright © 2018年 南鑫林. All rights reserved.
+//
+
+import Foundation
+import Alamofire
+import Moya
+import SwiftyJSON
+import ObjectMapper
+import RxSwift
+import RxCocoa
+import MoyaMapper
+import Result
+
+/// 超时时长
+private var requestTimeOut:Double = 20
+
+///网络请求的基本设置,这里可以拿到是具体的哪个网络请求,可以在这里做一些设置
+private let myEndpointClosure = { (target: MultiTarget) -> Endpoint in
+    ///这里把endpoint重新构造一遍主要为了解决网络请求地址里面含有? 时无法解析的bug https://github.com/Moya/Moya/issues/1198
+    let url = target.baseURL.absoluteString + target.path
+    var task = target.task
+    /*
+     👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆
+     如果需要在每个请求中都添加类似token参数的参数请取消注释上面代码
+     */
+    var endpoint = Endpoint(
+        url: url,
+        sampleResponseClosure: { .networkResponse(200, target.sampleData) },
+        method: target.method,
+        task: task,
+        httpHeaderFields: target.headers
+    )
+    requestTimeOut = 20//每次请求都会调用endpointClosure 到这里设置超时时长 也可单独每个接口设置
+    
+    return endpoint
+}
+
+///网络请求的设置
+private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
+    do {
+        var request = try endpoint.urlRequest()
+        //设置请求时长
+        request.timeoutInterval = requestTimeOut
+        // 打印请求参数
+        if let requestData = request.httpBody {
+            NXLLog("\n"+"请求地址:"+"\(request.url!)"+"\n"+"请求方式:"+"\(request.httpMethod ?? "")"+"\n"+"请求头部:"+"\(String(describing: request.allHTTPHeaderFields!))"+"\n"+"发送参数:"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
+        }else{
+            NXLLog("\n"+"请求地址:"+"\(request.url!)"+"\n"+"请求方式:"+"=\(String(describing: request.httpMethod!))"+"请求头部:"+"\(String(describing: request.allHTTPHeaderFields!))")
+        }
+        done(.success(request))
+    } catch {
+        done(.failure(MoyaError.underlying(error, nil)))
+    }
+}
+
+/// NetworkActivityPlugin插件用来监听网络请求,界面上做相应的展示
+///但这里我没怎么用这个。。。 loading的逻辑直接放在网络处理里面了
+private let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in
+    print("networkPlugin \(changeType)")
+    //targetType 是当前请求的基本信息
+    switch(changeType){
+    case .began:
+        DispatchQueue.main.async(execute: { () -> Void in
+            UIApplication.shared.isNetworkActivityIndicatorVisible = true
+        })
+    case .ended:
+        DispatchQueue.main.async(execute: { () -> Void in
+            UIApplication.shared.isNetworkActivityIndicatorVisible = false
+        })
+    }
+    
+}
+
+
+private let provider = MoyaProvider<MultiTarget>(endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)
+
+/// 基于Alamofire,网络是否连接,,这个方法不建议放到这个类中,可以放在全局的工具类中判断网络链接情况
+/// 用get方法是因为这样才会在获取isNetworkConnect时实时判断网络链接请求,如有更好的方法可以fork
+private var isNetworkConnect: Bool {
+    get{
+        let network = NetworkReachabilityManager()
+        return network?.isReachable ?? true //无返回就默认网络已连接
+    }
+}
+
+
+public class SwiftMoyaNetWorkManager: NSObject {
+
+    private let disposeBag = DisposeBag()
+    private var dataBaseName : String = "RainbowPlanet"
+
+
+    private static let _sharedInstance = SwiftMoyaNetWorkManager()
+    private override init() {} // 私有化init方法
+    /// 获取单例
+    ///
+    /// - Returns: SwiftMoyaNetWorkManager对象
+    class func shared() -> SwiftMoyaNetWorkManager {
+        return _sharedInstance
+    }
+
+    /// 成功回调
+    typealias successCallback = (_ data: Any) -> Void
+    /// 成功回调带泛型
+    typealias successCallTBack = (_ T: BaseMappable) -> Void
+
+    typealias falseCallback = () -> Void
+    var falseCallback : falseCallback?
+
+    /// 网络请求
+    ///
+    /// - Parameters:
+    ///   - type: 模型
+    ///   - target: 请求地址加参数
+    ///   - isCache: 是否缓存
+    ///   - completion: <#completion description#>
+    func request<T: BaseMappable>(_ type: T.Type,target: MultiTarget,completion: @escaping successCallTBack) -> Void {
+        //判断是否链接网络
+        if !isNetworkConnect{
+             SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            return
+        }
+
+        provider.rx
+            .request(target)
+            .map(T.self)
+            .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
+            .observeOn(MainScheduler.instance)
+            .subscribe(onSuccess: { [weak self] element in
+
+                guard let element = element else {
+                    if let falseCallback = self?.falseCallback  {
+                        falseCallback()
+                    }
+                    return
+                }
+                completion(element)
+            }) {
+                [weak self] (error) in
+                if let falseCallback = self?.falseCallback  {
+                    falseCallback()
+                }
+                SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            }
+            .disposed(by: disposeBag)
+    }
+
+    /// 缓存请求
+    ///
+    /// - Parameters:
+    ///   - target: 请求地址加参数
+    ///   - alwaysFetchCache: 是否总是缓存
+    ///   - cacheType: 缓存类型
+    ///   - completion: 请求成功回调
+    func cacheRequest<T: BaseMappable>(_ type: T.Type,target: MultiTarget,alwaysFetchCache: Bool = false,cacheType: MMCache.CacheKeyType = .default,completion: @escaping successCallback) -> Void {
+
+        //判断是否链接网络
+        if !isNetworkConnect{
+            SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            return
+        }
+
+        var cacheResponse: Response? = nil
+
+        if alwaysFetchCache {
+            cacheResponse = MMCache.shared.fetchResponseCache(target: target)
+            self.getResponseStatusCode(response: cacheResponse!, completion: completion)
+        } else {
+            if MMCache.shared.isNoRecord(target, cacheType: cacheType) {
+                MMCache.shared.record(target)
+                cacheResponse = MMCache.shared.fetchResponseCache(target: target)
+                self.getResponseStatusCode(response: cacheResponse!, completion: completion)
+            }
+        }
+
+        provider.rx
+            .request(target)
+            .map(T.self)
+            .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
+            .observeOn(MainScheduler.instance)
+            .subscribe(onSuccess: { [weak self] response in
+                MMCache.shared.cacheResponse(response as!  Response, target: target)
+                self?.getResponseStatusCode(response: response as! Response, completion: completion)
+            }) {
+                [weak self] (error) in
+                if let falseCallback = self?.falseCallback  {
+                    falseCallback()
+                }
+                SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            }
+            .disposed(by: disposeBag)
+
+    }
+
+    // MARK: - 网络请求
+    /// 网络请求
+    ///
+    /// - Parameters:
+    ///   - target: 请求地址加参数
+    ///   - completion: 请求成功回调
+    func request(target: MultiTarget,completion: @escaping successCallback) -> Void {
+        //判断是否链接网络
+        if !isNetworkConnect{
+            SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            return
+        }
+
+        provider.rx
+            .request(target)
+            .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
+            .observeOn(MainScheduler.instance)
+            .subscribe(onSuccess: { [weak self] response in
+                self?.getResponseStatusCode(response: response, completion: completion)
+            }) {
+                [weak self] (error) in
+                if let falseCallback = self?.falseCallback  {
+                    falseCallback()
+                }
+                SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            }
+            .disposed(by: disposeBag)
+    }
+
+
+    /// 缓存请求
+    ///
+    /// - Parameters:
+    ///   - target: 请求地址加参数
+    ///   - alwaysFetchCache: 是否总是缓存
+    ///   - cacheType: 缓存类型
+    ///   - completion: 请求成功回调
+    func cacheRequest(target: MultiTarget,alwaysFetchCache: Bool = false,cacheType: MMCache.CacheKeyType = .default,completion: @escaping successCallback) -> Void {
+
+        //判断是否链接网络
+        if !isNetworkConnect{
+            SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            return
+        }
+
+        var cacheResponse: Response? = nil
+
+        if alwaysFetchCache {
+            cacheResponse = MMCache.shared.fetchResponseCache(target: target)
+            self.getResponseStatusCode(response: cacheResponse!, completion: completion)
+        } else {
+            if MMCache.shared.isNoRecord(target, cacheType: cacheType) {
+                MMCache.shared.record(target)
+                cacheResponse = MMCache.shared.fetchResponseCache(target: target)
+                self.getResponseStatusCode(response: cacheResponse!, completion: completion)
+            }
+        }
+
+        provider.rx
+            .request(target)
+            .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
+            .observeOn(MainScheduler.instance)
+            .subscribe(onSuccess: { [weak self] response in
+                MMCache.shared.cacheResponse(response, target: target)
+                self?.getResponseStatusCode(response: response, completion: completion)
+            }) {
+                [weak self] (error) in
+                if let falseCallback = self?.falseCallback  {
+                    falseCallback()
+                }
+                SwiftProgressHUD.shared().showError("网络链接失败,请检查网络")
+            }
+            .disposed(by: disposeBag)
+
+    }
+
+
+    // MARK: - 获取状态码
+    /// 获取状态码
+    ///
+    /// - Parameters:
+    ///   - response: 响应结果
+    ///   - completion: 回调
+    private func getResponseStatusCode(response:Response, completion: @escaping successCallback) -> Void {
+        let json = try? JSON(response.mapJSON())
+        if response.statusCode == 200 {
+            NXLLog("\nstatusCode=\(response.statusCode)\njson=\n\(json!.description)");
+            let json = JSON(parseJSON: json!.description)
+            let rootModel = RootModel(JSONString: json.description)
+            let data = JSON(json["data"]).description
+            rootModel?.data = data
+            if rootModel!.code == 0 {
+                 completion(rootModel as Any)
+            }else if rootModel!.code  == 1 {
+                SwiftProgressHUD.shared().showError(rootModel!.msg ?? "信息有误!!!")
+                if let falseCallback = self.falseCallback  {
+                    falseCallback()
+                }
+            }else {
+                SwiftProgressHUD.shared().showError(rootModel!.msg ?? "信息有误!!!")
+                if let falseCallback = self.falseCallback  {
+                    falseCallback()
+                }
+            }
+        }else if response.statusCode == 401 {
+            NXLLog("\nstatusCode=\(response.statusCode)\njson=\n\(json!.description)");
+            let infoModel = InfoModel(JSONString: json?.description ?? "")
+            LoginModel.shared().removeLoginModel()
+            kAppDelegate.setLoginController()
+            SwiftProgressHUD.shared().showText(infoModel?.message ?? "")
+            if let falseCallback = self.falseCallback  {
+                falseCallback()
+            }
+        } else {
+            NXLLog("\nstatusCode=\(response.statusCode)\nerror=\n\(response.description)");
+            SwiftProgressHUD.shared().showError(response.description)
+            if let falseCallback = self.falseCallback  {
+                falseCallback()
+            }
+        }
+    }
+
+
+    // MARK: - 取消所有请求
+    /// 取消所有请求
+    func cancelAllRequest() {
+        provider.manager.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
+            dataTasks.forEach { $0.cancel() }
+            uploadTasks.forEach { $0.cancel() }
+            downloadTasks.forEach { $0.cancel() }
+        }
+    }
+
+    // MARK: - 取消指定请求
+    /// 取消指定请求
+    ///
+    /// - Parameter url: 指定的网络请求地址
+    func cancelDesignationRequest(url:String) {
+        provider.manager.session.getTasksWithCompletionHandler {
+            (sessionDataTask, uploadData, downloadData) in
+            sessionDataTask.forEach {
+                //只取消指定url的请求
+                if ($0.originalRequest?.url?.absoluteString == url) {
+                    $0.cancel()
+                }
+            }
+        }
+    }
+    
+}
+
+extension PrimitiveSequence where TraitType == SingleTrait, ElementType == Response {
+    func map<T: BaseMappable>(_ type: T.Type) -> Single<T?> {
+        return flatMap { response -> Single<T?> in
+            do {
+                let json = try JSON(response.mapJSON())
+                if response.statusCode == 200 {
+                    NXLLog("\nstatusCode=\(response.statusCode)\njson=\n\(json.description)");
+
+                    let json = JSON(parseJSON: json.description)
+                    let rootModel = RootModel(JSONString: json.description)
+                    let data = JSON(json["data"]).description
+                    rootModel?.data = data
+                    if rootModel!.code  == 0 {
+                        let mapper = T(JSONString:  rootModel!.data ?? "")
+                        return Single<T?>.just(mapper)
+                    }else if rootModel!.code  == 1 {
+                        SwiftProgressHUD.shared().showError(rootModel!.msg ?? "信息有误!!!")
+                        return Single<T?>.just(nil)
+                    }else {
+                        SwiftProgressHUD.shared().showError(rootModel!.msg ?? "信息有误!!!")
+                        return Single<T?>.just(nil)
+                    }
+                }else if response.statusCode == 401 {
+                    NXLLog("\nstatusCode=\(response.statusCode)\njson=\n\(json.description)");
+                    let infoModel = InfoModel(JSONString: json.description)
+                    SwiftProgressHUD.shared().showText(infoModel!.message ?? "登录过期,请重新登录")
+                    LoginModel.shared().removeLoginModel()
+                    kAppDelegate.setLoginController()
+                    return Single<T?>.just(nil)
+                }else {                NXLLog("\nstatusCode=\(response.statusCode)\nerror=\n\(response.description)");
+                    SwiftProgressHUD.shared().showError(response.description)
+                    return Single<T?>.just(nil)
+                }
+
+            } catch {
+                NXLLog("\nstatusCode=\(response.statusCode)\nerror=\n\(response.description)");
+                SwiftProgressHUD.shared().showError(response.description)
+                return Single<T?>.just(nil)
+            }
+        }
+    }
+}

+ 58 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServicePay/SwiftMoyaNetWorkServicePay.swift

@@ -0,0 +1,58 @@
+//
+//  SwiftMoyaNetWorkServicePay.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/4/3.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import Foundation
+import Moya
+import SwiftyJSON
+import ObjectMapper
+
+public class SwiftMoyaNetWorkServicePay: NSObject {
+    private static let _sharedInstance = SwiftMoyaNetWorkServicePay()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> SwiftMoyaNetWorkServicePay {
+        return _sharedInstance
+    }
+
+    /// 数据回调
+    typealias apiCallBack = (Any) -> (Void)
+
+    /// 支付
+    ///
+    /// - Parameters:
+    ///   - completion: 回调
+    func payAlipayApi(completion: @escaping apiCallBack) {
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(target: MultiTarget(SwiftMoyaServicePayApi.alipay)) { (rootModel) in
+            let rootModel = rootModel as! RootModel
+            if rootModel.code == 0 {
+                completion(rootModel.data as Any)
+                SwiftProgressHUD.shared().hide()
+            }else if rootModel.code == 1 {
+                SwiftProgressHUD.shared().showWarning(rootModel.msg ?? "")
+            }else {
+                SwiftProgressHUD.shared().showWarning(rootModel.msg ?? "")
+            }
+        }
+    }
+
+    /// 微信
+    ///
+    /// - Parameters:
+    ///   - completion: 回调
+    func payWeixinpayApi(completion: @escaping apiCallBack) {
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(WeChatpayOrderModel.self,target: MultiTarget(SwiftMoyaServicePayApi.weixinpay)) { (weChatpayOrderModel) in
+            let weChatpayOrderModel = weChatpayOrderModel as! WeChatpayOrderModel
+            completion(weChatpayOrderModel)
+            SwiftProgressHUD.shared().hide()
+        }
+    }
+
+}

+ 88 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServicePay/SwiftMoyaServicePayApi.swift

@@ -0,0 +1,88 @@
+//
+//  SwiftMoyaServicePayApi.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/4/3.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import Foundation
+import Foundation
+import Moya
+
+// MARK: - 支付宝支付接口
+/// 支付宝支付接口
+public let kAlipayApi = "/api/alipay"
+
+/// 支付宝支付接口
+public let kWeixinpayApi = "/api/weixin"
+
+/// 支付
+///
+/// - alipay: 支付宝支付
+public enum SwiftMoyaServicePayApi {
+    case alipay
+    case weixinpay
+}
+
+extension SwiftMoyaServicePayApi: TargetType {
+
+    public var baseURL: URL {
+        switch self {
+        case .alipay,
+             .weixinpay
+            :
+            return URL(string: kApiDataPrefix())!
+        }
+    }
+
+    public var path: String {
+        switch self {
+        case .alipay:
+            return kAlipayApi
+        case .weixinpay:
+            return kWeixinpayApi
+        }
+    }
+
+    public var method: Moya.Method {
+        switch self {
+        case .alipay,
+            .weixinpay
+            :
+            return .post
+        }
+    }
+
+    // MARK: - 请求任务事件(这里附带上参数)
+    public var task: Task {
+        switch self {
+        case .alipay,
+             .weixinpay
+            :
+            return .requestPlain
+        }
+    }
+
+
+    // MARK: - 是否执行Alamofire验证
+    public var validate: Bool {
+        return false
+    }
+
+    // MARK: - 这个就是做单元测试模拟的数据,只会在单元测试文件中有作用
+    public var sampleData: Data {
+        return "{}".data(using: String.Encoding.utf8)!
+    }
+
+    // MARK: - 请求头
+    public var headers: [String : String]? {
+        //同task,具体选择看后台 有application/x-www-form-urlencoded 、application/json
+        switch self {
+        case .alipay,
+             .weixinpay
+            :
+            return ["Content-Type":"application/x-www-form-urlencoded"]
+        }
+    }
+}

+ 48 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceSMS/SwiftMoyaNetWorkServiceSMS.swift

@@ -0,0 +1,48 @@
+//
+//  SwiftMoyaNetWorkServiceSMS.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/4/15.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import Moya
+import SwiftyJSON
+import ObjectMapper
+
+class SwiftMoyaNetWorkServiceSMS: NSObject {
+    
+    private static let _sharedInstance = SwiftMoyaNetWorkServiceSMS()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> SwiftMoyaNetWorkServiceSMS {
+        return _sharedInstance
+    }
+
+    /// 数据回调
+    typealias apiCallBack = (Any) -> (Void)
+
+    /// 登录
+    ///
+    /// - Parameters:
+    ///   - mobile: 电话号码
+    ///   - password: 用户密码
+    ///   - completion: 回调
+    func smsSendSMSApi(mobile:String,appNameType:AppNameType,sendType:SendType,smsType:SMSType,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(mobile, forKey: "mobile")
+        parameters.updateValue(appNameType, forKey: "app_name")
+        parameters.updateValue(sendType, forKey: "send_type")
+        parameters.updateValue(smsType, forKey: "sms_type")
+        parameters.updateValue(AppInfo.ipAddress, forKey: "ip")
+
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(target: MultiTarget(SwiftMoyaServiceSMSApi.smsSend(parameters: parameters))) { (loginModel) in
+            SwiftProgressHUD.shared().hide()
+            completion("")
+        }
+    }
+
+}

+ 103 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceSMS/SwiftMoyaServiceSMSApi.swift

@@ -0,0 +1,103 @@
+//
+//  SwiftMoyaServiceSMSApi.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/4/15.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import UIKit
+import Moya
+
+/// 应用名称
+///
+/// - app: App
+enum AppNameType : String {
+    case app = "APP"
+}
+
+
+/// 发送方式
+///
+/// - ali: 阿里
+enum SendType : String {
+    case ali = "ali"
+}
+
+
+/// 短信类型
+///
+/// - accountLogin: 用户登录
+/// - accountBind: 用户绑定
+enum SMSType : String {
+    case accountLogin = "account_login"
+    case accountBind = "account_bind"
+}
+
+// MARK: - 发送验证码
+/// 发送验证码
+public let kSMSSendApi = "/sms/send"
+
+/// 发送验证
+///
+/// - sendSMS: 发送验证
+public enum SwiftMoyaServiceSMSApi {
+    case smsSend(parameters:Dictionary<String, Any>)
+}
+
+extension SwiftMoyaServiceSMSApi: TargetType {
+
+    public var baseURL: URL {
+        switch self {
+        case .smsSend
+            :
+            return URL(string: kApiDataPrefix())!
+        }
+    }
+
+    public var path: String {
+        switch self {
+        case .smsSend:
+            return kSMSSendApi
+        }
+    }
+
+    public var method: Moya.Method {
+        switch self {
+        case .smsSend
+            :
+            return .post
+        }
+    }
+
+    // MARK: - 请求任务事件(这里附带上参数)
+    public var task: Task {
+        switch self {
+        case .smsSend(var parameters)
+            :
+            let sign = SwiftSign.shared().sign(signType:.SMS, parameters: parameters)
+            parameters.updateValue(sign, forKey: "sign")
+            return .requestParameters(parameters: parameters, encoding: URLEncoding.default)
+        }
+    }
+
+
+    // MARK: - 是否执行Alamofire验证
+    public var validate: Bool {
+        return false
+    }
+
+    // MARK: - 这个就是做单元测试模拟的数据,只会在单元测试文件中有作用
+    public var sampleData: Data {
+        return "{}".data(using: String.Encoding.utf8)!
+    }
+
+    // MARK: - 请求头
+    public var headers: [String : String]? {
+        //同task,具体选择看后台 有application/x-www-form-urlencoded 、application/json
+        switch self {
+        case .smsSend:
+            return ["Content-Type":"application/x-www-form-urlencoded"]
+        }
+    }
+}

+ 199 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceUser/SwiftMoyaNetWorkServiceUser.swift

@@ -0,0 +1,199 @@
+//
+//  SwiftMoyaNetWorkServiceUser.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/29.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import Foundation
+import Moya
+import SwiftyJSON
+import ObjectMapper
+
+public class SwiftMoyaNetWorkServiceUser: NSObject {
+
+    private static let sharedInstance = SwiftMoyaNetWorkServiceUser()
+
+    private override init() {} // 私有化init方法
+
+    public class func shared() -> SwiftMoyaNetWorkServiceUser {
+        return sharedInstance
+    }
+
+    /// 数据回调
+    typealias apiCallBack = (Any) -> (Void)
+
+    /// 登录
+    ///
+    /// - Parameters:
+    ///   - mobile: 电话号码
+    ///   - password: 用户密码
+    ///   - completion: 回调
+    func userLoginApi(mobile:String,password:String,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(mobile, forKey: "mobile")
+        parameters.updateValue(password, forKey: "password")
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(LoginModel.self ,target: MultiTarget(SwiftMoyaServiceUserApi.userLogin(parameters: parameters))) { (loginModel) in
+            LoginModel.shared().setLoginModel(loginModel: loginModel as! LoginModel)
+            SwiftProgressHUD.shared().hide()
+            completion("")
+        }
+    }
+
+
+    /// 登出
+    ///
+    /// - Parameters:
+    ///   - completion: 回调
+    func userLogoutApi() {
+        let parameters = Dictionary<String,Any>()
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(target: MultiTarget(SwiftMoyaServiceUserApi.userLogout(parameters: parameters))) { (data) in
+            LoginModel.shared().removeLoginModel()
+            kAppDelegate.setLoginController()
+            SwiftProgressHUD.shared().hide()
+        }
+    }
+
+    /// 刷新令牌
+    ///
+    /// - Parameters:
+    ///   - completion: 回调
+    func userRefreshApi(completion: @escaping apiCallBack) {
+        let parameters = Dictionary<String,Any>()
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(LoginModel.self,target: MultiTarget(SwiftMoyaServiceUserApi.userRefresh(parameters: parameters))) { (loginModel) in
+            LoginModel.shared().setLoginModel(loginModel: loginModel as! LoginModel)
+            SwiftProgressHUD.shared().hide()
+            completion("")
+        }
+    }
+
+    /// 微信注册/登录
+    ///
+    /// - Parameters:
+    ///   - open_id: 微信 open_id
+    ///   - union_id: 微信 string
+    ///   - avatar: 头像
+    ///   - username: 昵称
+    ///   - gender: 性别 1男 2女
+    ///   - completion: 回调
+    func userWeiXinRegisterApi(open_id:String,union_id:String,avatar:String,username:String,gender:Int,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(open_id, forKey: "open_id")
+        parameters.updateValue(union_id, forKey: "union_id")
+        parameters.updateValue(avatar, forKey: "avatar")
+        parameters.updateValue(username, forKey: "username")
+        parameters.updateValue(gender, forKey: "gender")
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(LoginModel.self,target: MultiTarget(SwiftMoyaServiceUserApi.userWeiXinRegister(parameters: parameters))) { (loginModel) in
+            LoginModel.shared().setLoginModel(loginModel: loginModel as! LoginModel)
+            SwiftProgressHUD.shared().hide()
+            completion("")
+        }
+    }
+
+
+    /// 手机注册/登录
+    ///
+    /// - Parameters:
+    ///   - mobile: 手机号
+    ///   - sms_code: 短信验证码
+    ///   - completion: 回调
+    func userMobileRegisterApi(mobile:String,sms_code:String,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(mobile, forKey: "mobile")
+        parameters.updateValue(sms_code, forKey: "sms_code")
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(LoginModel.self,target: MultiTarget(SwiftMoyaServiceUserApi.userMobileRegister(parameters: parameters))) { (loginModel) in
+            LoginModel.shared().setLoginModel(loginModel: loginModel as! LoginModel)
+            SwiftProgressHUD.shared().hide()
+            completion("")
+        }
+    }
+
+
+    /// 手机密码登录
+    ///
+    /// - Parameters:
+    ///   - mobile: 手机号
+    ///   - password: 密码
+    ///   - completion: 回调
+    func userMobileLoginApi(mobile:String,password:String,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(mobile, forKey: "mobile")
+        parameters.updateValue(password, forKey: "password")
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(LoginModel.self,target: MultiTarget(SwiftMoyaServiceUserApi.userMobileLogin(parameters: parameters))) { (loginModel) in
+            LoginModel.shared().setLoginModel(loginModel: loginModel as! LoginModel)
+            SwiftProgressHUD.shared().hide()
+            completion("")
+        }
+    }
+
+    /// 绑定微信
+    ///
+    /// - Parameters:
+    ///   - mobile: 手机号
+    ///   - umLoginModel: 微信模型
+    ///   - completion: 回调
+    func userBindWeixinApi(mobile:String,umLoginModel:UMLoginModel,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(mobile, forKey: "mobile")
+        parameters.updateValue(umLoginModel.open_id, forKey: "open_id")
+        parameters.updateValue(umLoginModel.union_id, forKey: "open_id")
+        parameters.updateValue(umLoginModel.avatar, forKey: "open_id")
+        parameters.updateValue(umLoginModel.username, forKey: "open_id")
+        parameters.updateValue(umLoginModel.gender, forKey: "open_id")
+
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(target: MultiTarget(SwiftMoyaServiceUserApi.userBindWeixin(parameters: parameters))) { (rootModel) in
+            let rootModel = rootModel as! RootModel
+            SwiftProgressHUD.shared().showText(rootModel.msg!)
+            completion("")
+        }
+    }
+
+    /// 绑定手机号
+    ///
+    /// - Parameters:
+    ///   - mobile: 手机号
+    ///   - smsCode: 验证码
+    ///   - completion: 回调
+    func userBindMobileApi(mobile:String,smsCode:String,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(mobile, forKey: "mobile")
+        parameters.updateValue(smsCode, forKey: "sms_code")
+
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(target: MultiTarget(SwiftMoyaServiceUserApi.userBindMobile(parameters: parameters))) { (rootModel) in
+            let rootModel = rootModel as! RootModel
+            SwiftProgressHUD.shared().showText(rootModel.msg!)
+            completion("")
+        }
+    }
+
+    /// 设置密码
+    ///
+    /// - Parameters:
+    ///   - mobile: 手机号
+    ///   - password: 密码
+    ///   - password_confirmation: 确认密码
+    ///   - completion: 回调
+    func userSetPasswordApi(mobile:String,password:String,password_confirmation:String,completion: @escaping apiCallBack) {
+        var parameters = Dictionary<String,Any>()
+        parameters.updateValue(mobile, forKey: "mobile")
+        parameters.updateValue(password, forKey: "password")
+        parameters.updateValue(password_confirmation, forKey: "password_confirmation")
+
+        SwiftProgressHUD.shared().showWait()
+        SwiftMoyaNetWorkManager.shared().request(target: MultiTarget(SwiftMoyaServiceUserApi.userSetPassword(parameters: parameters))) { (rootModel) in
+            let rootModel = rootModel as! RootModel
+            SwiftProgressHUD.shared().showText(rootModel.msg!)
+            completion("")
+        }
+    }
+
+}

+ 183 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftMoyaServiceUser/SwiftMoyaServiceUserApi.swift

@@ -0,0 +1,183 @@
+//
+//  SwiftMoyaServiceUserApi.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/3/29.
+//  Copyright © 2019 南鑫林. All rights reserved.
+//
+
+import Foundation
+import Moya
+
+// MARK: - 登录
+/// 登录
+public let kUserLoginApi = "/user/login"
+
+// MARK: - 登出
+/// 登出
+public let kUserLogoutApi = "/user/logout"
+
+// MARK: - 刷新用户信息
+/// 刷新用户信息
+public let kUserRefreshApi = "/user/refresh"
+
+// MARK: - 微信注册/登录
+/// 微信注册/登录
+public let kUserWeiXinRegisterApi = "/user/weixinRegister"
+
+// MARK: - 手机验证码注册/登录
+/// 手机验证码注册/登录
+public let kUserMobileRegisterApi = "/user/mobileRegister"
+
+// MARK: - 手机密码登录
+/// 手机密码登录
+public let kUserMobileLoginApi = "/user/mobileLogin"
+
+// MARK: - 绑定微信
+/// 绑定微信
+public let kUserBindWeixinApi = "/user/bindWeixin"
+
+// MARK: - 绑定手机号码
+/// 绑定手机号码
+public let kUserBindMobileApi = "/user/bindMobile"
+
+// MARK: - 设置密码
+/// 设置密码
+public let kUserSetPasswordApi = "/user/SetPassword"
+
+
+
+/// 用户
+///
+/// - login: 登录
+/// - logout: 登出
+/// - refresh: 刷新用户信息
+/// - sendSms: 发送短信验证码
+/// - weiXinRegister: 微信注册/登录
+/// - mobileRegister: 手机验证码注册/登录
+/// - mobileLogin: 手机密码登录
+/// - bindWeixin: 绑定微信
+/// - bindMobile: 绑定手机号码
+/// - setPassword: 设置密码
+public enum SwiftMoyaServiceUserApi {
+    case userLogin(parameters:Dictionary<String, Any>)
+    case userLogout(parameters:Dictionary<String, Any>)
+    case userRefresh(parameters:Dictionary<String, Any>)
+    case userWeiXinRegister(parameters:Dictionary<String, Any>)
+    case userMobileRegister(parameters:Dictionary<String, Any>)
+    case userMobileLogin(parameters:Dictionary<String, Any>)
+    case userBindWeixin(parameters:Dictionary<String, Any>)
+    case userBindMobile(parameters:Dictionary<String, Any>)
+    case userSetPassword(parameters:Dictionary<String, Any>)
+}
+
+extension SwiftMoyaServiceUserApi: TargetType {
+
+    public var baseURL: URL {
+        switch self {
+        case .userLogin,
+             .userLogout,
+             .userRefresh,
+             .userWeiXinRegister,
+             .userMobileRegister,
+             .userMobileLogin,
+             .userBindWeixin,
+             .userBindMobile,
+             .userSetPassword
+            :
+            return URL(string: kApiDataPrefix())!
+        }
+    }
+
+    public var path: String {
+        switch self {
+        case .userLogin:
+            return kUserLoginApi
+        case .userLogout:
+            return kUserLogoutApi
+        case .userRefresh:
+            return kUserRefreshApi
+        case .userWeiXinRegister:
+            return kUserWeiXinRegisterApi
+        case .userMobileRegister:
+            return kUserMobileRegisterApi
+        case .userMobileLogin:
+            return kUserMobileLoginApi
+        case .userBindWeixin:
+            return kUserBindMobileApi
+        case .userBindMobile:
+            return kUserBindMobileApi
+        case .userSetPassword:
+            return kUserSetPasswordApi
+        }
+    }
+
+    public var method: Moya.Method {
+        switch self {
+        case .userLogin,
+             .userLogout,
+             .userRefresh,
+             .userWeiXinRegister,
+             .userMobileRegister,
+             .userMobileLogin,
+             .userBindWeixin,
+             .userBindMobile,
+             .userSetPassword
+            :
+            return .post
+        }
+    }
+
+    // MARK: - 请求任务事件(这里附带上参数)
+    public var task: Task {
+        switch self {
+        case .userLogin(let parameters),
+             .userWeiXinRegister(let parameters),
+             .userMobileRegister(let parameters),
+             .userMobileLogin(let parameters)
+             :
+            return .requestParameters(parameters: parameters, encoding: URLEncoding.default)
+        case .userLogout(var parameters),
+             .userRefresh(var parameters),
+             .userBindWeixin(var parameters),
+             .userBindMobile(var parameters),
+             .userSetPassword(var parameters)
+            :
+            let sign = SwiftSign.shared().sign(signType:.AccessToken, parameters: parameters)
+            parameters.updateValue(sign, forKey: "sign")
+            return .requestParameters(parameters: parameters, encoding: URLEncoding.default)
+        }
+    }
+
+
+    // MARK: - 是否执行Alamofire验证
+    public var validate: Bool {
+        return false
+    }
+
+    // MARK: - 这个就是做单元测试模拟的数据,只会在单元测试文件中有作用
+    public var sampleData: Data {
+        return "{}".data(using: String.Encoding.utf8)!
+    }
+
+    // MARK: - 请求头
+    public var headers: [String : String]? {
+        //同task,具体选择看后台 有application/x-www-form-urlencoded 、application/json
+        switch self {
+        case .userLogin,
+             .userWeiXinRegister,
+             .userMobileRegister,
+             .userMobileLogin
+            :
+            return (headerParameters(headerType: .moreHeader) as! [String : String])
+        case .userLogout,
+             .userRefresh,
+             .userBindWeixin,
+             .userBindMobile,
+             .userSetPassword
+            :
+            return (headerParameters(headerType: .tokenHeader) as! [String : String])
+        }
+    }
+
+}

+ 130 - 0
RainbowPlanet/RainbowPlanet/Service/SwiftMoyaService/SwiftSign/SwiftSign.swift

@@ -0,0 +1,130 @@
+//
+//  SwiftSign.swift
+//  CreaditPayment
+//
+//  Created by 南鑫林 on 2018/11/17.
+//  Copyright © 2018 南鑫林. All rights reserved.
+//
+
+import UIKit
+import SwiftyJSON
+
+public class SwiftSign: NSObject {
+
+    private static let _sharedInstance = SwiftSign()
+
+    class func shared() -> SwiftSign {
+        return _sharedInstance
+    }
+
+    private override init() {} // 私有化init方法
+
+
+    /// 验签类型
+    ///
+    /// - AccessToken: 用户token
+    /// - SMS: 短信验签
+    public enum SignType {
+        case AccessToken
+        case SMS
+    }
+
+    /// 验签
+    ///
+    /// - Parameter parameters: 需要加密的参数
+    /// - Returns: data字符串
+    public func sign(signType:SignType,parameters: Dictionary<String,Any>) -> String {
+        
+        //第一步拼装map 1. 排序 2.转换字符串
+        let jsonStr = getJsonString(signType:signType,parameters: parameters)
+
+        //第二班步生成sign  strtoupper(md5(param.access_token))
+         let sign = getSign(jsonStr: jsonStr)
+        return sign
+    }
+    
+    // MARK: - 第一步拼装map 1. 排序 2.转换字符串 提交给服务端参数,统一删除参数组中所有等值为FALSE的参数(包括:NULL, 空字符串,0, false)
+    private func getJsonString(signType:SignType, parameters:Dictionary<String,Any>) -> String {
+
+        var namedPaird = [String]()
+
+        if !parameters.isEmpty {
+            let sortedKeysAndValues = parameters.sorted { (t1, t2) -> Bool in
+                return t1.0 < t2.0
+            }
+
+            for(key, value) in sortedKeysAndValues {
+
+                if value is String { //空字符串
+                    let value = value as! String
+                    if value == "" {
+                        continue
+                    }
+                }
+
+                if value is Bool { //false
+                    let value = value as! Bool
+                    if !value {
+                        continue
+                    }
+                }
+
+                if value is Int {//0
+                    let value = value as! Int
+                    if value == 0 {
+                        continue
+                    }
+                }
+
+                if value is NSNull {//NULL
+                    continue
+                }
+
+                namedPaird.append("\(key)" + "=" + "\(value)")
+            }
+        }
+
+        switch signType {
+        case .AccessToken:
+            let access_token = setAccessTokenchxq_key()
+            if !access_token.isEmpty {
+                namedPaird.append("chxq_key" + "=" + "\(access_token)")
+            }
+            break
+        case .SMS:
+            let sms = setSMSchxq_key()
+            namedPaird.append("chxq_key" + "=" + "\(sms)")
+            break
+        }
+
+
+        let returnString = namedPaird.joined(separator:"&")
+        let jsonStr = JSON(returnString).description.description
+        NXLLog(jsonStr)
+        return jsonStr
+    }
+    
+    // MARK: - 第二班步生成sign  strtoupper(md5(param.access_token))
+    private func getSign(jsonStr:String) -> String {
+        let sign = jsonStr.md5().uppercased()
+        NXLLog(sign)
+        return sign
+    }
+
+
+    private func setSMSchxq_key() -> String {
+        //获取当前时间
+        let date = Date()
+        //日期转字符串(格式化输出)
+        let dateStr = date.dateToString(date, dateFormat: "yyyy-MM-dd")
+        let SMS = "caihong" + dateStr + "xingqiu"
+        return SMS
+    }
+
+    private func setAccessTokenchxq_key() -> String {
+        //获取当前时间
+        let access_token = LoginModel.shared().getLoginModel()?.accessToken ?? ""
+        return access_token
+    }
+
+}

+ 116 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,116 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneNotification_20pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneNotification_20pt@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneSpootlight5_29pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneSpootlight5_29pt@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneSpootlight7_40pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneSpootlight7_40pt@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneApp_60pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "logo-1024iPhoneApp_60pt@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadNotifications_20pt.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadNotifications_20pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadSpootlight5_29pt.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadSpootlight5_29pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadSpootlight7_40pt.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadSpootlight7_40pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadApp_76pt.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadApp_76pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "logo-1024iPadProApp_83.5pt@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "1024x1024",
+      "idiom" : "ios-marketing",
+      "filename" : "logo-1024store_1024pt.png",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadApp_76pt.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadApp_76pt@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadNotifications_20pt.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadNotifications_20pt@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadProApp_83.5pt@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight5_29pt.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight5_29pt@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight7_40pt.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPadSpootlight7_40pt@2x.png


BIN
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPhoneApp_60pt@2x.png


+ 0 - 0
RainbowPlanet/RainbowPlanet/Supporting Files/Assets.xcassets/AppIcon.appiconset/logo-1024iPhoneApp_60pt@3x.png


Неке датотеке нису приказане због велике количине промена