| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- //
- // QuoteViewController.swift
- // MTP2_iOS
- //
- // Created by zhongyuan on 2018/4/3.
- // Copyright © 2018年 zhongyuan.All rights reserved.
- //
- import UIKit
- import GTMRefresh
- import JXSegmentedView
- import WHToast
- /// 期货商品行情报价列表视图容器控制类
- class QuoteViewController: BaseTableViewController<QuoteModel>, QuoteSubscriptDelete {
-
- // MARK: - 属性列表
- /// 类目
- @IBOutlet weak var segmentedView: JXSegmentedView! {
- didSet {
- segmentedView.dataSource = subDataSource
- segmentedView.indicators = [backgroundIndicator]
- segmentedView.delegate = self
- }
- }
-
- /// 数据显示列表
- @IBOutlet weak var tableView: UITableView!
- /// 涨跌按钮
- @IBOutlet weak var riseButton: UIButton!
- /// 持仓量按钮
- @IBOutlet weak var volumnButton: UIButton!
- /// 无数据按钮
- @IBOutlet weak var dataButton: UIButton! {
- didSet {
- dataButton.set(image: UIImage.getImage(name: "noData-universal"), title: "没有查询记录", titlePosition: .bottom, additionalSpacing: 5.0, state: .normal)
- dataButton.tintColor = .hex999()
- dataButton.isHidden = true
- }
- }
- /// 所属市场
- var marketID: Int = Int.max {
- didSet {
- /// 构建行情列表
- self.buildQuoteModels()
- }
- }
- /// 外部交易市场
- var exchanges: [MoExternalExchange] = []
-
- // MARK: - 生命周期相关
- override func viewDidLoad() {
- super.viewDidLoad()
-
- /// loding...
- addLoadingView()
- /// cellReuseIdentifier
- cellReuseIdentifier = "Quote_Cell"
- /// 构建外部交易市场
- buildExternalExchanges()
- /// 添加下拉刷新控件
- tableView.gtm_addRefreshHeaderView(refreshHeader: DefaultGTMRefreshHeader()) { [weak self] in
- if self?.segmentedView.selectedIndex == 0 { /// 自选
- self?.buildMyFavoriteGoods()
- } else if self?.segmentedView.selectedIndex == 1 { /// 主力
- self?.buildGoodsSortByPosition()
- } else {
- /// 请求数据
- self?.buildQuoteModels()
- }
- }
- }
-
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
- /// 清除广播侦听
- MTP2BusinessCore.shared.broadcastManager?.removeBroadcastListener(owner: self)
- }
-
- override func viewDidAppear(_ animated: Bool) {
- super.viewDidAppear(animated)
- /// 初始化广播侦听
- initListen()
- }
-
- /// 初始化广播侦听
- func initListen() {
- /// 侦听行情推送广播
- MTP2BusinessCore.shared.broadcastManager?.addBroadcastListener(owner: self, action: .ReceiveTradeQuote) { [weak self] in
- guard let quoteGoodsInfos = $0.object as? [(goodsHqCode: String, exchHqCode: String)],
- let goodsManager = MTP2BusinessCore.shared.goodsManager,
- let weakSelf = self else { return }
- /// 有数据
- if quoteGoodsInfos.count != 0 {
- /// 待刷新行
- for (index, quoteModel) in weakSelf.tableCellModels.enumerated() {
- if quoteGoodsInfos.first(where: { $0.goodsHqCode == quoteModel.outgoodscode }) != nil {
- let indexPath = IndexPath(row: index, section: 0)
- /// 更新显示行情数据
- guard let moGoodsInfo = goodsManager.goodsInfos?.first(where: { $0.goodscode == quoteModel.goodscode }) else { continue }
- if quoteModel.last != moGoodsInfo.moQuoteInfo?.last {
- quoteModel.update(moGoodsInfo: moGoodsInfo)
- DispatchQueue.main.async {
- /// 判断是否在可见区域
- if weakSelf.tableView.indexPathsForVisibleRows?.firstIndex(of: indexPath) != nil {
- weakSelf.tableView.reloadRows(at: [indexPath], with: .none)
- }
- }
- }
- }
- }
- }
- }
- }
-
- // MARK: - 数据初始化
- /// 构建外部交易市场
- fileprivate func buildExternalExchanges() {
- /// 加载资管外部交易市场
- guard let goodsManager = MTP2BusinessCore.shared.goodsManager,
- let externals = goodsManager.exchanges?.filter({$0.goodsGroups.count != 0}),
- externals.count != 0 else {
- return
- }
- /// 外部交易市场
- exchanges = externals
- /// subDataSource
- subDataSource.titles = externals.map({ (obj) -> String in
- return obj.exexchangename
- })
- subDataSource.titles.insert(contentsOf: ["自选", "主力"], at: 0)
- /// 默认选中
- segmentedView.defaultSelectedIndex = 1
- segmentedView.reloadData()
- segmentedView.delegate?.segmentedView(segmentedView, didSelectedItemAt: 1)
- }
-
- // MARK: - 行情相关
- /// 构建行情
- fileprivate func buildQuoteModels() {
- /// 获取当前外部交易市场下的所有商品组的商品信息
- guard let goodsManager = MTP2BusinessCore.shared.goodsManager,
- let exchange = goodsManager.getMoExternalExchange(autoID: marketID) else { return }
-
- /// 显示外部交易所下面商品组的商品信息
- var showGoodsInfos: [MoGoodsInfo] = []
- if let goodsInfos = goodsManager.goodsInfos {
- for obj in exchange.goodsGroups {
- let desGoodsInfos = goodsInfos.filter { $0.goodsgroupid == obj.goodsgroupid }
- showGoodsInfos.append(contentsOf: desGoodsInfos)
- }
-
- /// endRefreshing
- tableView.endRefreshing()
- /// 移出所有数据
- tableCellModels.removeAll()
- /// 构建数据
- showGoodsInfos.forEach {
- tableCellModels.append(QuoteModel(moGoodsInfo: $0, rise: false, volumn: 0))
- }
- /// 刷新数据
- tableView.reloadData()
- /// 无数据按钮
- dataButton.isHidden = tableCellModels.count != 0
-
- if tableCellModels.count > 0 {
- /// 等待UI操作完成,也就是tableView刷新完之后执行
- DispatchQueue.main.async { [weak self] in
- if self?.visibleGoodsCodes.count != 0 {
- self?.shouldSubscriptGoodsCodes = self?.visibleGoodsCodes
- }
- }
- }
- }
- }
-
- /// 构建我的自选商品信息
- fileprivate func buildMyFavoriteGoods() {
- /// 获取当前外部交易市场下的所有商品组的商品信息
- guard let goodsManager = MTP2BusinessCore.shared.goodsManager,
- let goodsInfos = goodsManager.goodsInfos else { return }
-
- /// startAnimating
- _anim?.startAnimating()
- /// 查询我得收藏商品
- goodsManager.queryUserFavoriteGoodses { (isSuccess, error, ids) in
- DispatchQueue.main.async {
- /// endRefreshing
- self.tableView.endRefreshing()
- /// stopAnimating
- self._anim?.stopAnimating()
-
- /// 查询失败
- if !isSuccess {
- /// 为空
- self.tableCellModels = []
- /// 刷新数据
- self.tableView.reloadData()
- /// 无数据按钮
- self.dataButton.isHidden = self.tableCellModels.count != 0
- /// show error
- WHToast.showMessage("自选获取失败", duration: ToastTimer, finishHandler: {})
- return
- }
- /// 行情显示数据
- var objs: [QuoteModel] = []
- if let goodsids = ids, goodsids.count != 0 {
- goodsids.forEach { (id) in
- if let goodsInfo = goodsInfos.first(where: {$0.goodsid == id}) {
- objs.append(QuoteModel(moGoodsInfo: goodsInfo, rise: false, volumn: 0))
- }
- }
- }
- self.tableCellModels = objs
- /// 刷新数据
- self.tableView.reloadData()
- /// 无数据按钮
- self.dataButton.isHidden = self.tableCellModels.count != 0
- /// 等待UI操作完成,也就是tableView刷新完之后执行
- if self.tableCellModels.count > 0 {
- DispatchQueue.main.async { [weak self] in
- if self?.visibleGoodsCodes.count != 0 { self?.shouldSubscriptGoodsCodes = self?.visibleGoodsCodes }
- }
- }
- }
- }
- }
-
- /// 获取主力合约商品信息
- fileprivate func buildGoodsSortByPosition() {
- /// 获取当前外部交易市场下的所有商品组的商品信息
- guard let goodsManager = MTP2BusinessCore.shared.goodsManager,
- let goodsInfos = goodsManager.goodsInfos else { return }
- /// endRefreshing
- tableView.endRefreshing()
- /// 行情显示数据
- var objs: [QuoteModel] = []
- let infos = goodsManager.sortByPositions
- if infos.count != 0 {
- infos.forEach { (id) in
- if let goodsInfo = goodsInfos.first(where: {$0.goodscode == id.goodscode}) {
- goodsInfo.ismian = true
- objs.append(QuoteModel(moGoodsInfo: goodsInfo, rise: false, volumn: 0))
- }
- }
- }
- tableCellModels = objs
- /// 刷新数据
- tableView.reloadData()
- /// 无数据按钮
- dataButton.isHidden = self.tableCellModels.count != 0
- /// 等待UI操作完成,也就是tableView刷新完之后执行
- if tableCellModels.count > 0 {
- DispatchQueue.main.async { [weak self] in
- if self?.visibleGoodsCodes.count != 0 {
- self?.shouldSubscriptGoodsCodes = self?.visibleGoodsCodes
- }
- }
- }
- }
-
- // MARK: - 交互相关
- /// onButtonPressed
- /// - Parameter sender: sender
- @IBAction func onButtonPressed(_ sender: UIButton) {}
-
- // MARK: - 订阅行情相关
- var uuid: String = UUID().uuidString
- var shouldSubscriptGoodsCodes: Set<String>? {
- didSet {
- guard let quoteSubscriptManager = MTP2BusinessCore.shared.quoteSubscriptManager else { return }
- quoteSubscriptManager.updateQuoteSubcriptGoods(uuid: uuid, goodsCode: shouldSubscriptGoodsCodes ?? [])
- }
- }
- var visibleGoodsCodes: Set<String> {
- var goodsCodes = Set<String>()
- self.tableView.visibleCells.forEach { (cell) in
- if let quoteCell = cell as? QuoteCell,
- let goodsCode = quoteCell.model?.outgoodscode {
- goodsCodes.insert(goodsCode)
- }
- }
- return goodsCodes
- }
-
- // MARK: - UIScrollViewDelegate
- override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
- if visibleGoodsCodes.count != 0 {
- shouldSubscriptGoodsCodes = visibleGoodsCodes
- }
- }
-
- override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return 60.0
- }
-
- // 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 == "ShowATPTrade", let t = segue.destination as? ATPTradeViewController, let goodsid = (sender as? QuoteCell)?.model?.goodsid { /// 交易下单
- t.moGoodsInfo = MTP2BusinessCore.shared.goodsManager?.goodsInfos?.first(where: {$0.goodsid == goodsid})
- } else if segue.identifier == "ShowChart", let c = segue.destination as? ChartViewController, let goodsid = (sender as? QuoteCell)?.model?.goodsid { /// 图表
- c.moGoodsInfo = MTP2BusinessCore.shared.goodsManager?.goodsInfos?.first(where: {$0.goodsid == goodsid})
- }
- }
- }
- // MARK: - JXSegmentedViewDelegate
- extension QuoteViewController: JXSegmentedViewDelegate {
- func segmentedView(_ segmentedView: JXSegmentedView, didSelectedItemAt index: Int) {
- if index == 0 { /// 自选
- buildMyFavoriteGoods()
- } else if index == 1 { /// 主力
- buildGoodsSortByPosition()
- } else {
- marketID = exchanges[index-2].autoid
- }
- }
- }
- // MARK: - 行情报价牌Cell
- class QuoteCell: BaseTableViewCell<QuoteModel> {
- /// 商品名称
- @IBOutlet weak var goodsName: UILabel!
- /// 商品代码
- @IBOutlet weak var goodsCode: UILabel!
- /// 最新价
- @IBOutlet weak var last: UILabel!
- /// 涨跌
- @IBOutlet weak var increase: UILabel!
- /// 最低
- @IBOutlet weak var lowest: UILabel!
- /// 交易所标识
- @IBOutlet weak var flag: UILabel!
- /// 自选按钮
- @IBOutlet weak var favorit: UIButton!
- /// 最新价视图
- @IBOutlet weak var lastBgView: UIView!
-
- /// 是否是自选
- fileprivate var isSelfGoods = false {
- didSet {
- /// 图标
- favorit.setImage(UIImage(named: isSelfGoods ? "favorited" : "unfavorited"), for: .normal)
- }
- }
-
- override var model: QuoteModel? {
- didSet {
- if let obj = model {
- /// 商品名称
- goodsName.text = obj.goodsname
- /// 商品代码
- goodsCode.text = obj.outgoodscode
- /// 最新价
- last.text = (obj.last != nil && obj.last != 0.0) ? String(format: "%.\(obj.decimalplace)f", obj.last!) : "--"
-
- /// 自选商品
- isSelfGoods = MTP2BusinessCore.shared.goodsManager?.favGoodsIds?.contains(where: {$0 == obj.goodsid}) ?? false
- /// 涨跌值
- increase.text = obj.last == 0.0 ? "--" : "\(((obj.last ?? 0.0 )-obj.preSettle).toUpString(place: obj.decimalplace))"
-
- /// 持仓量 最低 最高 为0 则显示--
- let high = Double(obj.highest ?? "0.0") == 0.0 ? "--" : obj.highest?.isBlank()
- let low = Double(obj.lowest ?? "0.0") == 0.0 ? "--" : obj.lowest?.isBlank()
- let totalVolumn = obj.totalVolumn ?? "--"
- lowest.text = obj.volumn == 0 ? totalVolumn : (obj.volumn == 1 ? high : low)
-
- /// 昨结颜色
- if obj.preColorFlag == 1 {
- last.textColor = Color_Quote_Up
- increase.textColor = Color_Quote_Up
- lowest.textColor = Color_Quote_Up
- } else if obj.preColorFlag == -1 {
- last.textColor = Color_Quote_Down
- increase.textColor = Color_Quote_Down
- lowest.textColor = Color_Quote_Up
- } else {
- last.textColor = Color_Quote_Normal
- increase.textColor = Color_Quote_Normal
- lowest.textColor = Color_Quote_Up
- }
-
- /// 涨跌颜色
- if obj.colorFlag == 1 {
- lastBgView.backgroundColor = .fromHex(rgbValue: 0xFFEAEC)
- } else if obj.colorFlag == -1 {
- lastBgView.backgroundColor = .fromHex(rgbValue: 0xDDFFF4)
- } else {
- lastBgView.backgroundColor = .white
- }
-
- /// 获取标志
- guard let goodsManager = MTP2BusinessCore.shared.goodsManager,
- let goodsGroup = goodsManager.goodsGroups?.first(where: {$0.goodsgroupid == obj.goodsgroupid}),
- let exchange = goodsManager.exchanges?.first(where: {$0.autoid == goodsGroup.exexchangeid}) else {
- return
- }
- flag.text = exchange.exexchangecode.getExchangeCodeVerb()
- }
- }
- }
-
- @IBAction fileprivate func onButtonPressed(_ sender: UIButton) {
- switch sender {
- case favorit:
- /// 异常
- guard let goodsManager = MTP2BusinessCore.shared.goodsManager,
- let goodsid = model?.goodsid else {
- return
- }
-
- /// 判断是否为自选
- if isSelfGoods {
- /// 删自选
- goodsManager.requestRemoveUserFavoriteGoods(goodsID: goodsid, callback: { (isSuccess, _) in
- DispatchQueue.main.async {
- self.isSelfGoods = !isSuccess
- }
- })
- } else { /// 加自选
- goodsManager.requestAddUserFavoriteGoods(goodsID: goodsid, callback: { (isSuccess, _) in
- DispatchQueue.main.async {
- self.isSelfGoods = isSuccess
- }
- })
- }
- default: break
- }
- }
- }
- // MARK: - 行情显示模型
- class QuoteModel {
- /// 商品ID
- var goodsid: Int = 0
- /// 商品名称
- var goodsname: String
- /// 商品代码
- var goodscode: String
- /// 外部商品代码
- var outgoodscode: String
- /// 最新价
- var last: Double?
- /// 成交量
- var totalVolumn: String?
- /// 最低
- var lowest: String?
- /// 最高
- var highest: String?
- /// 小数位
- var decimalplace: Int = 0
- /// 颜色标识
- var colorFlag: Int = 0
- /// 昨收颜色标识
- var preColorFlag: Int = 0
- /// 商品组ID
- var goodsgroupid: Int = 0
- /// 涨跌变量
- var rise: Bool = false
- /// 持仓量变量
- var volumn: Int = 0
- /// 昨结算
- var preSettle: Double = 0.0
-
- init(goodsid: Int = 0,
- goodscode: String,
- goodsname: String,
- outgoodscode: String) {
- self.goodscode = goodscode
- self.goodsname = goodsname
- self.goodsid = goodsid
- self.outgoodscode = outgoodscode
- }
-
- init(moGoodsInfo: MoGoodsInfo) {
- self.goodscode = moGoodsInfo.goodscode
- self.goodsname = moGoodsInfo.goodsname
- self.decimalplace = moGoodsInfo.decimalplace
- self.goodsgroupid = moGoodsInfo.goodsgroupid
- self.goodsid = moGoodsInfo.goodsid
- self.outgoodscode = moGoodsInfo.outgoodscode
- /// 更新行情信息
- self.update(moGoodsInfo: moGoodsInfo)
- }
-
- init(moGoodsInfo: MoGoodsInfo,
- rise: Bool = false,
- volumn: Int = 0) {
- self.goodscode = moGoodsInfo.goodscode
- self.goodsname = moGoodsInfo.goodsname
- self.decimalplace = moGoodsInfo.decimalplace
- self.goodsgroupid = moGoodsInfo.goodsgroupid
- self.rise = rise
- self.volumn = volumn
- self.goodsid = moGoodsInfo.goodsid
- self.outgoodscode = moGoodsInfo.outgoodscode
- /// 更新行情信息
- self.update(moGoodsInfo: moGoodsInfo)
- }
-
- func update(moGoodsInfo: MoGoodsInfo) {
- /// 行情相关字段赋值
- if let quote = moGoodsInfo.moQuoteInfo {
- /// 最新价
- self.last = quote.last
- /// 成交量
- self.totalVolumn = Double(moGoodsInfo.moQuoteInfo?.totalVolume ?? 0).getTotalTurnoverString(reserve: 2).isBlank()
- /// 颜色
- let preColorFlag = quote.last.compare(settle: moGoodsInfo.getPreClose())
- /// 昨收颜色标识
- self.preColorFlag = preColorFlag
- /// 昨结算
- self.preSettle = quote.presettle
- }
-
- /// 颜色值
- self.colorFlag = moGoodsInfo.colorFlag
- /// 最低价
- self.lowest = moGoodsInfo.moQuoteInfo?.lowest.toUpString(place: moGoodsInfo.decimalplace).isBlank()
- /// 最高价
- self.highest = moGoodsInfo.moQuoteInfo?.highest.toUpString(place: moGoodsInfo.decimalplace).isBlank()
- }
- }
|