HotQuoteViewController.swift 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. //
  2. // HotQuoteViewController.swift
  3. // MTP2_iOS
  4. //
  5. // Created by Handy_Cao on 2020/10/30.
  6. // Copyright © 2020 Muchinfo. All rights reserved.
  7. //
  8. import UIKit
  9. import WHToast
  10. import SwiftyAttributes
  11. import GTMRefresh
  12. /// 热卖商品视图容器控制类
  13. class HotQuoteViewController: BaseViewController {
  14. // MARK: - 属性列表
  15. /// 位置按钮
  16. @IBOutlet weak var location: UIButton!
  17. /// 商品数据集合视图
  18. @IBOutlet weak var collectionView: UICollectionView! {
  19. didSet {
  20. if collectionView.responds(to: #selector(setter: UICollectionView.isPrefetchingEnabled)) {
  21. collectionView.isPrefetchingEnabled = false
  22. }
  23. /// 设置约束
  24. collectionView.setCollectionViewLayout(flowLayout, animated: true)
  25. }
  26. }
  27. /// 数据显示集合视图约束
  28. lazy var flowLayout: UICollectionViewFlowLayout = {
  29. /// 最小行间距,默认是0
  30. $0.minimumLineSpacing = 0
  31. /// 最小左右间距,默认是10
  32. $0.minimumInteritemSpacing = 0
  33. /// 区域内间距,默认是 UIEdgeInsetsMake(0, 0, 0, 0)
  34. $0.sectionInset = UIEdgeInsets(top: 0.0, left: 0, bottom: 0, right: 0)
  35. /// 水平滚动
  36. $0.scrollDirection = .vertical
  37. return $0
  38. } (UICollectionViewFlowLayout())
  39. /// GoodsCellIdentifier
  40. let GoodsCellIdentifier = "Goods_Cell"
  41. /// 商品数据信息
  42. var goods: [MoGoodsInfo] = [] {
  43. didSet {
  44. /// 刷新数据
  45. collectionView.reloadData()
  46. /// 是否隐藏按钮
  47. self.noDataButton.isHidden = goods.count != 0
  48. if goods.count > 0 {
  49. /// 等待UI操作完成,也就是tableView刷新完之后执行
  50. DispatchQueue.main.async { [weak self] in
  51. if self?.visibleGoodsCodes.count != 0 { self?.shouldSubscriptGoodsCodes = self?.visibleGoodsCodes }
  52. }
  53. }
  54. }
  55. }
  56. /// 省份信息
  57. var geographics: [MoGeographicPosition] = []
  58. /// 市区信息
  59. var city: MoGeographic? {
  60. didSet {
  61. self.location.setTitle(city?.pathname ?? "全部", for: .normal)
  62. /// 查询商品
  63. self.requestQueryHotGoods(self.city)
  64. }
  65. }
  66. // MARK: - 生命周期
  67. override func viewDidLoad() {
  68. super.viewDidLoad()
  69. // Do any additional setup after loading the view.
  70. /// UI界面初始化
  71. buildView()
  72. }
  73. override func didMove(toParent parent: UIViewController?) {
  74. super.didMove(toParent: parent)
  75. if let _ = parent {
  76. /// 数据初始化
  77. initData()
  78. } else {
  79. noDataButton.isHidden = true
  80. }
  81. /// 侦听行情推送广播
  82. MTP2BusinessCore.shared.broadcastManager?.addBroadcastListener(owner: self, action: .ReceiveTradeQuote) { [weak self] in
  83. guard let quoteGoodsInfos = $0.object as? [(goodsHqCode: String, exchHqCode: String)],
  84. let weakSelf = self else { return }
  85. /// 有数据
  86. if quoteGoodsInfos.count != 0 {
  87. /// 待刷新行
  88. var refreshIndexPaths = [IndexPath]()
  89. DispatchQueue.main.async {
  90. for (index, cell) in weakSelf.collectionView.visibleCells.enumerated() {
  91. if quoteGoodsInfos.first(where: { $0.goodsHqCode == (cell as? GoodsCell)?.model?.goodscode }) != nil {
  92. let indexPath = IndexPath(row: index, section: 0)
  93. if refreshIndexPaths.firstIndex(of: indexPath) == nil {
  94. /// 记录待刷新行
  95. /// 判断是否在可见区域
  96. if weakSelf.collectionView.indexPathsForVisibleItems.firstIndex(of: indexPath) != nil {
  97. refreshIndexPaths.append(indexPath)
  98. }
  99. }
  100. }
  101. }
  102. }
  103. /// 刷新行情列表
  104. if refreshIndexPaths.count > 0 {
  105. DispatchQueue.main.async {
  106. weakSelf.collectionView.reloadItems(at: refreshIndexPaths)
  107. }
  108. }
  109. }
  110. }
  111. }
  112. deinit {
  113. /// 清除广播侦听
  114. MTP2BusinessCore.shared.broadcastManager?.removeBroadcastListener(owner: self, forName: .ReceiveTradeQuote)
  115. }
  116. // MARK: - 数据初始化
  117. /// 数据初始化
  118. fileprivate func initData() {
  119. /// 查询热门商品信息
  120. requestQueryHotGoods(self.city)
  121. }
  122. /// UI界面初始化
  123. fileprivate func buildView() {
  124. /// 异常
  125. guard let accountManager = MTP2BusinessCore.shared.accountManager else {
  126. return
  127. }
  128. /// loding......
  129. addLoadingView()
  130. /// 赋值省市区信息
  131. self.geographics = accountManager.geographics ?? []
  132. /// 添加下拉刷新控件
  133. self.collectionView.gtm_addRefreshHeaderView(refreshHeader: DefaultGTMRefreshHeader()) {
  134. /// 重置请求条件
  135. self.initData()
  136. }
  137. }
  138. // MARK: - 接口请求
  139. /// 获取热门商品数据信息
  140. fileprivate func requestQueryHotGoods(_ city: MoGeographic?) {
  141. /// 异常
  142. guard let goodsManager = MTP2BusinessCore.shared.goodsManager else {
  143. return
  144. }
  145. /// 目标省份
  146. let descProvinceID = (city == nil || city?.divisionlevel != "province") ? nil : city?.autoid
  147. /// 目标城市
  148. let descCityID = (city == nil || city?.divisionlevel != "city") ? nil : city?.autoid
  149. /// startAnimating
  150. self._anim?.startAnimating()
  151. /// 发送请求
  152. goodsManager.requestQueryTopGoods(goodsManager.getMarketIDs(.TRADEMODE_LISTING_SELECT), descProvinceID, descCityID) { (isComplete, error, topGoods) in
  153. DispatchQueue.main.async {
  154. /// stopAnimating
  155. self._anim?.stopAnimating()
  156. /// endRefreshing
  157. self.collectionView.endRefreshing()
  158. if isComplete {
  159. /// 数据获取成功
  160. self.goods = topGoods ?? []
  161. } else {
  162. self.goods = []
  163. /// toast
  164. WHToast.showError(withMessage: "数据获取失败,原因:\(error?.retMsg ?? "未知错误")", duration: 1.0, finishHandler: {})
  165. }
  166. }
  167. }
  168. }
  169. // MARK: - 交互相关
  170. /// onButtonPressed
  171. /// - Parameter sender: sender
  172. @IBAction fileprivate func onButtonPressed(_ sender: UIButton) {
  173. switch sender {
  174. case location: /// 位置
  175. let geographicPickView = GeographicPickView(nibName: "GeographicPickView", bundle: nil)
  176. geographicPickView.modalTransitionStyle = .coverVertical
  177. geographicPickView.modalPresentationStyle = .overFullScreen
  178. geographicPickView.callback = { (_ takeInfo: MoGeographic?, _ isSure: Bool) in
  179. self.city = takeInfo
  180. }
  181. self.present(geographicPickView, animated: true, completion: {})
  182. default:
  183. break
  184. }
  185. }
  186. // MARK: - 订阅行情相关
  187. var uuid: String = UUID().uuidString
  188. var shouldSubscriptGoodsCodes: Set<String>? {
  189. didSet {
  190. guard let quoteSubscriptManager = MTP2BusinessCore.shared.quoteSubscriptManager else { return }
  191. quoteSubscriptManager.updateQuoteSubcriptGoods(uuid: uuid, goodsCode: shouldSubscriptGoodsCodes ?? [])
  192. }
  193. }
  194. var visibleGoodsCodes: Set<String> {
  195. var goodsCodes = Set<String>()
  196. self.collectionView.visibleCells.forEach { (cell) in
  197. if let quoteCell = cell as? GoodsCell, let goodsCode = quoteCell.model?.goodscode {
  198. goodsCodes.insert(goodsCode)
  199. }
  200. }
  201. return goodsCodes
  202. }
  203. // MARK: - Navigation
  204. // In a storyboard-based application, you will often want to do a little preparation before navigation
  205. override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  206. // Get the new view controller using segue.destination.
  207. // Pass the selected object to the new view controller.
  208. if segue.identifier == "ShowGoodsDetail" {
  209. /// 商品详情
  210. (segue.destination as? GoodsDetailViewController)?.model = (sender as? GoodsCell)?.model
  211. }
  212. }
  213. }
  214. // MARK: - UIScrollViewDelegate
  215. extension HotQuoteViewController: UIScrollViewDelegate {
  216. func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
  217. if visibleGoodsCodes.count != 0 { shouldSubscriptGoodsCodes = visibleGoodsCodes }
  218. }
  219. }
  220. // MARK: - UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
  221. extension HotQuoteViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
  222. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  223. return self.goods.count
  224. }
  225. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  226. let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GoodsCellIdentifier, for: indexPath) as! GoodsCell
  227. cell.model = self.goods[indexPath.item]
  228. return cell
  229. }
  230. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  231. return CGSize(width: collectionView.width/2, height: ((collectionView.width/2)*0.9)+80.0)
  232. }
  233. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  234. }
  235. }