HomeViewController.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. //
  2. // HomeViewController.swift
  3. // MTP2_iOS
  4. //
  5. // Created by Handy_Cao on 2020/10/23.
  6. // Copyright © 2020 Muchinfo. All rights reserved.
  7. //
  8. import UIKit
  9. import SDCycleScrollView
  10. import SafariServices
  11. import SDWebImage
  12. import SwiftyAttributes
  13. import WHToast
  14. import GTMRefresh
  15. import WebKit
  16. /// 首页视图容器管理类
  17. class HomeViewController: BaseViewController {
  18. // MARK: - 属性列表
  19. /// 系统设置
  20. @IBOutlet weak var settings: UIButton!
  21. /// 新卡抢购
  22. @IBOutlet weak var xkqg: UIButton!
  23. /// 热卖专区
  24. @IBOutlet weak var rmzq: UIButton!
  25. /// 我的订单
  26. @IBOutlet weak var wddd: UIButton!
  27. /// 海南网警
  28. @IBOutlet weak var police: UIButton!
  29. /// 海拔资讯
  30. @IBOutlet weak var hbzx: UIButton!
  31. /// 海拔资讯
  32. @IBOutlet weak var hbzxStackView: UIStackView!
  33. /// 我的卡包
  34. @IBOutlet weak var wdkb: UIButton!
  35. /// 主滚动视图
  36. @IBOutlet weak var scrollView: UIScrollView!
  37. /// 操作视图
  38. @IBOutlet weak var operationView: UIView!
  39. /// 图片轮播图
  40. @IBOutlet weak var bannerView: SDCycleScrollView! {
  41. didSet {
  42. bannerView.bannerImageViewContentMode = .scaleAspectFill
  43. bannerView.autoScrollTimeInterval = 5.0
  44. bannerView.autoScroll = true
  45. bannerView.infiniteLoop = true
  46. bannerView.scrollDirection = .horizontal
  47. bannerView.layer.masksToBounds = true
  48. bannerView.layer.cornerRadius = 10.0
  49. bannerView.delegate = self
  50. }
  51. }
  52. /// 商品数据集合视图
  53. @IBOutlet weak var collectionView: UICollectionView! {
  54. didSet {
  55. if collectionView.responds(to: #selector(setter: UICollectionView.isPrefetchingEnabled)) {
  56. collectionView.isPrefetchingEnabled = false
  57. }
  58. /// 设置约束
  59. collectionView.setCollectionViewLayout(flowLayout, animated: true)
  60. }
  61. }
  62. /// 商品数据列表高度
  63. @IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!
  64. /// 搜索框
  65. @IBOutlet weak var searchBar: UIButton!
  66. /// 数据显示集合视图约束
  67. lazy var flowLayout: UICollectionViewFlowLayout = {
  68. /// 最小行间距,默认是0
  69. $0.minimumLineSpacing = 0
  70. /// 最小左右间距,默认是10
  71. $0.minimumInteritemSpacing = 0
  72. /// 区域内间距,默认是 UIEdgeInsetsMake(0, 0, 0, 0)
  73. $0.sectionInset = UIEdgeInsets(top: 0.0, left: 0, bottom: 0, right: 0)
  74. /// 水平滚动
  75. $0.scrollDirection = .vertical
  76. return $0
  77. } (UICollectionViewFlowLayout())
  78. /// 轮播图数据
  79. var configs: [MoImageConfigs] = []
  80. /// 商品数据信息
  81. var goods: [MoGoodsInfo] = [] {
  82. didSet {
  83. /// 刷新数据
  84. self.collectionView.reloadData()
  85. /// 设置约束
  86. collectionViewHeightConstraint.constant = CGFloat((goods.count%2 == 0) ? (goods.count/2) : (goods.count/2+1))*(((collectionView.width/2)*0.9)+80.0)
  87. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.5, execute: {
  88. if self.goods.count > 0 {
  89. /// 等待UI操作完成,也就是tableView刷新完之后执行
  90. DispatchQueue.main.async { [weak self] in
  91. if self?.visibleGoodsCodes.count != 0 { self?.shouldSubscriptGoodsCodes = self?.visibleGoodsCodes }
  92. }
  93. }
  94. })
  95. }
  96. }
  97. /// GoodsCellIdentifier
  98. let GoodsCellIdentifier = "Goods_Cell"
  99. // MARK: - 生命周期
  100. required init?(coder aDecoder: NSCoder) {
  101. super.init(coder: aDecoder)
  102. /// 设置TabBar图片
  103. self.tabBarItem.image = UIImage(named: "home_normal")?.withRenderingMode(.alwaysOriginal)
  104. self.tabBarItem.selectedImage = UIImage(named: "home_selected")?.withRenderingMode(.alwaysOriginal)
  105. }
  106. override func viewWillAppear(_ animated: Bool) {
  107. super.viewWillAppear(animated)
  108. /// 隐藏导航栏
  109. self.navigationController?.setNavigationBarHidden(true, animated: true)
  110. /// 行情侦听
  111. initListen()
  112. }
  113. override func viewDidDisappear(_ animated: Bool) {
  114. super.viewDidDisappear(animated)
  115. /// 清除广播侦听
  116. MTP2BusinessCore.shared.broadcastManager?.removeBroadcastListener(owner: self, forName: .ReceiveTradeQuote)
  117. }
  118. override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
  119. super.viewWillTransition(to: size, with: coordinator)
  120. }
  121. override func viewDidLoad() {
  122. super.viewDidLoad()
  123. // Do any additional setup after loading the view.
  124. /// 不需要返回按钮
  125. addBackBarButtonItem(true)
  126. /// UI界面初始化
  127. buildView()
  128. /// 数据初始化
  129. initData()
  130. }
  131. // MARK: - 行情初始化
  132. /// 行情监听
  133. fileprivate func initListen() {
  134. if goods.count > 0 {
  135. /// 等待UI操作完成,也就是tableView刷新完之后执行
  136. DispatchQueue.main.async { [weak self] in
  137. if self?.visibleGoodsCodes.count != 0 { self?.shouldSubscriptGoodsCodes = self?.visibleGoodsCodes }
  138. }
  139. }
  140. /// 侦听行情推送广播
  141. MTP2BusinessCore.shared.broadcastManager?.addBroadcastListener(owner: self, action: .ReceiveTradeQuote) { [weak self] in
  142. guard let quoteGoodsInfos = $0.object as? [(goodsHqCode: String, exchHqCode: String)],
  143. let weakSelf = self else { return }
  144. /// 有数据
  145. if quoteGoodsInfos.count != 0 {
  146. /// 待刷新行
  147. var refreshIndexPaths = [IndexPath]()
  148. DispatchQueue.main.async {
  149. for (index, cell) in weakSelf.collectionView.visibleCells.enumerated() {
  150. if quoteGoodsInfos.first(where: { $0.goodsHqCode == (cell as? GoodsCell)?.model?.goodscode }) != nil {
  151. let indexPath = IndexPath(row: index, section: 0)
  152. if refreshIndexPaths.firstIndex(of: indexPath) == nil {
  153. /// 记录待刷新行
  154. /// 判断是否在可见区域
  155. if weakSelf.collectionView.indexPathsForVisibleItems.firstIndex(of: indexPath) != nil {
  156. refreshIndexPaths.append(indexPath)
  157. }
  158. }
  159. }
  160. }
  161. }
  162. /// 刷新行情列表
  163. if refreshIndexPaths.count > 0 {
  164. DispatchQueue.main.async {
  165. weakSelf.collectionView.reloadItems(at: refreshIndexPaths)
  166. }
  167. }
  168. }
  169. }
  170. }
  171. // MARK: - 初始化
  172. /// UI界面初始化
  173. fileprivate func buildView() {
  174. /// addLoadingView
  175. self.addLoadingView()
  176. /// 添加下拉刷新控件
  177. self.scrollView.gtm_addRefreshHeaderView(refreshHeader: DefaultGTMRefreshHeader()) {
  178. if let _ = UserDefaultsUtils.addressInfo() {
  179. /// 重置请求条件
  180. self.requestHomePageDatas()
  181. } else {
  182. /// 游客登录
  183. /// startAnimating
  184. self._anim?.startAnimating()
  185. /// 查询未登录前的相关信息
  186. MTP2BusinessCore.shared.requestCommonDatas { (_) in
  187. DispatchQueue.main.async {
  188. /// stopAnimating
  189. self._anim?.stopAnimating()
  190. /// 获取首页相关数据
  191. self.requestHomePageDatas()
  192. }
  193. }
  194. }
  195. }
  196. }
  197. /// 数据初始化
  198. fileprivate func initData() {
  199. /// 当前登录了
  200. if let _ = MTP2BusinessCore.shared.accountManager?.loginRsp {
  201. /// 获取首页相关数据
  202. self.requestHomePageDatas()
  203. } else {
  204. /// 游客登录
  205. /// startAnimating
  206. self._anim?.startAnimating()
  207. /// 查询未登录前的相关信息
  208. MTP2BusinessCore.shared.requestCommonDatas { (_) in
  209. DispatchQueue.main.async {
  210. /// stopAnimating
  211. self._anim?.stopAnimating()
  212. /// 获取首页相关数据
  213. self.requestHomePageDatas()
  214. }
  215. }
  216. }
  217. }
  218. // MARK: - 按钮交互
  219. /// 按钮相应点击事件方法
  220. /// - Parameter sender: sender
  221. @IBAction fileprivate func onButtonPressed(_ sender: UIButton) {
  222. switch sender {
  223. case settings: /// 系统设置
  224. self.push(storyboardName: "Settings", storyboardId: "Settings", checkLogin: false)
  225. case rmzq,
  226. xkqg: /// 热卖专区 新卡抢购
  227. guard let main = self.appDelegate.window?.rootViewController as? MainViewController,
  228. let quoteController = (main.viewControllers?[1] as? BaseNavigationController)?.viewControllers[0] as? QuoteViewController else { return }
  229. main.selectedIndex = 1
  230. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.4) {
  231. /// 选中
  232. quoteController.segmentedView.defaultSelectedIndex = (sender == self.rmzq ? 0 : 1)
  233. quoteController.segmentedView.reloadData()
  234. quoteController.segmentedView.delegate?.segmentedView(quoteController.segmentedView, didSelectedItemAt: sender == self.rmzq ? 0 : 1)
  235. }
  236. case hbzx: /// 海拔资讯
  237. let auth = UIStoryboard(name: "Settings", bundle: nil).instantiateViewController(withIdentifier: "Auth") as! AuthAddressViewController
  238. auth.title = "海拔资讯"
  239. auth.url = MTP2BusinessCore.shared.address?.newsUrl ?? ""
  240. self.navigationController?.pushViewController(auth, animated: true)
  241. case wddd: /// 我的订单
  242. self.push(storyboardName: "Order", storyboardId: "Order")
  243. case wdkb: /// 我的商品
  244. self.push(storyboardName: "Quote", storyboardId: "MyGoods")
  245. case police: /// 海南网警
  246. push(storyboardName: "Feedback", storyboardId: "Feedback")
  247. case searchBar: /// 跳转到检索页面
  248. push(storyboardName: "Quote", storyboardId: "Search", checkLogin: false)
  249. default:
  250. break
  251. }
  252. }
  253. // MARK: - 接口请求
  254. /// 查询首页数据信息
  255. fileprivate func requestHomePageDatas() {
  256. /// 异常
  257. guard let goodsManager = MTP2BusinessCore.shared.goodsManager,
  258. let noticeManager = MTP2BusinessCore.shared.noticeManager else {
  259. return
  260. }
  261. let group = DispatchGroup()
  262. /// startAnimating
  263. self._anim?.startAnimating()
  264. var hotGoods: [MoGoodsInfo] = []
  265. /// 已登录
  266. if MTP2BusinessCore.shared.getLoginStatus() {
  267. /// 资金账号
  268. let accountID = MTP2BusinessCore.shared.accountManager?.getCurrentTAAccountInfo()?.accountId ?? 0
  269. /// 获取商城商品数据
  270. group.enter()
  271. goodsManager.requestQueryHsbyMarketGoodses(goodsManager.getMarketIDs(.TRADEMODE_TRADEMODE_HSBY_SHOP), accountID, nil, nil, nil) { (isComplete, error, marketGoodses) in
  272. hotGoods.append(contentsOf: marketGoodses ?? [])
  273. group.leave()
  274. }
  275. } else {
  276. /// 获取商城商品数据
  277. group.enter()
  278. goodsManager.requestQueryHsbyVisitorMarketGoodses(goodsManager.getMarketIDs(.TRADEMODE_TRADEMODE_HSBY_SHOP), nil, nil, nil) { (isComplete, error, marketGoodses) in
  279. hotGoods.append(contentsOf: marketGoodses ?? [])
  280. group.leave()
  281. }
  282. }
  283. /// 获取热门商品
  284. group.enter()
  285. goodsManager.requestQueryTopGoods(goodsManager.getMarketIDs(.TRADEMODE_LISTING_SELECT), nil, nil) { (isComplete, error, topGoods) in
  286. hotGoods.append(contentsOf: topGoods ?? [])
  287. group.leave()
  288. }
  289. /// 发送请求
  290. group.enter()
  291. /// 查询轮播图
  292. noticeManager.requestQueryImageConfigs { (isComplete, error, imageConfigs) in
  293. self.configs = imageConfigs?.filter({$0.isshow == 1}) ?? []
  294. group.leave()
  295. }
  296. var notices: [MoNotice] = []
  297. group.enter()
  298. /// 查询未读公告消息
  299. noticeManager.requestNotices(nil, nil, nil, true) { (isComplete, error, messages) in
  300. notices = messages ?? []
  301. group.leave()
  302. }
  303. group.notify(queue: DispatchQueue.main) {
  304. /// stopAnimating
  305. self._anim?.stopAnimating()
  306. /// endRefreshing
  307. self.scrollView.endRefreshing()
  308. /// 热门商品数据
  309. self.goods = hotGoods.sorted(by: { (obj1, obj2) -> Bool in
  310. return obj1.hotindex>obj2.hotindex
  311. })
  312. /// 轮播图相关
  313. if self.configs.count != 0 {
  314. let paths = self.configs.map({ (model) -> String in
  315. let managerUrl = MTP2BusinessCore.shared.address?.openApiUrl ?? ""
  316. let url = managerUrl+NSString(string: model.imagepath).replacingOccurrences(of: "./", with: "/")
  317. return url
  318. })
  319. self.bannerView.imageURLStringsGroup = paths
  320. }
  321. /// 更新成功
  322. if notices.contains(where: {$0.readed == false}) {
  323. self.showAlertController(title: "提示", message: "有新的未读消息公告,是否前去查看", cancelTitle: "取消", sureTitle: "去查看", cancelBlock: {}) {
  324. /// 跳转到公告消息页面
  325. (self.appDelegate.window?.rootViewController as? MainViewController)?.selectedIndex = 2
  326. }
  327. }
  328. /// 新闻地址信息
  329. if let url = MTP2BusinessCore.shared.address?.newsUrl,
  330. url != "" {
  331. self.hbzxStackView.isHidden = false
  332. } else {
  333. self.hbzxStackView.isHidden = true
  334. }
  335. }
  336. }
  337. // MARK: - 订阅行情相关
  338. var uuid: String = UUID().uuidString
  339. var shouldSubscriptGoodsCodes: Set<String>? {
  340. didSet {
  341. guard let quoteSubscriptManager = MTP2BusinessCore.shared.quoteSubscriptManager else { return }
  342. quoteSubscriptManager.updateQuoteSubcriptGoods(uuid: uuid, goodsCode: shouldSubscriptGoodsCodes ?? [])
  343. }
  344. }
  345. var visibleGoodsCodes: Set<String> {
  346. var goodsCodes = Set<String>()
  347. self.collectionView.visibleCells.forEach { (cell) in
  348. if let quoteCell = cell as? GoodsCell,
  349. let goodsCode = quoteCell.model?.goodscode {
  350. goodsCodes.insert(goodsCode)
  351. }
  352. }
  353. return goodsCodes
  354. }
  355. /*
  356. // MARK: - Navigation
  357. // In a storyboard-based application, you will often want to do a little preparation before navigation
  358. override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  359. // Get the new view controller using segue.destination.
  360. // Pass the selected object to the new view controller.
  361. }
  362. */
  363. }
  364. // MARK: - SFSafariViewControllerDelegate
  365. extension HomeViewController: SFSafariViewControllerDelegate {
  366. func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
  367. controller.dismiss(animated: true, completion: {})
  368. }
  369. }
  370. // MARK: - UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
  371. extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
  372. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  373. return goods.count
  374. }
  375. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  376. let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GoodsCellIdentifier, for: indexPath) as! GoodsCell
  377. cell.model = goods[indexPath.row]
  378. return cell
  379. }
  380. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  381. return CGSize(width: collectionView.width/2, height: ((collectionView.width/2)*0.9)+80.0)
  382. }
  383. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  384. /// 商品详情
  385. let goodsDetailController = UIStoryboard(name: "Quote", bundle: nil).instantiateViewController(withIdentifier: "GoodsDetail") as! GoodsDetailViewController
  386. goodsDetailController.model = self.goods[indexPath.row]
  387. self.navigationController?.pushViewController(goodsDetailController, animated: true)
  388. }
  389. }
  390. // MARK: - SDCycleScrollViewDelegate
  391. extension HomeViewController: SDCycleScrollViewDelegate {
  392. func cycleScrollView(_ cycleScrollView: SDCycleScrollView!, didScrollTo index: Int) {}
  393. func cycleScrollView(_ cycleScrollView: SDCycleScrollView!, didSelectItemAt index: Int) {
  394. /// 广告跳转
  395. if configs[index].urltype == 1,
  396. configs[index].url != "" {
  397. let urlString = !configs[index].url.lowercased().hasPrefix("http://") ? ("http://"+configs[index].url) : configs[index].url
  398. guard let url = URL(string: urlString) else { return }
  399. let safriViewController = SFSafariViewController(url: url)
  400. safriViewController.delegate = self
  401. self.present(safriViewController, animated: true, completion: {})
  402. } else { /// 商品ID
  403. /// 异常
  404. guard let goodsManager = MTP2BusinessCore.shared.goodsManager else {
  405. return
  406. }
  407. if configs[index].trademode == ETradeMode.TRADEMODE_LISTING_SELECT,
  408. let goodsInfo = MTP2BusinessCore.shared.goodsManager?.goodsInfos.first(where: {"\($0.goodsid)" == configs[index].url}) { /// 竞价商品
  409. let goodsDetailController = UIStoryboard(name: "Quote", bundle: nil).instantiateViewController(withIdentifier: "GoodsDetail") as! GoodsDetailViewController
  410. goodsDetailController.model = goodsInfo
  411. self.navigationController?.pushViewController(goodsDetailController, animated: true)
  412. } else { /// 商城商品
  413. if MTP2BusinessCore.shared.getLoginStatus() { /// 已登录
  414. goodsManager.requestQueryHsbyMarketGoodses(goodsManager.getMarketIDs(.TRADEMODE_TRADEMODE_HSBY_SHOP), nil, MTP2BusinessCore.shared.accountManager?.getCurrentTAAccountInfo()?.accountId, configs[index].url, nil, callback: { (isComplete, error, objs) in
  415. DispatchQueue.main.async {
  416. if isComplete, let goodsInfo = objs?.first(where: {"\($0.goodsid)" == self.configs[index].url}) {
  417. let goodsDetailController = UIStoryboard(name: "Quote", bundle: nil).instantiateViewController(withIdentifier: "GoodsDetail") as! GoodsDetailViewController
  418. goodsDetailController.model = goodsInfo
  419. self.navigationController?.pushViewController(goodsDetailController, animated: true)
  420. }
  421. }
  422. })
  423. } else { /// 未登录
  424. goodsManager.requestQueryHsbyVisitorMarketGoodses(goodsManager.getMarketIDs(.TRADEMODE_TRADEMODE_HSBY_SHOP), nil, configs[index].url, nil, callback: { (isComplete, error, objs) in
  425. DispatchQueue.main.async {
  426. if isComplete, let goodsInfo = objs?.first(where: {"\($0.goodsid)" == self.configs[index].url}) {
  427. let goodsDetailController = UIStoryboard(name: "Quote", bundle: nil).instantiateViewController(withIdentifier: "GoodsDetail") as! GoodsDetailViewController
  428. goodsDetailController.model = goodsInfo
  429. self.navigationController?.pushViewController(goodsDetailController, animated: true)
  430. }
  431. }
  432. })
  433. }
  434. }
  435. }
  436. }
  437. }
  438. /// 商品数据Cell
  439. class GoodsCell: UICollectionViewCell {
  440. /// 背景图片
  441. @IBOutlet weak var image: UIImageView!
  442. /// 商品名称
  443. @IBOutlet weak var goodsName: UILabel!
  444. /// 价格
  445. @IBOutlet weak var price: UILabel!
  446. /// 数据集合
  447. var model: MoGoodsInfo? {
  448. didSet {
  449. /// 更新显示行情数据
  450. guard let obj = MTP2BusinessCore.shared.goodsManager?.goodsInfos.first(where: { $0.goodscode == model?.goodscode }) else { return }
  451. /// 商品名称
  452. goodsName.text = obj.goodsname
  453. /// 价格
  454. if obj.trademode == .TRADEMODE_LISTING_SELECT {
  455. price.attributedText = (obj.currencysign.withFont(.font_12)+" \((obj.getLast() == 0.0 ? obj.last : obj.getLast()).toDownString(reserve: obj.decimalplace))".withFont(.font_16)).withTextColor(.red)
  456. } else if obj.trademode == .TRADEMODE_TRADEMODE_HSBY_SHOP { /// 商城商品
  457. price.attributedText = (("\(obj.currencysign)".withFont(.font_12))+("\(obj.goodsprice)".withFont(.font_16))).withTextColor(.red)
  458. } else { /// 新品抢购
  459. price.attributedText = (("抢购价:\(obj.currencysign)".withFont(.font_12))+(obj.refprice.description.withFont(.font_16))).withTextColor(.red)
  460. }
  461. /// 地址异常
  462. if let url = StringUtils.getImageUrl(obj.picurls) {
  463. /// 背景图片
  464. image.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder_image"), options: .queryDiskDataSync, context: nil)
  465. }
  466. }
  467. }
  468. }