// // HotQuoteViewController.swift // MTP2_iOS // // Created by Handy_Cao on 2020/10/30. // Copyright © 2020 Muchinfo. All rights reserved. // import UIKit import WHToast import SwiftyAttributes import GTMRefresh /// 热卖商品视图容器控制类 class HotQuoteViewController: BaseViewController { // MARK: - 属性列表 /// 位置按钮 @IBOutlet weak var location: UIButton! /// 商品数据集合视图 @IBOutlet weak var collectionView: UICollectionView! { didSet { if collectionView.responds(to: #selector(setter: UICollectionView.isPrefetchingEnabled)) { collectionView.isPrefetchingEnabled = false } /// 设置约束 collectionView.setCollectionViewLayout(flowLayout, animated: true) } } /// 数据显示集合视图约束 lazy var flowLayout: UICollectionViewFlowLayout = { /// 最小行间距,默认是0 $0.minimumLineSpacing = 0 /// 最小左右间距,默认是10 $0.minimumInteritemSpacing = 0 /// 区域内间距,默认是 UIEdgeInsetsMake(0, 0, 0, 0) $0.sectionInset = UIEdgeInsets(top: 0.0, left: 0, bottom: 0, right: 0) /// 水平滚动 $0.scrollDirection = .vertical return $0 } (UICollectionViewFlowLayout()) /// GoodsCellIdentifier let GoodsCellIdentifier = "Goods_Cell" /// 商品数据信息 var goods: [MoGoodsInfo] = [] { didSet { /// 刷新数据 collectionView.reloadData() /// 是否隐藏按钮 self.noDataButton.isHidden = goods.count != 0 if goods.count > 0 { /// 等待UI操作完成,也就是tableView刷新完之后执行 DispatchQueue.main.async { [weak self] in if self?.visibleGoodsCodes.count != 0 { self?.shouldSubscriptGoodsCodes = self?.visibleGoodsCodes } } } } } /// 省份信息 var geographics: [MoGeographicPosition] = [] /// 市区信息 var city: MoGeographic? { didSet { self.location.setTitle(city?.pathname ?? "全部", for: .normal) /// 查询商品 self.requestQueryHotGoods(self.city) } } // MARK: - 生命周期 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. /// UI界面初始化 buildView() } override func didMove(toParent parent: UIViewController?) { super.didMove(toParent: parent) if let _ = parent { /// 数据初始化 initData() } else { noDataButton.isHidden = true } /// 侦听行情推送广播 MTP2BusinessCore.shared.broadcastManager?.addBroadcastListener(owner: self, action: .ReceiveTradeQuote) { [weak self] in guard let quoteGoodsInfos = $0.object as? [(goodsHqCode: String, exchHqCode: String)], let weakSelf = self else { return } /// 有数据 if quoteGoodsInfos.count != 0 { /// 待刷新行 var refreshIndexPaths = [IndexPath]() DispatchQueue.main.async { for (index, cell) in weakSelf.collectionView.visibleCells.enumerated() { if quoteGoodsInfos.first(where: { $0.goodsHqCode == (cell as? GoodsCell)?.model?.goodscode }) != nil { let indexPath = IndexPath(row: index, section: 0) if refreshIndexPaths.firstIndex(of: indexPath) == nil { /// 记录待刷新行 /// 判断是否在可见区域 if weakSelf.collectionView.indexPathsForVisibleItems.firstIndex(of: indexPath) != nil { refreshIndexPaths.append(indexPath) } } } } } /// 刷新行情列表 if refreshIndexPaths.count > 0 { DispatchQueue.main.async { weakSelf.collectionView.reloadItems(at: refreshIndexPaths) } } } } } deinit { /// 清除广播侦听 MTP2BusinessCore.shared.broadcastManager?.removeBroadcastListener(owner: self, forName: .ReceiveTradeQuote) } // MARK: - 数据初始化 /// 数据初始化 fileprivate func initData() { /// 查询热门商品信息 requestQueryHotGoods(self.city) } /// UI界面初始化 fileprivate func buildView() { /// 异常 guard let accountManager = MTP2BusinessCore.shared.accountManager else { return } /// loding...... addLoadingView() /// 赋值省市区信息 self.geographics = accountManager.geographics ?? [] /// 添加下拉刷新控件 self.collectionView.gtm_addRefreshHeaderView(refreshHeader: DefaultGTMRefreshHeader()) { /// 重置请求条件 self.initData() } } // MARK: - 接口请求 /// 获取热门商品数据信息 fileprivate func requestQueryHotGoods(_ city: MoGeographic?) { /// 异常 guard let goodsManager = MTP2BusinessCore.shared.goodsManager else { return } /// 目标省份 let descProvinceID = (city == nil || city?.divisionlevel != "province") ? nil : city?.autoid /// 目标城市 let descCityID = (city == nil || city?.divisionlevel != "city") ? nil : city?.autoid /// startAnimating self._anim?.startAnimating() /// 发送请求 goodsManager.requestQueryTopGoods(goodsManager.getMarketIDs(.TRADEMODE_LISTING_SELECT), descProvinceID, descCityID) { (isComplete, error, topGoods) in DispatchQueue.main.async { /// stopAnimating self._anim?.stopAnimating() /// endRefreshing self.collectionView.endRefreshing() if isComplete { /// 数据获取成功 self.goods = topGoods ?? [] } else { self.goods = [] /// toast WHToast.showError(withMessage: "数据获取失败,原因:\(error?.retMsg ?? "未知错误")", duration: 1.0, finishHandler: {}) } } } } // MARK: - 交互相关 /// onButtonPressed /// - Parameter sender: sender @IBAction fileprivate func onButtonPressed(_ sender: UIButton) { switch sender { case location: /// 位置 let geographicPickView = GeographicPickView(nibName: "GeographicPickView", bundle: nil) geographicPickView.modalTransitionStyle = .coverVertical geographicPickView.modalPresentationStyle = .overFullScreen geographicPickView.callback = { (_ takeInfo: MoGeographic?, _ isSure: Bool) in self.city = takeInfo } self.present(geographicPickView, animated: true, completion: {}) default: break } } // MARK: - 订阅行情相关 var uuid: String = UUID().uuidString var shouldSubscriptGoodsCodes: Set? { didSet { guard let quoteSubscriptManager = MTP2BusinessCore.shared.quoteSubscriptManager else { return } quoteSubscriptManager.updateQuoteSubcriptGoods(uuid: uuid, goodsCode: shouldSubscriptGoodsCodes ?? []) } } var visibleGoodsCodes: Set { var goodsCodes = Set() self.collectionView.visibleCells.forEach { (cell) in if let quoteCell = cell as? GoodsCell, let goodsCode = quoteCell.model?.goodscode { goodsCodes.insert(goodsCode) } } return goodsCodes } // 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. if segue.identifier == "ShowGoodsDetail" { /// 商品详情 (segue.destination as? GoodsDetailViewController)?.model = (sender as? GoodsCell)?.model } } } // MARK: - UIScrollViewDelegate extension HotQuoteViewController: UIScrollViewDelegate { func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { if visibleGoodsCodes.count != 0 { shouldSubscriptGoodsCodes = visibleGoodsCodes } } } // MARK: - UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout extension HotQuoteViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.goods.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GoodsCellIdentifier, for: indexPath) as! GoodsCell cell.model = self.goods[indexPath.item] return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: collectionView.width/2, height: ((collectionView.width/2)*0.9)+80.0) } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { } }