// // GoodsDetailViewController.swift // MTP2_iOS // // Created by Handy_Cao on 2020/10/30. // Copyright © 2020 Muchinfo. All rights reserved. // import UIKit import WHToast import WebKit import MediaPlayer import SwiftyAttributes import IBAnimatable /// 商品详情视图容器控制类 class GoodsDetailViewController: BaseViewController { // MARK: - 属性列表 /// 商品名称 @IBOutlet weak var goodsName: UILabel! /// 商品代码 @IBOutlet weak var goodsCode: UILabel! /// 媒体视图 @IBOutlet weak var videoView: UIView! /// 媒体视图容器控制View lazy var mediaView: TSVideoPlayback = { return $0 }(TSVideoPlayback(frame: CGRect(x: 0.0, y: 0.0, width: self.view.width, height: self.view.width*0.78))) /// 商品价格 @IBOutlet weak var price: IBLabel! /// 供应商 @IBOutlet weak var vendorname: UILabel! /// 卖家 @IBOutlet weak var customername: UILabel! /// 交易按钮 @IBOutlet weak var trade: IBButton! { didSet { trade.setTitle(MTP2BusinessCore.shared.getLoginStatus() ? "立即购买" : "未登录", for: .normal) } } /// 交易按钮 @IBOutlet weak var tradeView: AnimatableView! /// 客服按钮 @IBOutlet weak var customer: UIButton! /// 收藏按钮 @IBOutlet weak var favorite: UIButton! /// 发行单位 @IBOutlet weak var issuer: UILabel! /// 发行数量 @IBOutlet weak var preQty: UILabel! /// 日期范围 @IBOutlet weak var dateRange: UILabel! /// 网页视图用来加载商品详情信息 @IBOutlet weak var webView: WKWebView! { didSet { webView.uiDelegate = self webView.navigationDelegate = self webView.scrollView.showsVerticalScrollIndicator = false webView.scrollView.showsHorizontalScrollIndicator = false webView.scrollView.isScrollEnabled = false webView.isOpaque = false } } /// 高度约束 @IBOutlet weak var webViewLayoutConstraint: NSLayoutConstraint! /// 折线图 @IBOutlet weak var chartView: UIStackView! /// 折线图 @IBOutlet weak var lineChartView: LHYChartView! { didSet { /// 初始化视图 lineChartView.initNew() /// 是否默认选中第一个 lineChartView.isShowFirstPaoPao = false /// 是否默认选中第一个 lineChartView.isShowLastPaoPao = true /// 是否有网格 lineChartView.isGrid = true /// 是否可以浮动 lineChartView.isFloating = false /// 显示多少行 lineChartView.row = 6 /// 显示多少列 self.lineChartView.xRow = 10 /// 设置X轴坐标字体大小 lineChartView.x_Font = .font_8 /// 设置Y轴坐标字体大小 lineChartView.y_Font = .font_8 /// 设置Y轴坐标字体颜色 lineChartView.y_Color = UIColorFromHex(rgbValue: 0x4f6a8f) /// 设置X轴坐标字体颜色 lineChartView.x_Color = UIColorFromHex(rgbValue: 0x4f6a8f) /// 边框标线颜色 lineChartView.borderLineColor = UIColorFromHex(rgbValue: 0x4f6a8f) /// 设置X轴数据间隔 lineChartView.xmargin = 55 /// 设置背景颜色 lineChartView.backgroundColor = .white /// 设置泡泡的背景色 lineChartView.paopaoBackGroundColor = UIColorFromHex(rgbValue: 0x88a2bc, alpha: 1) /// 中间标线颜色 lineChartView.middleLineColor = UIColorFromHex(rgbValue: 0xffffff, alpha: 1) /// 边框三角颜色 lineChartView.borderTriangleColor = UIColorFromHex(rgbValue: 0x9f6c66) /// 设置标线颜色 lineChartView.markColor = UIColorFromHex(rgbValue: 0x9f6c66) /// 设置泡泡的标题颜色 lineChartView.paopaoTitleColor = UIColorFromHex(rgbValue: 0xffffff) /// 设置折线样式 lineChartView.chartViewStyle = .moreClickLine /// 设置图层效果 lineChartView.chartLayerStyle = .gradient /// 设置折现效果 lineChartView.lineLayerStyle = .gradient /// 渐变效果的颜色组 /// 渐变开始比例 lineChartView.proportion = 0.5; /// 折线图是否从零点开始画 lineChartView.hiddenZreo = false /// 单位 lineChartView.unitStyle = .million /// 设置颜色 lineChartView.leftColorStrArr = ["#6dd89c"]; } } /// 价格视图 @IBOutlet weak var priceView: UIImageView! /// 数据模型 var model: MoGoodsInfo? { didSet { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.3) { /// 异常 guard let obj = self.model else { return } /// 热卖商品 挂牌点选 if obj.trademode == .TRADEMODE_LISTING_SELECT { /// 不需要显示这些字段 self.issuer.removeFromSuperview() ///移出preQty self.preQty.removeFromSuperview() /// 移出dateRange self.dateRange.removeFromSuperview() /// 移出customername self.customername.removeFromSuperview() /// 查询商品详情 self.requestQueryHsbyListingGoodsDetail(obj.goodsid) /// 查询历史数据信息 self.requestHistoryDatas() /// 行情订阅 self.shouldSubscriptGoodsCodes = self.visibleGoodsCodes } else if obj.trademode == .TRADEMODE_TRADEMODE_CPTRADE_LS { /// 挂牌预售 /// 移出customername self.customername.removeFromSuperview() /// 移出视图 self.chartView.removeFromSuperview() self.requestQueryHsbyPreGoodsDetail(obj.goodsid) } else { /// 商城 /// 不需要显示这些字段 self.issuer.removeFromSuperview() ///移出preQty self.preQty.removeFromSuperview() /// 移出dateRange self.dateRange.removeFromSuperview() /// 移出视图 self.chartView.removeFromSuperview() /// 未登录不需要显示商家信息 if !MTP2BusinessCore.shared.getLoginStatus() { /// 移出customername self.customername.removeFromSuperview() } /// 查询商城商品详情信息 MTP2BusinessCore.shared.getLoginStatus() ? self.requestQueryHsbyMarketGoodsDetail(obj.orderid) : self.requestQueryHsbyVisitorMarketGoodsDetail(obj.goodsid) } } } } /// 商品详情 var goodsDetail: MoGoodsInfo? { didSet { /// 显示商品详情信息 showGoodsDetail(goodsDetail) } } /// 是否为我的收藏 var isFavorite: Bool = false { didSet { favorite.setImage(UIImage(named: isFavorite ? "favorited" : "favorite"), for: .normal) } } // MARK: - 生命周期 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. /// UI界面初始化 buildView() /// 数据初始化 initData() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) /// 隐藏导航栏 self.navigationController?.setNavigationBarHidden(true, animated: true) /// 商城商品不需要行情 if self.model?.trademode == .TRADEMODE_LISTING_SELECT { /// 侦听行情推送广播 MTP2BusinessCore.shared.broadcastManager?.addBroadcastListener(owner: self, action: .ReceiveTradeQuote) { [weak self] in guard let quoteGoodsInfos = $0.object as? [(goodsHqCode: String, exchHqCode: String)] else { return } DispatchQueue.main.async { /// 有数据 if quoteGoodsInfos.count != 0 { if quoteGoodsInfos.first(where: { $0.goodsHqCode == self?.model?.goodscode }) != nil { if let obj = MTP2BusinessCore.shared.goodsManager?.goodsInfos.first(where: {$0.goodscode == self?.model?.goodscode}), obj.trademode == .TRADEMODE_LISTING_SELECT { self?.price.attributedText = ("热卖价:\(obj.currencysign)".withFont(.font_13)+(" \((obj.getLast() == 0.0 ? obj.last : obj.getLast()).toDownString(reserve: obj.decimalplace))").withFont(.font_20)).withTextColor(.white) } } } } } } } deinit { /// 商城商品不需要行情 if self.model?.trademode == .TRADEMODE_LISTING_SELECT { /// 清除广播侦听 MTP2BusinessCore.shared.broadcastManager?.removeBroadcastListener(owner: self, forName: .ReceiveTradeQuote) } /// 清楚缓存 self.mediaView.clearCache() } // MARK: - 初始化 /// UI界面初始化 fileprivate func buildView() { /// 添加每天视图 self.videoView.addSubview(mediaView) /// loding...... addLoadingView() } /// 数据初始化 fileprivate func initData() { /// 判断是否为我的藏品 self.isFavorite = MTP2BusinessCore.shared.goodsManager?.favGoodsIds?.contains(where: {$0 == model?.goodsid}) ?? false } /// 显示商品详情信息 /// - Parameter detail: detail fileprivate func showGoodsDetail(_ detail: MoGoodsInfo?) { /// 异常 guard let obj = detail else { return } /// 商品名称 goodsName.text = obj.goodsname /// 商品代码 goodsCode.attributedText = ("商品代码 ".withTextColor(UIColorFromHex(rgbValue: 0x999999))+obj.goodscode.withTextColor(UIColorFromHex(rgbValue: 0x333333))).withFont(.font_13) /// 供应商 vendorname.attributedText = ("供 应 商 ".withTextColor(UIColorFromHex(rgbValue: 0x999999)) + obj.vendorname.withTextColor(UIColorFromHex(rgbValue: 0x333333))).withFont(.font_13) /// 价格视图 priceView.image = UIImage(named: obj.goodsstatus == 3 ? "image_blued_grident" : "image_read_grident") /// 二级市场 if obj.trademode == .TRADEMODE_LISTING_SELECT { /// 价格 price.attributedText = ("热卖价:\(obj.currencysign)".withFont(.font_13)+(" \((obj.getLast() == 0.0 ? obj.last : obj.getLast()).toDownString(reserve: obj.decimalplace))").withFont(.font_20)).withTextColor(.white) } else if obj.trademode == .TRADEMODE_TRADEMODE_HSBY_SHOP { /// 商城 /// 价格 price.attributedText = ("热卖价:\(obj.currencysign)".withFont(.font_13)+(" \(obj.goodsprice.toDownString(reserve: obj.decimalplace))").withFont(.font_20)).withTextColor(.white) /// 发行单位 if MTP2BusinessCore.shared.getLoginStatus() { customername.attributedText = ("卖 家 ".withTextColor(UIColorFromHex(rgbValue: 0x999999))+obj.customername.withTextColor(UIColorFromHex(rgbValue: 0x333333))).withFont(.font_13) } } else { /// 产能预售 /// 发行单位 issuer.attributedText = ("发行单位 ".withTextColor(UIColorFromHex(rgbValue: 0x999999))+"\(obj.customername)".withTextColor(UIColorFromHex(rgbValue: 0x333333))).withFont(.font_13) /// 发行数量 preQty.attributedText = ("发行数量 ".withTextColor(UIColorFromHex(rgbValue: 0x999999))+"\(obj.presaleqty)\(obj.goodunit)".withTextColor(UIColorFromHex(rgbValue: 0x333333))).withFont(.font_13) /// 抢购价 price.attributedText = (("抢 购 价: "+"\(obj.currencysign)").withFont(.font_13)+"\(obj.refprice)".withFont(.font_20)).withTextColor(.white) /// 日期范围 dateRange.attributedText = ("抢购日期 ".withTextColor(UIColorFromHex(rgbValue: 0x999999))+"\(DateUtils.getTDateString(obj.listingdate, "yyyy/MM/dd")) 至 \(DateUtils.getTDateString(obj.lasttradedate, "yyyy/MM/dd"))".withTextColor(UIColorFromHex(rgbValue: 0x333333))).withFont(.font_13) /// 上市的才可以交易 trade.isEnabled = obj.goodsstatus == 3 /// 判断其是否已登录 trade.setTitle(MTP2BusinessCore.shared.getLoginStatus() ? (obj.goodsstatus == 3 ? "立即购买" : "未开售") : "未登录", for: .normal) tradeView.startColor = obj.goodsstatus == 3 ? UIColorFromHex(rgbValue: 0xdf7e58) : .lightGray tradeView.endColor = obj.goodsstatus == 3 ? UIColorFromHex(rgbValue: 0xdf5958) : .lightGray } /// 商品详情 let goodsdesc = NSString(string: obj.goodsdesc).replacingOccurrences(of: "./uploadFile", with: (MTP2BusinessCore.shared.address?.openApiUrl ?? "")+"/uploadFile") webView.loadHTMLString(goodsdesc, baseURL: Bundle.main.bundleURL) /// 管理端 guard let managerUrl = MTP2BusinessCore.shared.address?.openApiUrl, managerUrl != "" else { return } /// 商品图片 var urls = obj.picurls.components(separatedBy: ",") let videourls = obj.videourls.components(separatedBy: ",") if videourls.first != "" { urls.insert(contentsOf: videourls.map { (url) -> String in if url.hasPrefix("./") { return managerUrl+NSString(string: url).replacingOccurrences(of: "./", with: "/") } return url }, at: 0) } /// 设置媒体介质 if urls.count != 0 { self.mediaView.setWithIsVideo(obj.videourls == "" ? TSDETAILTYPEIMAGE : TSDETAILTYPEVIDEO, andDataArray: urls.map { (url) -> String in if url.hasPrefix("./") { return managerUrl+NSString(string: url).replacingOccurrences(of: "./", with: "/") } return url }) } } // MARK: - 交互相关 /// onButtonPressed /// - Parameter sender: sender @IBAction fileprivate func onButtonPressed(_ sender: UIControl) { switch sender { case trade: /// 立即购买 guard let obj = model else { return } if obj.trademode == ETradeMode.TRADEMODE_LISTING_SELECT { /// 商品热卖 push(storyboardName: "Quote", storyboardId: "Trade", takeInfo: goodsDetail) } else if obj.trademode == ETradeMode.TRADEMODE_TRADEMODE_HSBY_SHOP { /// 商城 push(storyboardName: "Quote", storyboardId: "PaymentOrder", takeInfo: goodsDetail) } else { if MTP2BusinessCore.shared.getLoginStatus() { /// 新品预售 let preTraderController = self.viewController(name: "Quote", identifier: "PreTrade") as! PreTradeViewController /// 商品详情 preTraderController.takeInfo = goodsDetail preTraderController.modalPresentationStyle = .overCurrentContext preTraderController.modalTransitionStyle = .crossDissolve /// 回调块 preTraderController.disBlock = { (_ orderId: String?, _ amount: Double, _ payOrder: MoMyPayOrders?) in /// 异常 guard let paymentController = self.viewController(name: "Order", identifier: "Payment") as? PaymentViewController else { return } /// 待付款单据 paymentController.myPayOrder = payOrder /// 页面跳转 self.navigationController?.pushViewController(paymentController, animated: true) } self.present(preTraderController, animated: true, completion: {}) } else { /// 未登录 let login = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Login") self.navigationController?.pushViewController(login, animated: true) } } case favorite: /// 收藏 /// 未登录 if !MTP2BusinessCore.shared.getLoginStatus() { let login = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Login") self.navigationController?.pushViewController(login, animated: true) return } /// 异常 guard let obj = model else { return } if isFavorite { /// 删除收藏 self.removeUserFavoriteGoods(obj.goodsid) } else { /// 添加收藏 self.AddUserFavoriteGoods(obj.goodsid) } default: break } } // MARK: - 接口请求 /// 服务端查询二级市场商品详情请求方法 /// - Parameter goodsID: goodsID fileprivate func requestQueryHsbyListingGoodsDetail(_ goodsID: Int) { /// 异常 guard let goodsManager = MTP2BusinessCore.shared.goodsManager else { return } /// startAnimating _anim?.startAnimating() /// 发送请求 goodsManager.requestQueryHsbyListingGoodsDetail(goodsID) { (isComplete, error, detail) in DispatchQueue.main.async { /// stopAnimating self._anim?.stopAnimating() if isComplete { /// 查询成功 self.goodsDetail = detail } else { WHToast.showMessage("数据加载失败,原因:\(error?.retMsg ?? "未知错误")", duration: 1.5, finishHandler: {}) } } } } /// 服务端查询一级市场商品详情请求方法 /// - Parameter goodsID: goodsID fileprivate func requestQueryHsbyPreGoodsDetail(_ goodsID: Int) { /// 异常 guard let goodsManager = MTP2BusinessCore.shared.goodsManager else { return } /// startAnimating _anim?.startAnimating() /// 发送请求 goodsManager.requestQueryHsbyPreGoodsDetail(goodsID) { (isComplete, error, detail) in DispatchQueue.main.async { /// stopAnimating self._anim?.stopAnimating() if isComplete { /// 查询成功 self.goodsDetail = detail } else { WHToast.showMessage("数据加载失败,原因:\(error?.retMsg ?? "未知错误")", duration: 1.5, finishHandler: {}) } } } } /// 服务端查询商城商品详情请求方法 /// - Parameter orderID: orderID fileprivate func requestQueryHsbyMarketGoodsDetail(_ orderID: String) { /// 异常 guard let goodsManager = MTP2BusinessCore.shared.goodsManager else { return } /// startAnimating _anim?.startAnimating() /// 发送请求 goodsManager.requestQueryHsbyMarketGoodsDetail(orderID, callback: { (isComplete, error, detail) in DispatchQueue.main.async { /// stopAnimating self._anim?.stopAnimating() if isComplete { /// 查询成功 self.goodsDetail = detail } else { WHToast.showMessage("数据加载失败,原因:\(error?.retMsg ?? "未知错误")", duration: 1.5, finishHandler: {}) } } }) } /// 服务端查询游客商城商品详情请求方法 /// - Parameter orderID: orderID fileprivate func requestQueryHsbyVisitorMarketGoodsDetail(_ goodsID: Int) { /// 异常 guard let goodsManager = MTP2BusinessCore.shared.goodsManager else { return } /// startAnimating _anim?.startAnimating() /// 发送请求 goodsManager.requestQueryHsbyVisitorMarketGoodsDetail(goodsID, callback: { (isComplete, error, detail) in DispatchQueue.main.async { /// stopAnimating self._anim?.stopAnimating() if isComplete { /// 查询成功 self.goodsDetail = detail } else { WHToast.showMessage("数据加载失败,原因:\(error?.retMsg ?? "未知错误")", duration: 1.5, finishHandler: {}) } } }) } /// 添加用户藏品数据信息请求接口 /// - Parameter goodsID: 商品代码 fileprivate func AddUserFavoriteGoods(_ goodsID: Int) { /// 异常 guard let goodsManager = MTP2BusinessCore.shared.goodsManager else { return } /// 发送请求 goodsManager.requestAddUserFavoriteGoods(goodsID) { (_, _) in DispatchQueue.main.async { WHToast.showSuccess(withMessage: "添加成功", duration: 1.5, finishHandler: {}) self.isFavorite = !self.isFavorite } } } /// 移出用户藏品数据信息请求接口 /// - Parameter goodsID: 商品代码 fileprivate func removeUserFavoriteGoods(_ goodsID: Int) { /// 异常 guard let goodsManager = MTP2BusinessCore.shared.goodsManager else { return } /// 发送请求 goodsManager.requestRemoveUserFavoriteGoods(goodsID) { (_, _) in DispatchQueue.main.async { WHToast.showSuccess(withMessage: "移出成功", duration: 1.5, finishHandler: {}) self.isFavorite = !self.isFavorite } } } /// 获取历史数据请求 fileprivate func requestHistoryDatas() { /// 异常 guard let quoteManager = MTP2BusinessCore.shared.quoteManager else { return } /// 查询历史服务数据 quoteManager.requestQueryHistoryDatas(.MinutesDay, model?.goodscode ?? "", nil, nil, 400, true) { (isComplete, error, historyDatas) in DispatchQueue.main.async { if isComplete, historyDatas?.count != 0 { let xs = historyDatas?.map({ (obj) -> String in return DateUtils.getTDateString(obj.ts, "MM-dd") }) let max = historyDatas?.sorted(by: { (obj1, obj2) -> Bool in return obj1.c > obj2.c }).first?.c ?? 0.0 let ys = [historyDatas?.map({ (obj) -> String in return obj.c.description })] /// 折线图数据 self.lineChartView.leftDataArr = ys as [Any] /// 底部日期 self.lineChartView.dataArrOfX = xs /// 泡泡标题 self.lineChartView.paopaoTitleArray = xs /// 泡泡数据 self.lineChartView.paopaoDataArray = ys as [Any] /// 最大值 self.lineChartView.max = CGFloat(max*1.2) /// 最小值 self.lineChartView.min = CGFloat(historyDatas?.sorted(by: { (obj1, obj2) -> Bool in return obj1.c < obj2.c }).first?.c ?? 0.0) /// 开始画图 self.lineChartView.show() } else { /// 移出视图 self.chartView.removeFromSuperview() } } } } // 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 == "ShowCustomer" { (segue.destination as? CustomerViewController)?.goodsDetail = self.goodsDetail } } // 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() goodsCodes.insert(self.model?.goodscode ?? "") return goodsCodes } } // MARK: - WKUIDelegate, WKNavigationDelegate extension GoodsDetailViewController: WKUIDelegate, WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { /// 图片缩放比例不正确问题 webView.evaluateJavaScript(""" var imgs = document.getElementsByTagName("img") for (var i = 0; i < imgs.length; i++) { imgs[i].setAttribute('width', '100%') } """,completionHandler: nil) webView.evaluateJavaScript(""" var oMeta = document.createElement('meta'); oMeta.content = 'width=device-width, initial-scale=1, user-scalable=0'; oMeta.name = 'viewport'; document.getElementsByTagName('head')[0].appendChild(oMeta); """,completionHandler: nil) /// 动态计算webView内容高度 webView.evaluateJavaScript("document.body.scrollHeight") { [unowned self] (result, error) in if let tempHeight: Double = result as? Double { UIView.animate(withDuration: 0.5) { self.webViewLayoutConstraint.constant = CGFloat(tempHeight) } } } /// 设置webView 内容背景色 webView.evaluateJavaScript("document.getElementsByTagName('body')[0].style.background='#FFFFFF'") { (result, error) in } } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { WHToast.showError(withMessage: error.localizedDescription, duration: 1.5, finishHandler: {}) } func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { /// 设置webView 内容背景色 webView.evaluateJavaScript("document.getElementsByTagName('body')[0].style.background='#FFFFFF'") { (result, error) in } } } // MARK: - UIScrollViewDelegate extension GoodsDetailViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { if scrollView.contentOffset.y >= 20.0 { self.navigationController?.setNavigationBarHidden(false, animated: true) } else { self.navigationController?.setNavigationBarHidden(true, animated: true) } } } // MARK: - TSVideoPlaybackDelegate extension GoodsDetailViewController: TSVideoPlaybackDelegate, SDPhotoBrowserDelegate { func videoView(_ view: TSVideoPlayback!, didSelectItemAtIndexPath index: Int) { let browser = SDPhotoBrowser() browser.currentImageIndex = index-1 browser.sourceImagesContainerView = self.mediaView.scrolView browser.delegate = self browser.show() } /// 预告视图 func photoBrowser(_ browser: SDPhotoBrowser!, placeholderImageFor index: Int) -> UIImage! { return UIImage(named: "placeholder_image") } }