// // QSLVipController.swift // QuickSearchLocation // // Created by Destiny on 2024/11/27. // import UIKit import YYText enum QSLVipJumpType: Int { case homeRoad // 定位查看轨迹 case add // 添加好友 case friendRoad // 好友列表查看轨迹 case contact // 添加紧急联系人 case mine // case guideComments // 引导评论 } class QSLVipController: QSLBaseController { // 购买人数 static let record_non_member_clicks_to_claim = "RECORD_NON_MEMBER_CLIKS_CLAIM" struct UX { static let mostCellHeight = 113.0.rpx static let collectionRowHeight = 137.0.rpx static let goodsBgHeight = 54.rpx + UX.mostCellHeight + 20.rpx } var type: QSLVipJumpType? var goodList: [QSLGoodModel] = [QSLGoodModel]() ///是否是订阅的产品 //var is var selectGood: QSLGoodModel? { didSet { updateSelectGoodUI() } } lazy var vipBg: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "vip_bg") return imageView }() lazy var backButton: UIButton = { let button = UIButton() button.image(UIImage(named: "public_back_btn_white")) button.title("会员中心") button.mediumFont(17) button.textColor(.white) button.setImageTitleLayout(.imgLeft, spacing: 4.rpx) button.addTarget(self, action: #selector(backBtnAction), for: .touchUpInside) return button }() lazy var peopleCountView: UIView = { let view = UIView() view.layer.cornerRadius = 12.rpx view.layer.borderColor = UIColor.white.withAlphaComponent(0.16).cgColor view.layer.borderWidth = 1.rpx return view }() lazy var peopleAvatarImageView: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "vip_avatars_icon") return imageView }() lazy var peopleCountLabel: UILabel = { let label = UILabel() label.text("1456488人 已开通VIP") label.color("#FFE6C0") label.font(12) return label }() lazy var scrollView: UIScrollView = { let scrollView = UIScrollView() // scrollView.delegate = self scrollView.bounces = false scrollView.showsVerticalScrollIndicator = false scrollView.contentInsetAdjustmentBehavior = .never return scrollView }() lazy var cardBannerImageView: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "vip_banner_card") return imageView }() lazy var vipTimeLabel: UILabel = { let label = UILabel() label.text("升级VIP会员,解锁全部功能") label.font(13) label.textColor = .hexStringColor(hexString: "#AF7655") return label }() lazy var funcBannerImageView: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "vip_banner_func") return imageView }() lazy var mainView: UIView = { let view = UIView() view.backgroundColor = QSLColor.backGroundColor view.addRadius(radius: 12.rpx) return view }() lazy var goodsBgView: UIView = { let view = UIView() view.gradientBackgroundColor(color1: .hexStringColor(hexString: "#FFF8F2"), color2: .hexStringColor(hexString: "#FFFFFF"), width: QSLConst.qsl_kScreenW, height: UX.goodsBgHeight, direction: .vertical) return view }() lazy var vipGoodsTitleIcon: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "vip_title_icon") return imageView }() lazy var resumeBtn: UIButton = { let button = UIButton() button.title("恢复购买") button.setTitleColor(.hexStringColor(hexString: "#000000").withAlphaComponent(0.5), for: .normal) button.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: .medium) button.image(UIImage(named: "vip_resume_btn")) button.setImageTitleLayout(.imgLeft, spacing: 2.rpx) button.addTarget(self, action: #selector(resumeBtnAction), for: .touchUpInside) return button }() lazy var mostCell: QSLVipMostGoodCell = { let cell = QSLVipMostGoodCell() cell.isUserInteractionEnabled = true let tap = UITapGestureRecognizer(target: self, action: #selector(firstCellClickAction)) cell.addGestureRecognizer(tap) return cell }() lazy var goodsCollectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.minimumLineSpacing = 0 layout.scrollDirection = .vertical let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.backgroundColor = .clear collectionView.dataSource = self collectionView.delegate = self collectionView.showsHorizontalScrollIndicator = false collectionView.bounces = false collectionView.register(cellClass: QSLVipGoodCollectionViewCell.self) return collectionView }() lazy var selectBtn: UIButton = { let btn = UIButton() btn.image(UIImage(named: "public_select_btn_false"), .normal) btn.image(UIImage(named: "public_select_btn_true"), .selected) btn.addTarget(self, action: #selector(selectBtnAction), for: .touchUpInside) return btn }() lazy var serviceLabel: YYLabel = { let label = YYLabel() //updateServiceLabelText(showSubscribe: true) // 默认显示所有内容 return label }() // 更新服务条款文本内容 func updateServiceLabelText(showSubscribe: Bool) { let attr = NSMutableAttributedString() // 固定部分:购买即同意 let firstAttr = NSMutableAttributedString(string: "购买即同意") firstAttr.font(10) firstAttr.color(.hexStringColor(hexString: "#A7A7A7")) attr.append(firstAttr) let blankAttr = NSMutableAttributedString(string: " ") blankAttr.font(10) attr.append(blankAttr) // 《隐私权政策》 let privacyHL = YYTextHighlight() let privacyStr = "《隐私权政策》" let privacyText = NSMutableAttributedString(string: privacyStr) privacyText.font(10) privacyText.color(.hexStringColor(hexString: "#E7B983")) privacyText.yy_setTextHighlight(privacyHL, range: NSRange(location: 0, length: privacyStr.count)) privacyHL.tapAction = { [weak self] containerView, text, range, rect in self?.privacyAction() } attr.append(privacyText) attr.append(blankAttr) // 《用户协议》 let serviceHL = YYTextHighlight() let serviceStr = "《用户协议》" let serviceText = NSMutableAttributedString(string: serviceStr) serviceText.font(10) serviceText.color(.hexStringColor(hexString: "#E7B983")) serviceText.yy_setTextHighlight(serviceHL, range: NSRange(location: 0, length: serviceStr.count)) serviceHL.tapAction = { [weak self] containerView, text, range, rect in self?.serviceAction() } attr.append(serviceText) // 根据条件决定是否添加《续订说明》相关内容 if showSubscribe { attr.append(blankAttr) let andAttr = NSMutableAttributedString(string: "和") andAttr.font(10) andAttr.color(.hexStringColor(hexString: "#A7A7A7")) attr.append(andAttr) attr.append(blankAttr) let subcribeHL = YYTextHighlight() let subcribeStr = "《续订说明》" let subcribeText = NSMutableAttributedString(string: subcribeStr) subcribeText.font(10) subcribeText.color(.hexStringColor(hexString: "#E7B983")) subcribeText.yy_setTextHighlight(subcribeHL, range: NSRange(location: 0, length: subcribeStr.count)) subcribeHL.tapAction = { [weak self] containerView, text, range, rect in self?.subscibeAction() } attr.append(subcribeText) } serviceLabel.attributedText = attr } // 在需要隐藏《续订说明》时调用此方法 func hideSubscribeDescription() { updateServiceLabelText(showSubscribe: false) } // 在需要显示《续订说明》时调用此方法 func showSubscribeDescription() { updateServiceLabelText(showSubscribe: true) } lazy var commentView: UIView = { let view = UIView() view.backgroundColor = .white return view }() lazy var commentTitleIcon: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "vip_comment_title_icon") return imageView }() lazy var comment1: QSLVipCommentCellView = { let view = QSLVipCommentCellView() view.config(name: "用户189****7913", comment: "上班没时间,远程遛娃,非常方便很好用。") return view }() lazy var comment2: QSLVipCommentCellView = { let view = QSLVipCommentCellView() view.config(name: "用户189****7913", comment: "用了之后,才发现真的可以找到他。") return view }() lazy var comment3: QSLVipCommentCellView = { let view = QSLVipCommentCellView() view.config(name: "用户189****7913", comment: "轨迹很准,一目了然,奶奶出门遇到危险直接一键报警,我就收到信息了") return view }() lazy var tipTitleLabel: UILabel = { let label = UILabel() label.text("温馨提示") label.font(12) label.textColor = .hexStringColor(hexString: "#000000").withAlphaComponent(0.8) return label }() lazy var tipContentLabel: UILabel = { let label = UILabel() label.numberOfLines = 0 label.text("1 订阅后会从您的iTunes账户中扣除相关费用。如需取消续订,请在当前订阅周期结束前,至少24小时内通过手机“账户设置”的订阅管理关闭自动续费功能。\n2 未成年人请在监护者的陪同下进行购买\n3 购买后不支持退款,请仔细审阅《隐私权政策》《用户协议》和《续订说明》") label.font(10) label.textColor = .hexStringColor(hexString: "#000000").withAlphaComponent(0.6) label.changeLineSpace(space: 5) return label }() lazy var bottomContentView: UIView = { let view = UIView() return view }() lazy var bottomTopView: UIView = { let view = UIView() view.isHidden = true view.backgroundColor = .hexStringColor(hexString: "#FFFED8") view.addRadius(radius: 30.rpx) return view }() lazy var bottomTopLabel: UILabel = { let label = UILabel() label.text = "" return label }() func bottomTopLabelInfo(_ goodInfo : QSLGoodModel) { let darkGrayAttributes: [NSAttributedString.Key: Any] = [ .foregroundColor: UIColor.hexStringColor(hexString: "#404040"), .font: UIFont.systemFont(ofSize: 11), .paragraphStyle: { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center return paragraphStyle }(), .kern: -1 ] // 创建绿色文本样式 let greenAttributes: [NSAttributedString.Key: Any] = [ .foregroundColor: UIColor.hexStringColor(hexString: "#EE6C1C"), .font: UIFont.systemFont(ofSize: 15, weight: .black), .paragraphStyle: { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center return paragraphStyle }(), .kern: -1 ] let textArray = goodInfo.text.components(separatedBy: goodInfo.keys.key) if textArray.count > 0 && goodInfo.text.count > 0{ bottomTopView.isHidden = false let inputtr = NSMutableAttributedString() let titleOneAttr = NSAttributedString(string: textArray.first ?? "", attributes: darkGrayAttributes) let titleTwoAttr = NSAttributedString(string: " \(goodInfo.keys.value) ", attributes: greenAttributes) inputtr.append(titleOneAttr) inputtr.append(titleTwoAttr) if textArray.count > 1 { let titleThreeAttr = NSAttributedString(string: textArray[1], attributes: darkGrayAttributes) inputtr.append(titleThreeAttr) } bottomTopLabel.attributedText = inputtr } else { bottomTopView.isHidden = true } } lazy var bottomView: UIView = { let view = UIView() view.gradientBackgroundColor(color1: .hexStringColor(hexString: "#00434E"), color2: .hexStringColor(hexString: "#0E5E61"), width: QSLConst.qsl_kScreenW - 24.rpx, height: 50.rpx, direction: .horizontal) view.addRadius(radius: 25.rpx) return view }() lazy var unlockBtn: UIButton = { let btn = UIButton() btn.setBackgroundImage(UIImage(named: "vip_unlock_btn_bg"), for: .normal) btn.title("立即解锁") btn.textColor(.hexStringColor(hexString: "#9B3800")) btn.mediumFont(18) btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: 30.rpx, bottom: 0, right: 0) btn.addTarget(self, action: #selector(unlockBtnAction), for: .touchUpInside) return btn }() lazy var priceIconLabel: UILabel = { let label = UILabel() label.text("¥") label.textColor = .hexStringColor(hexString: "#FFF8EF") label.font(14) return label }() lazy var priceLabel: UILabel = { let label = UILabel() label.text("168") label.textColor = .hexStringColor(hexString: "#FFF8EF") label.font(24) return label }() lazy var goodTypeLabel: UILabel = { let label = UILabel() label.text("/") label.textColor = .hexStringColor(hexString: "#FFF8EF") label.font(12) return label }() lazy var goodOriginalPriceLabel: UILabel = { let label = UILabel() label.text("原价228") label.textColor = .hexStringColor(hexString: "#FFF8EF") label.font(12) label.centerLineText(lineValue: 1, underlineColor: .hexStringColor(hexString: "#FFF8EF")) return label }() override func viewDidLoad() { super.viewDidLoad() initializeView() updateUI() requestItemList() calculateBuyCount() if let type = self.type { switch type { case .homeRoad: gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1001]) case .add: gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1002]) case .friendRoad: gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1003]) case .contact: gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1004]) case .mine: gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1006]) case .guideComments: print("") } } } } extension QSLVipController { @objc func privacyAction() { let vc = QSLWebViewController() vc.webUrl = QSLConfig.AppPrivacyAgreementLink vc.title = "隐私政策" self.navigationController?.pushViewController(vc, animated: true) } @objc func serviceAction() { let vc = QSLWebViewController() vc.webUrl = QSLConfig.AppServiceAgreementLink vc.title = "服务协议" self.navigationController?.pushViewController(vc, animated: true) } @objc func subscibeAction() { let vc = QSLWebViewController() vc.webUrl = QSLConfig.AppSubscibeAgreementLink vc.title = "续订说明" self.navigationController?.pushViewController(vc, animated: true) } @objc func selectBtnAction() { selectBtn.isSelected = !selectBtn.isSelected } // 恢复按钮点击 @objc func resumeBtnAction() { let memberModel = QSLBaseManager.shared.userModel.memberModel let expired = memberModel.expired if !expired { QSLLoading.success(text: "您已经在订阅中,无需恢复") return } QSLLoading.show() QSLVipManager.shared.restoreAction { isSuccess in QSLVipManager.shared.isPaying = false if isSuccess { QSLNetwork().request(.userMember(dict: [:])) { response in let model = response.mapObject(QSLMemberModel.self, modelKey: "data") QSLBaseManager.shared.userModel.memberModel = model if model.expired { QSLBaseManager.shared.saveVipExpiredTime(time: 0) } else { QSLBaseManager.shared.saveVipExpiredTime(time: model.endTimestamp) } QSLBaseManager.shared.saveUserId(id: model.userId) if model.endTimestamp > memberModel.endTimestamp { QSLLoading.success(text: "恢复成功") // 支付成功通知 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) { self.navigationController?.popViewController(animated: true) } } else { QSLLoading.error(text: "没有可供恢复的订阅") } } fail: { code, error in QSLLoading.error(text: "没有可供恢复的订阅") } } else { QSLLoading.error(text: "没有可供恢复的订阅") } } } // 支付按钮点击 @objc func unlockBtnAction() { switch self.selectGood?.level { case 100 : gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1006]) break case 700: gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1005]) break; case 3100: gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1004]) break; case 9200: gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1003]) break; case 36600: gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1002]) break; case 3660000: gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1001]) break; default: break; } // if !selectBtn.isSelected { // self.view.toast(text: "请先同意《隐私权政策》和《用户协议》") // return // } let memberModel = QSLBaseManager.shared.userModel.memberModel if let subscriptionExpired = memberModel.subscriptionExpired, !subscriptionExpired { self.view.toast(text: "你已经订阅了") return } if goodList.count > 0, let selectGood = self.selectGood { QSLLoading.show() QSLVipManager.shared.startPay(goods: selectGood) { [self] status, outTradeNo in QSLVipManager.shared.isPaying = false if status == .success { QSLLoading.success(text: "支付成功") //支付成功埋点 gravityInstance?.track(QSLGravityConst.vip_submit_success, properties: ["id": 01001]) //弹出是否好评的弹窗 QSLGuideusersToCommentManager.commentShare.manageWhetherTriggerPopUpWindow(QSLGuideusersToCommentType.member) // 引力传递支付事件 if let selectGood = self.selectGood { gravityInstance?.trackPayEvent(withAmount: Int32(selectGood.amount), withPayType: "CNY", withOrderId: outTradeNo, withPayReason: selectGood.name, withPayMethod: "apple") } #if DEBUG #else //苹果广告奇异果传递支付事件 QSWikiHandle.shared.addEventResultAttribution(eventDict: ["event_name": "pay", "event_val": selectGood.amount]) #endif if let type = self.type { switch type { case .homeRoad: gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1001]) case .add: gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1002]) case .friendRoad: gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1003]) case .contact: gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1004]) case .mine: gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1006]) case .guideComments: print("") } } switch self.selectGood?.level { case 100 : gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 1]) break case 700: gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 5]) break; case 3100: gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 9]) break; case 9200: gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 13]) break; case 36600: gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 17]) break; case 3660000: gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 21]) break; default: break; } DispatchQueue.main.asyncAfter(deadline: .now() + 3) { self.navigationController?.popViewController(animated: true) NotificationCenter.default.post(name: QSLNotification.QSLRefreshMember, object: nil) } } else if status == .cancel { QSLLoading.error(text: "支付取消") } else if status == .fail { gravityInstance?.track(QSLGravityConst.vip_fail) QSLLoading.error(text: "支付失败") } else if status == .searchFail { QSLLoading.error(text: "查询订单失败,请稍后重试") } } } } @objc func firstCellClickAction() { for i in 0.. 0 { self.goodList[0].isSelect = true self.selectGood = self.goodList[0] self.mostCell.config(model: self.goodList[0]) } switch self.selectGood?.level { case 100 : gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1006]) break case 700: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1005]) break; case 3100: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1004]) break; case 9200: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1003]) break; case 36600: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1002]) break; case 3660000: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1001]) break; default: break; } self.goodsCollectionView.reloadData() } } extension QSLVipController { // 请求商品列表 func requestItemList() { // 定义并赋值 itemListDict(根据条件变化) var itemListDict: [String: Any] = ["itemListType": 2] if UserDefaults.standard.string(forKey: QSLVipController.record_non_member_clicks_to_claim) == nil && self.type == .guideComments { itemListDict = ["itemListType": 2, "showExtraText": true] // 记录非会员点击领取 UserDefaults.standard.set("YES", forKey: QSLVipController.record_non_member_clicks_to_claim) UserDefaults.standard.synchronize() } // 网络请求时使用 itemListDict 作为参数(关键修复) QSLNetwork().request(.vipItemList(dict: itemListDict)) { response in // 后续逻辑不变... let list = response.mapArray(QSLGoodModel.self, modelKey: "data>list") self.goodList = list if self.goodList.count > 0 { self.goodList[0].isSelect = true self.selectGood = self.goodList[0] self.mostCell.config(model: self.goodList[0]) let row = ceil(Double(self.goodList.count - 1) / 3.0) let height = UX.goodsBgHeight + (row * UX.collectionRowHeight) self.goodsBgView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#FFF8F2"), color2: .hexStringColor(hexString: "#FFFFFF"), width: QSLConst.qsl_kScreenW, height: height, direction: .vertical) self.goodsBgView.snp.updateConstraints { make in make.height.equalTo(height) } self.scrollView.snp.makeConstraints { make in make.bottom.equalTo(self.mainView) } self.checkRenewalOfProducts() } self.goodsCollectionView.reloadData() } fail: { code, error in self.view.toast(text: "加载商品列表失败") } } ///检查有没有续订的产品 func checkRenewalOfProducts() { let hasSubscribable = self.goodList.contains(where: { model in return model.subscribable == 1 }) if hasSubscribable == false { tipContentLabel.isHidden = true hideSubscribeDescription() serviceLabel.snp.removeConstraints() serviceLabel.snp.makeConstraints { make in make.left.equalTo(16) make.top.equalTo(comment3.snp.bottom).offset(28.rpx) } } else { tipContentLabel.isHidden = false showSubscribeDescription() } } // 计算购买人数 func calculateBuyCount() { var num = 145883 if let localNum = UserDefaults.standard.value(forKey: QSLConfig.user_default_local_buy_count) as? Int { num = localNum } let randomAddCount = Int.random(in: 1...10) num = num + randomAddCount UserDefaults.standard.setValue(num, forKey: QSLConfig.user_default_local_buy_count) self.peopleCountLabel.text("\(num)人 已开通VIP") } } // MARK: - 设置 CollectionView extension QSLVipController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return goodList.count - 1 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(cellType: QSLVipGoodCollectionViewCell.self, cellForRowAt: indexPath) let model = self.goodList[indexPath.row + 1] if self.goodList.count - 1 == 2 { cell.config(model: model, type: .big) } else { cell.config(model: model, type: .small) } return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { for i in 0.. 0 { self.goodList[indexPath.row + 1].isSelect = true self.selectGood = self.goodList[indexPath.row + 1] self.mostCell.config(model: self.goodList[0]) } switch self.selectGood?.level { case 100 : gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1006]) break case 700: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1005]) break; case 3100: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1004]) break; case 9200: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1003]) break; case 36600: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1002]) break; case 3660000: gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1001]) break; default: break; } self.goodsCollectionView.reloadData() } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { var width = (QSLConst.qsl_kScreenW - 42.0.rpx) / 3.0 if self.goodList.count - 1 == 2 { width = (QSLConst.qsl_kScreenW - 36.0.rpx) / 2.0 } return CGSize(width: width, height: 134.0.rpx) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 6.rpx } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return 3.rpx } } extension QSLVipController { func updateUI() { if QSLBaseManager.shared.isLogin() && QSLBaseManager.shared.isVip() { let model = QSLBaseManager.shared.userModel.memberModel if model.permanent { self.vipTimeLabel.text("您已是尊贵的永久会员") self.bottomContentView.isHidden = true } else { let level = model.memberLevelString() let endTime = model.endTimestampString() self.vipTimeLabel.text("\(level):\(endTime)到期") } } else { self.vipTimeLabel.text("升级VIP会员,解锁全部功能") } } func updateSelectGoodUI() { var priceText = "" var originalPriceText = "" if let selectGood = self.selectGood { if selectGood.amount.truncatingRemainder(dividingBy: 100) == 0 { priceText = "\(Int(selectGood.amount / 100))" } else { priceText = String(format: "%.2lf", selectGood.amount / 100 ) } if selectGood.originalAmount.truncatingRemainder(dividingBy: 100) == 0 { originalPriceText = "\(Int(selectGood.originalAmount / 100))" } else { originalPriceText = String(format: "%.2lf", selectGood.originalAmount / 100 ) } } self.priceLabel.text(priceText) // self.goodTypeLabel.text("/ \(self.selectGood?.name ?? "")") self.goodOriginalPriceLabel.text("原价\(originalPriceText)") ///底部内容 bottomTopLabelInfo(self.selectGood ?? QSLGoodModel()) } func initializeView() { self.view.addSubview(vipBg) vipBg.snp.makeConstraints { make in make.left.top.right.equalTo(0) } self.view.addSubview(backButton) backButton.snp.makeConstraints { make in make.size.equalTo(100.rpx) make.height.equalTo(25.rpx) make.left.equalTo(12.rpx) make.top.equalTo(QSLConst.qsl_kStatusBarFrameH) } self.view.addSubview(peopleCountView) peopleCountView.snp.makeConstraints { make in make.size.equalTo(CGSize(width: 212.rpx, height: 24.rpx)) make.right.equalTo(-13.rpx) make.centerY.equalTo(backButton.snp.centerY) } peopleCountView.addSubview(peopleAvatarImageView) peopleAvatarImageView.snp.makeConstraints { make in make.size.equalTo(CGSize(width: 72.rpx, height: 16.6.rpx)) make.left.equalTo(3.rpx) make.centerY.equalTo(peopleCountView.snp.centerY) } peopleCountView.addSubview(peopleCountLabel) peopleCountLabel.snp.makeConstraints { make in make.left.equalTo(peopleAvatarImageView.snp.right).offset(7.rpx) make.centerY.equalTo(peopleCountView.snp.centerY) } self.view.addSubview(scrollView) scrollView.snp.makeConstraints { make in make.left.right.equalTo(0) make.top.equalTo(QSLConst.qsl_kNavFrameH) make.bottom.equalTo(0) } scrollView.addSubview(cardBannerImageView) cardBannerImageView.snp.makeConstraints { make in make.top.equalTo(0) make.centerX.equalToSuperview() make.width.equalTo(336.rpx) make.height.equalTo(108.rpx) } cardBannerImageView.addSubview(vipTimeLabel) vipTimeLabel.snp.makeConstraints { make in make.left.equalTo(23.rpx) make.bottom.equalTo(-19.rpx) } scrollView.addSubview(funcBannerImageView) funcBannerImageView.snp.makeConstraints { make in make.size.equalTo(CGSize(width: 336.rpx, height: 172.rpx)) make.centerX.equalToSuperview() make.top.equalTo(cardBannerImageView.snp.bottom).offset(14.rpx) } scrollView.addSubview(mainView) mainView.snp.makeConstraints { make in make.left.right.equalTo(0) make.top.equalTo(funcBannerImageView.snp.bottom).offset(-24.rpx) make.width.equalTo(QSLConst.qsl_kScreenW) // make.height.equalTo(800.rpx) } let goodsBgHeight = 54.rpx + UX.mostCellHeight mainView.addSubview(goodsBgView) goodsBgView.snp.makeConstraints { make in make.top.left.right.equalTo(0) make.width.equalTo(QSLConst.qsl_kScreenW) make.height.equalTo(goodsBgHeight) } goodsBgView.addSubview(vipGoodsTitleIcon) vipGoodsTitleIcon.snp.makeConstraints { make in make.size.equalTo(CGSize(width: 117.rpx, height: 26.rpx)) make.left.equalTo(20.rpx) make.top.equalTo(16.rpx) } goodsBgView.addSubview(resumeBtn) resumeBtn.snp.makeConstraints { make in make.size.equalTo(CGSize(width: 75.rpx, height: 16.rpx)) make.right.equalTo(-18.rpx) make.centerY.equalTo(vipGoodsTitleIcon.snp.centerY) } goodsBgView.addSubview(mostCell) mostCell.snp.makeConstraints { make in make.left.equalTo(12.rpx) make.right.equalTo(-16.rpx) make.height.equalTo(113.rpx) make.top.equalTo(vipGoodsTitleIcon.snp.bottom).offset(10.rpx) } goodsBgView.addSubview(goodsCollectionView) goodsCollectionView.snp.makeConstraints { make in make.left.equalTo(12.rpx) make.right.equalTo(-18.rpx) make.bottom.equalTo(-20.rpx) make.top.equalTo(mostCell.snp.bottom).offset(3.rpx) } // goodsBgView.addSubview(selectBtn) // selectBtn.snp.makeConstraints { make in // make.size.equalTo(CGSize(width: 12.rpx, height: 12.rpx)) // make.left.equalTo(23.rpx) // make.top.equalTo(goodsCollectionView.snp.bottom).offset(16.rpx) // } // // goodsBgView.addSubview(serviceLabel) // serviceLabel.snp.makeConstraints { make in // make.left.equalTo(selectBtn.snp.right).offset(2.rpx) // make.centerY.equalTo(selectBtn.snp.centerY) // } mainView.addSubview(commentView) commentView.snp.makeConstraints { make in make.left.right.equalTo(0) make.top.equalTo(goodsBgView.snp.bottom).offset(8.rpx) make.height.equalTo(525.rpx + QSLConst.qsl_kTabbarBottom) make.bottom.equalTo(0) } commentView.addSubview(commentTitleIcon) commentTitleIcon.snp.makeConstraints { make in make.size.equalTo(CGSize(width: 83.rpx, height: 26.rpx)) make.top.equalTo(16.rpx) make.left.equalTo(12.rpx) } let commentHeight1 = "上班没时间,远程遛娃,非常方便很好用。".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx commentView.addSubview(comment1) comment1.snp.makeConstraints { make in make.left.right.equalTo(0) make.top.equalTo(commentTitleIcon.snp.bottom).offset(16.rpx) make.height.equalTo(commentHeight1) } let commentHeight2 = "用了之后,才发现真的可以找到他。".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx commentView.addSubview(comment2) comment2.snp.makeConstraints { make in make.left.right.equalTo(0) make.top.equalTo(comment1.snp.bottom).offset(30.rpx) make.height.equalTo(commentHeight2) } let commentHeight3 = "轨迹很准,一目了然,奶奶出门遇到危险直接一键报警,我就收到信息了".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx commentView.addSubview(comment3) comment3.snp.makeConstraints { make in make.left.right.equalTo(0) make.top.equalTo(comment2.snp.bottom).offset(30.rpx) make.height.equalTo(commentHeight3) } // commentView.addSubview(tipTitleLabel) // tipTitleLabel.snp.makeConstraints { make in // make.left.equalTo(16) // make.top.equalTo(comment3.snp.bottom).offset(28) // } commentView.addSubview(tipContentLabel) tipContentLabel.snp.makeConstraints { make in make.left.equalTo(16) make.right.equalTo(-16) make.top.equalTo(comment3.snp.bottom).offset(11) } commentView.addSubview(serviceLabel) serviceLabel.snp.makeConstraints { make in make.left.equalTo(16) make.top.equalTo(tipContentLabel.snp.bottom).offset(28.rpx) } scrollView.snp.makeConstraints { make in make.bottom.equalTo(mainView) } self.view.addSubview(bottomContentView) bottomContentView.snp.makeConstraints { make in make.left.equalTo(12.rpx) make.right.equalTo(-12.rpx) make.bottom.equalTo(-QSLConst.qsl_kTabbarBottom) make.height.equalTo(72.rpx) } bottomContentView.addSubview(bottomTopView) bottomTopView.snp.makeConstraints { make in make.left.equalToSuperview() make.right.equalToSuperview() make.top.equalToSuperview() make.height.equalTo(60.rpx) } bottomTopView.addSubview(bottomTopLabel) bottomTopLabel.snp.makeConstraints { make in make.left.equalToSuperview().offset(22) make.top.equalToSuperview() make.height.equalTo(21.rpx) } bottomContentView.addSubview(bottomView) bottomView.snp.makeConstraints { make in make.left.equalToSuperview() make.right.equalToSuperview() make.bottom.equalToSuperview() make.height.equalTo(50.rpx) } bottomView.addSubview(unlockBtn) unlockBtn.snp.makeConstraints { make in make.right.top.bottom.equalTo(0) make.width.equalTo(165.rpx) } bottomView.addSubview(priceIconLabel) priceIconLabel.snp.makeConstraints { make in make.left.equalTo(20.rpx) make.bottom.equalTo(-12.rpx) } bottomView.addSubview(priceLabel) priceLabel.snp.makeConstraints { make in make.left.equalTo(priceIconLabel.snp.right).offset(2.rpx) make.bottom.equalTo(-10.rpx) } bottomView.addSubview(goodTypeLabel) goodTypeLabel.snp.makeConstraints { make in make.left.equalTo(priceLabel.snp.right).offset(2.rpx) make.bottom.equalTo(-14.rpx) } bottomView.addSubview(goodOriginalPriceLabel) goodOriginalPriceLabel.snp.makeConstraints { make in make.left.equalTo(goodTypeLabel.snp.right).offset(2.rpx) make.centerY.equalTo(goodTypeLabel.snp.centerY) } } }