QSLVipController.swift 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. //
  2. // QSLVipController.swift
  3. // QuickSearchLocation
  4. //
  5. // Created by Destiny on 2024/11/27.
  6. //
  7. import UIKit
  8. import YYText
  9. enum QSLVipJumpType: Int {
  10. case homeRoad // 定位查看轨迹
  11. case add // 添加好友
  12. case friendRoad // 好友列表查看轨迹
  13. case contact // 添加紧急联系人
  14. case mine //
  15. }
  16. class QSLVipController: QSLBaseController {
  17. struct UX {
  18. static let mostCellHeight = 113.0.rpx
  19. static let collectionRowHeight = 137.0.rpx
  20. static let goodsBgHeight = 54.rpx + UX.mostCellHeight + 20.rpx
  21. }
  22. var type: QSLVipJumpType?
  23. var goodList: [QSLGoodModel] = [QSLGoodModel]()
  24. var selectGood: QSLGoodModel? {
  25. didSet {
  26. updateSelectGoodUI()
  27. }
  28. }
  29. lazy var vipBg: UIImageView = {
  30. let imageView = UIImageView()
  31. imageView.image = UIImage(named: "vip_bg")
  32. return imageView
  33. }()
  34. lazy var backButton: UIButton = {
  35. let button = UIButton()
  36. button.image(UIImage(named: "public_back_btn_white"))
  37. button.title("会员中心")
  38. button.mediumFont(17)
  39. button.textColor(.white)
  40. button.setImageTitleLayout(.imgLeft, spacing: 4.rpx)
  41. button.addTarget(self, action: #selector(backBtnAction), for: .touchUpInside)
  42. return button
  43. }()
  44. lazy var peopleCountView: UIView = {
  45. let view = UIView()
  46. view.layer.cornerRadius = 12.rpx
  47. view.layer.borderColor = UIColor.white.withAlphaComponent(0.16).cgColor
  48. view.layer.borderWidth = 1.rpx
  49. return view
  50. }()
  51. lazy var peopleAvatarImageView: UIImageView = {
  52. let imageView = UIImageView()
  53. imageView.image = UIImage(named: "vip_avatars_icon")
  54. return imageView
  55. }()
  56. lazy var peopleCountLabel: UILabel = {
  57. let label = UILabel()
  58. label.text("1456488人 已开通VIP")
  59. label.color("#FFE6C0")
  60. label.font(12)
  61. return label
  62. }()
  63. lazy var scrollView: UIScrollView = {
  64. let scrollView = UIScrollView()
  65. // scrollView.delegate = self
  66. scrollView.bounces = false
  67. scrollView.showsVerticalScrollIndicator = false
  68. scrollView.contentInsetAdjustmentBehavior = .never
  69. return scrollView
  70. }()
  71. lazy var cardBannerImageView: UIImageView = {
  72. let imageView = UIImageView()
  73. imageView.image = UIImage(named: "vip_banner_card")
  74. return imageView
  75. }()
  76. lazy var vipTimeLabel: UILabel = {
  77. let label = UILabel()
  78. label.text("升级VIP会员,解锁全部功能")
  79. label.font(13)
  80. label.textColor = .hexStringColor(hexString: "#AF7655")
  81. return label
  82. }()
  83. lazy var funcBannerImageView: UIImageView = {
  84. let imageView = UIImageView()
  85. imageView.image = UIImage(named: "vip_banner_func")
  86. return imageView
  87. }()
  88. lazy var mainView: UIView = {
  89. let view = UIView()
  90. view.backgroundColor = QSLColor.backGroundColor
  91. view.addRadius(radius: 12.rpx)
  92. return view
  93. }()
  94. lazy var goodsBgView: UIView = {
  95. let view = UIView()
  96. view.gradientBackgroundColor(color1: .hexStringColor(hexString: "#FFF8F2"), color2: .hexStringColor(hexString: "#FFFFFF"), width: QSLConst.qsl_kScreenW, height: UX.goodsBgHeight, direction: .vertical)
  97. return view
  98. }()
  99. lazy var vipGoodsTitleIcon: UIImageView = {
  100. let imageView = UIImageView()
  101. imageView.image = UIImage(named: "vip_title_icon")
  102. return imageView
  103. }()
  104. lazy var resumeBtn: UIButton = {
  105. let button = UIButton()
  106. button.title("恢复购买")
  107. button.setTitleColor(.hexStringColor(hexString: "#000000").withAlphaComponent(0.5), for: .normal)
  108. button.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: .medium)
  109. button.image(UIImage(named: "vip_resume_btn"))
  110. button.setImageTitleLayout(.imgLeft, spacing: 2.rpx)
  111. button.addTarget(self, action: #selector(resumeBtnAction), for: .touchUpInside)
  112. return button
  113. }()
  114. lazy var mostCell: QSLVipMostGoodCell = {
  115. let cell = QSLVipMostGoodCell()
  116. cell.isUserInteractionEnabled = true
  117. let tap = UITapGestureRecognizer(target: self, action: #selector(firstCellClickAction))
  118. cell.addGestureRecognizer(tap)
  119. return cell
  120. }()
  121. lazy var goodsCollectionView: UICollectionView = {
  122. let layout = UICollectionViewFlowLayout()
  123. layout.minimumLineSpacing = 0
  124. layout.scrollDirection = .vertical
  125. let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
  126. collectionView.backgroundColor = .clear
  127. collectionView.dataSource = self
  128. collectionView.delegate = self
  129. collectionView.showsHorizontalScrollIndicator = false
  130. collectionView.bounces = false
  131. collectionView.register(cellClass: QSLVipGoodCollectionViewCell.self)
  132. return collectionView
  133. }()
  134. lazy var selectBtn: UIButton = {
  135. let btn = UIButton()
  136. btn.image(UIImage(named: "public_select_btn_false"), .normal)
  137. btn.image(UIImage(named: "public_select_btn_true"), .selected)
  138. btn.addTarget(self, action: #selector(selectBtnAction), for: .touchUpInside)
  139. return btn
  140. }()
  141. lazy var serviceLabel: YYLabel = {
  142. let label = YYLabel()
  143. let attr = NSMutableAttributedString()
  144. let firstAttr = NSMutableAttributedString(string: "购买即同意")
  145. firstAttr.font(10)
  146. firstAttr.color(.hexStringColor(hexString: "#A7A7A7"))
  147. attr.append(firstAttr)
  148. let blankAttr = NSMutableAttributedString(string: " ")
  149. blankAttr.font(10)
  150. attr.append(blankAttr)
  151. let privacyHL = YYTextHighlight()
  152. var privacyStr = "《隐私权政策》"
  153. let privacyText = NSMutableAttributedString(string: privacyStr)
  154. privacyText.font(10)
  155. privacyText.color(.hexStringColor(hexString: "#E7B983"))
  156. privacyText.yy_setTextHighlight(privacyHL, range: NSRange(location: 0, length: privacyStr.count))
  157. privacyHL.tapAction = { [weak self] containerView, text, range, rect in
  158. self?.privacyAction()
  159. }
  160. attr.append(privacyText)
  161. attr.append(blankAttr)
  162. let serviceHL = YYTextHighlight()
  163. var serviceStr = "《用户协议》"
  164. let serviceText = NSMutableAttributedString(string: serviceStr)
  165. serviceText.font(10)
  166. serviceText.color(.hexStringColor(hexString: "#E7B983"))
  167. serviceText.yy_setTextHighlight(serviceHL, range: NSRange(location: 0, length: serviceStr.count))
  168. serviceHL.tapAction = { [weak self] containerView, text, range, rect in
  169. self?.serviceAction()
  170. }
  171. attr.append(serviceText)
  172. attr.append(blankAttr)
  173. let andAttr = NSMutableAttributedString(string: "和")
  174. andAttr.font(10)
  175. andAttr.color(.hexStringColor(hexString: "#A7A7A7"))
  176. attr.append(andAttr)
  177. attr.append(blankAttr)
  178. let subcribeHL = YYTextHighlight()
  179. var subcribeStr = "《续订说明》"
  180. let subcribeText = NSMutableAttributedString(string: subcribeStr)
  181. subcribeText.font(10)
  182. subcribeText.color(.hexStringColor(hexString: "#E7B983"))
  183. subcribeText.yy_setTextHighlight(subcribeHL, range: NSRange(location: 0, length: subcribeStr.count))
  184. subcribeHL.tapAction = { [weak self] containerView, text, range, rect in
  185. self?.subscibeAction()
  186. }
  187. attr.append(subcribeText)
  188. label.attributedText = attr
  189. return label
  190. }()
  191. lazy var commentView: UIView = {
  192. let view = UIView()
  193. view.backgroundColor = .white
  194. return view
  195. }()
  196. lazy var commentTitleIcon: UIImageView = {
  197. let imageView = UIImageView()
  198. imageView.image = UIImage(named: "vip_comment_title_icon")
  199. return imageView
  200. }()
  201. lazy var comment1: QSLVipCommentCellView = {
  202. let view = QSLVipCommentCellView()
  203. view.config(name: "用户189****7913", comment: "上班没时间,远程遛娃,非常方便很好用。")
  204. return view
  205. }()
  206. lazy var comment2: QSLVipCommentCellView = {
  207. let view = QSLVipCommentCellView()
  208. view.config(name: "用户189****7913", comment: "用了之后,才发现真的可以找到他。")
  209. return view
  210. }()
  211. lazy var comment3: QSLVipCommentCellView = {
  212. let view = QSLVipCommentCellView()
  213. view.config(name: "用户189****7913", comment: "轨迹很准,一目了然,奶奶出门遇到危险直接一键报警,我就收到信息了")
  214. return view
  215. }()
  216. lazy var tipTitleLabel: UILabel = {
  217. let label = UILabel()
  218. label.text("温馨提示")
  219. label.font(12)
  220. label.textColor = .hexStringColor(hexString: "#000000").withAlphaComponent(0.8)
  221. return label
  222. }()
  223. lazy var tipContentLabel: UILabel = {
  224. let label = UILabel()
  225. label.numberOfLines = 0
  226. label.text("1 订阅后会从您的iTunes账户中扣除相关费用。如需取消续订,请在当前订阅周期结束前,至少24小时内通过手机“账户设置”的订阅管理关闭自动续费功能。\n2 未成年人请在监护者的陪同下进行购买\n3 购买后不支持退款,请仔细审阅《隐私权政策》《用户协议》和《续订说明》")
  227. label.font(10)
  228. label.textColor = .hexStringColor(hexString: "#000000").withAlphaComponent(0.6)
  229. label.changeLineSpace(space: 5)
  230. return label
  231. }()
  232. lazy var bottomView: UIView = {
  233. let view = UIView()
  234. view.gradientBackgroundColor(color1: .hexStringColor(hexString: "#00434E"), color2: .hexStringColor(hexString: "#0E5E61"), width: QSLConst.qsl_kScreenW - 24.rpx, height: 50.rpx, direction: .horizontal)
  235. view.addRadius(radius: 25.rpx)
  236. return view
  237. }()
  238. lazy var unlockBtn: UIButton = {
  239. let btn = UIButton()
  240. btn.setBackgroundImage(UIImage(named: "vip_unlock_btn_bg"), for: .normal)
  241. btn.title("立即解锁")
  242. btn.textColor(.hexStringColor(hexString: "#9B3800"))
  243. btn.mediumFont(18)
  244. btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: 30.rpx, bottom: 0, right: 0)
  245. btn.addTarget(self, action: #selector(unlockBtnAction), for: .touchUpInside)
  246. return btn
  247. }()
  248. lazy var priceIconLabel: UILabel = {
  249. let label = UILabel()
  250. label.text("¥")
  251. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  252. label.font(14)
  253. return label
  254. }()
  255. lazy var priceLabel: UILabel = {
  256. let label = UILabel()
  257. label.text("168")
  258. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  259. label.font(24)
  260. return label
  261. }()
  262. lazy var goodTypeLabel: UILabel = {
  263. let label = UILabel()
  264. label.text("/")
  265. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  266. label.font(12)
  267. return label
  268. }()
  269. lazy var goodOriginalPriceLabel: UILabel = {
  270. let label = UILabel()
  271. label.text("原价228")
  272. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  273. label.font(12)
  274. label.centerLineText(lineValue: 1, underlineColor: .hexStringColor(hexString: "#FFF8EF"))
  275. return label
  276. }()
  277. override func viewDidLoad() {
  278. super.viewDidLoad()
  279. initializeView()
  280. updateUI()
  281. requestItemList()
  282. calculateBuyCount()
  283. if let type = self.type {
  284. switch type {
  285. case .homeRoad:
  286. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1001])
  287. case .add:
  288. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1002])
  289. case .friendRoad:
  290. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1003])
  291. case .contact:
  292. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1004])
  293. case .mine:
  294. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1006])
  295. }
  296. }
  297. }
  298. }
  299. extension QSLVipController {
  300. @objc func privacyAction() {
  301. let vc = QSLWebViewController()
  302. vc.webUrl = QSLConfig.AppPrivacyAgreementLink
  303. vc.title = "隐私政策"
  304. self.navigationController?.pushViewController(vc, animated: true)
  305. }
  306. @objc func serviceAction() {
  307. let vc = QSLWebViewController()
  308. vc.webUrl = QSLConfig.AppServiceAgreementLink
  309. vc.title = "服务协议"
  310. self.navigationController?.pushViewController(vc, animated: true)
  311. }
  312. @objc func subscibeAction() {
  313. let vc = QSLWebViewController()
  314. vc.webUrl = QSLConfig.AppSubscibeAgreementLink
  315. vc.title = "续订说明"
  316. self.navigationController?.pushViewController(vc, animated: true)
  317. }
  318. @objc func selectBtnAction() {
  319. selectBtn.isSelected = !selectBtn.isSelected
  320. }
  321. // 恢复按钮点击
  322. @objc func resumeBtnAction() {
  323. let memberModel = QSLBaseManager.shared.userModel.memberModel
  324. let expired = memberModel.expired
  325. if !expired {
  326. QSLLoading.success(text: "您已经在订阅中,无需恢复")
  327. return
  328. }
  329. QSLLoading.show()
  330. QSLVipManager.shared.restoreAction { isSuccess in
  331. QSLVipManager.shared.isPaying = false
  332. if isSuccess {
  333. QSLNetwork().request(.userMember(dict: [:])) { response in
  334. let model = response.mapObject(QSLMemberModel.self, modelKey: "data")
  335. QSLBaseManager.shared.userModel.memberModel = model
  336. if model.expired {
  337. QSLBaseManager.shared.saveVipExpiredTime(time: 0)
  338. } else {
  339. QSLBaseManager.shared.saveVipExpiredTime(time: model.endTimestamp)
  340. }
  341. QSLBaseManager.shared.saveUserId(id: model.userId)
  342. if model.endTimestamp > memberModel.endTimestamp {
  343. QSLLoading.success(text: "恢复成功")
  344. // 支付成功通知
  345. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
  346. self.navigationController?.popViewController(animated: true)
  347. }
  348. } else {
  349. QSLLoading.error(text: "没有可供恢复的订阅")
  350. }
  351. } fail: { code, error in
  352. QSLLoading.error(text: "没有可供恢复的订阅")
  353. }
  354. } else {
  355. QSLLoading.error(text: "没有可供恢复的订阅")
  356. }
  357. }
  358. }
  359. // 支付按钮点击
  360. @objc func unlockBtnAction() {
  361. switch self.selectGood?.level {
  362. case 100 :
  363. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1006])
  364. break
  365. case 700:
  366. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1005])
  367. break;
  368. case 3100:
  369. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1004])
  370. break;
  371. case 9200:
  372. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1003])
  373. break;
  374. case 36600:
  375. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1002])
  376. break;
  377. case 3660000:
  378. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1001])
  379. break;
  380. default:
  381. break;
  382. }
  383. // if !selectBtn.isSelected {
  384. // self.view.toast(text: "请先同意《隐私权政策》和《用户协议》")
  385. // return
  386. // }
  387. let memberModel = QSLBaseManager.shared.userModel.memberModel
  388. if let subscriptionExpired = memberModel.subscriptionExpired, !subscriptionExpired {
  389. self.view.toast(text: "你已经订阅了")
  390. return
  391. }
  392. if goodList.count > 0, let selectGood = self.selectGood {
  393. QSLLoading.show()
  394. QSLVipManager.shared.startPay(goods: selectGood) { status, outTradeNo in
  395. QSLVipManager.shared.isPaying = false
  396. if status == .success {
  397. QSLLoading.success(text: "支付成功")
  398. // 引力传递支付事件
  399. if let selectGood = self.selectGood {
  400. gravityInstance?.trackPayEvent(withAmount: Int32(selectGood.amount), withPayType: "CNY", withOrderId: outTradeNo, withPayReason: selectGood.name, withPayMethod: "apple")
  401. }
  402. if let type = self.type {
  403. switch type {
  404. case .homeRoad:
  405. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1001])
  406. case .add:
  407. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1002])
  408. case .friendRoad:
  409. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1003])
  410. case .contact:
  411. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1004])
  412. case .mine:
  413. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1006])
  414. }
  415. }
  416. switch self.selectGood?.level {
  417. case 100 :
  418. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 1])
  419. break
  420. case 700:
  421. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 5])
  422. break;
  423. case 3100:
  424. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 9])
  425. break;
  426. case 9200:
  427. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 13])
  428. break;
  429. case 36600:
  430. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 17])
  431. break;
  432. case 3660000:
  433. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 21])
  434. break;
  435. default:
  436. break;
  437. }
  438. DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
  439. self.navigationController?.popViewController(animated: true)
  440. NotificationCenter.default.post(name: QSLNotification.QSLRefreshMember, object: nil)
  441. }
  442. } else if status == .cancel {
  443. QSLLoading.error(text: "支付取消")
  444. } else if status == .fail {
  445. gravityInstance?.track(QSLGravityConst.vip_fail)
  446. QSLLoading.error(text: "支付失败")
  447. } else if status == .searchFail {
  448. QSLLoading.error(text: "查询订单失败,请稍后重试")
  449. }
  450. }
  451. }
  452. }
  453. @objc func firstCellClickAction() {
  454. for i in 0..<self.goodList.count {
  455. self.goodList[i].isSelect = false
  456. }
  457. if self.goodList.count > 0 {
  458. self.goodList[0].isSelect = true
  459. self.selectGood = self.goodList[0]
  460. self.mostCell.config(model: self.goodList[0])
  461. }
  462. switch self.selectGood?.level {
  463. case 100 :
  464. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1006])
  465. break
  466. case 700:
  467. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1005])
  468. break;
  469. case 3100:
  470. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1004])
  471. break;
  472. case 9200:
  473. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1003])
  474. break;
  475. case 36600:
  476. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1002])
  477. break;
  478. case 3660000:
  479. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1001])
  480. break;
  481. default:
  482. break;
  483. }
  484. self.goodsCollectionView.reloadData()
  485. }
  486. }
  487. extension QSLVipController {
  488. // 请求商品列表
  489. func requestItemList() {
  490. QSLNetwork().request(.vipItemList(dict: ["itemListType": 2])) { response in
  491. let list = response.mapArray(QSLGoodModel.self, modelKey: "data>list")
  492. self.goodList = list
  493. if self.goodList.count > 0 {
  494. self.goodList[0].isSelect = true
  495. self.selectGood = self.goodList[0]
  496. self.mostCell.config(model: self.goodList[0])
  497. let row = ceil(Double(self.goodList.count - 1) / 3.0)
  498. let height = UX.goodsBgHeight + (row * UX.collectionRowHeight)
  499. self.goodsBgView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#FFF8F2"), color2: .hexStringColor(hexString: "#FFFFFF"), width: QSLConst.qsl_kScreenW, height: height, direction: .vertical)
  500. self.goodsBgView.snp.updateConstraints { make in
  501. make.height.equalTo(height)
  502. }
  503. self.scrollView.snp.makeConstraints { make in
  504. make.bottom.equalTo(self.mainView)
  505. }
  506. }
  507. self.goodsCollectionView.reloadData()
  508. } fail: { code, error in
  509. self.view.toast(text: "加载商品列表失败")
  510. }
  511. }
  512. // 计算购买人数
  513. func calculateBuyCount() {
  514. var num = 145883
  515. if let localNum = UserDefaults.standard.value(forKey: QSLConfig.user_default_local_buy_count) as? Int {
  516. num = localNum
  517. }
  518. let randomAddCount = Int.random(in: 1...10)
  519. num = num + randomAddCount
  520. UserDefaults.standard.setValue(num, forKey: QSLConfig.user_default_local_buy_count)
  521. self.peopleCountLabel.text("\(num)人 已开通VIP")
  522. }
  523. }
  524. // MARK: - 设置 CollectionView
  525. extension QSLVipController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
  526. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  527. return goodList.count - 1
  528. }
  529. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  530. let cell = collectionView.dequeueReusableCell(cellType: QSLVipGoodCollectionViewCell.self, cellForRowAt: indexPath)
  531. let model = self.goodList[indexPath.row + 1]
  532. if self.goodList.count - 1 == 2 {
  533. cell.config(model: model, type: .big)
  534. } else {
  535. cell.config(model: model, type: .small)
  536. }
  537. return cell
  538. }
  539. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  540. for i in 0..<self.goodList.count {
  541. self.goodList[i].isSelect = false
  542. }
  543. if self.goodList.count > 0 {
  544. self.goodList[indexPath.row + 1].isSelect = true
  545. self.selectGood = self.goodList[indexPath.row + 1]
  546. self.mostCell.config(model: self.goodList[0])
  547. }
  548. switch self.selectGood?.level {
  549. case 100 :
  550. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1006])
  551. break
  552. case 700:
  553. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1005])
  554. break;
  555. case 3100:
  556. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1004])
  557. break;
  558. case 9200:
  559. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1003])
  560. break;
  561. case 36600:
  562. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1002])
  563. break;
  564. case 3660000:
  565. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1001])
  566. break;
  567. default:
  568. break;
  569. }
  570. self.goodsCollectionView.reloadData()
  571. }
  572. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  573. var width = (QSLConst.qsl_kScreenW - 42.0.rpx) / 3.0
  574. if self.goodList.count - 1 == 2 {
  575. width = (QSLConst.qsl_kScreenW - 36.0.rpx) / 2.0
  576. }
  577. return CGSize(width: width, height: 134.0.rpx)
  578. }
  579. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
  580. return 6.rpx
  581. }
  582. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
  583. return 3.rpx
  584. }
  585. }
  586. extension QSLVipController {
  587. func updateUI() {
  588. if QSLBaseManager.shared.isLogin() && QSLBaseManager.shared.isVip() {
  589. let model = QSLBaseManager.shared.userModel.memberModel
  590. if model.permanent {
  591. self.vipTimeLabel.text("您已是尊贵的永久会员")
  592. self.bottomView.isHidden = true
  593. } else {
  594. let level = model.memberLevelString()
  595. let endTime = model.endTimestampString()
  596. self.vipTimeLabel.text("\(level):\(endTime)到期")
  597. }
  598. } else {
  599. self.vipTimeLabel.text("升级VIP会员,解锁全部功能")
  600. }
  601. }
  602. func updateSelectGoodUI() {
  603. var priceText = ""
  604. var originalPriceText = ""
  605. if let selectGood = self.selectGood {
  606. if selectGood.amount.truncatingRemainder(dividingBy: 100) == 0 {
  607. priceText = "\(Int(selectGood.amount / 100))"
  608. } else {
  609. priceText = String(format: "%.2lf", selectGood.amount / 100 )
  610. }
  611. if selectGood.originalAmount.truncatingRemainder(dividingBy: 100) == 0 {
  612. originalPriceText = "\(Int(selectGood.originalAmount / 100))"
  613. } else {
  614. originalPriceText = String(format: "%.2lf", selectGood.originalAmount / 100 )
  615. }
  616. }
  617. self.priceLabel.text(priceText)
  618. // self.goodTypeLabel.text("/ \(self.selectGood?.name ?? "")")
  619. self.goodOriginalPriceLabel.text("原价\(originalPriceText)")
  620. }
  621. func initializeView() {
  622. self.view.addSubview(vipBg)
  623. vipBg.snp.makeConstraints { make in
  624. make.left.top.right.equalTo(0)
  625. }
  626. self.view.addSubview(backButton)
  627. backButton.snp.makeConstraints { make in
  628. make.size.equalTo(100.rpx)
  629. make.height.equalTo(25.rpx)
  630. make.left.equalTo(12.rpx)
  631. make.top.equalTo(QSLConst.qsl_kStatusBarFrameH)
  632. }
  633. self.view.addSubview(peopleCountView)
  634. peopleCountView.snp.makeConstraints { make in
  635. make.size.equalTo(CGSize(width: 212.rpx, height: 24.rpx))
  636. make.right.equalTo(-13.rpx)
  637. make.centerY.equalTo(backButton.snp.centerY)
  638. }
  639. peopleCountView.addSubview(peopleAvatarImageView)
  640. peopleAvatarImageView.snp.makeConstraints { make in
  641. make.size.equalTo(CGSize(width: 72.rpx, height: 16.6.rpx))
  642. make.left.equalTo(3.rpx)
  643. make.centerY.equalTo(peopleCountView.snp.centerY)
  644. }
  645. peopleCountView.addSubview(peopleCountLabel)
  646. peopleCountLabel.snp.makeConstraints { make in
  647. make.left.equalTo(peopleAvatarImageView.snp.right).offset(7.rpx)
  648. make.centerY.equalTo(peopleCountView.snp.centerY)
  649. }
  650. self.view.addSubview(scrollView)
  651. scrollView.snp.makeConstraints { make in
  652. make.left.right.equalTo(0)
  653. make.top.equalTo(QSLConst.qsl_kNavFrameH)
  654. make.bottom.equalTo(0)
  655. }
  656. scrollView.addSubview(cardBannerImageView)
  657. cardBannerImageView.snp.makeConstraints { make in
  658. make.top.equalTo(0)
  659. make.centerX.equalToSuperview()
  660. make.width.equalTo(336.rpx)
  661. make.height.equalTo(108.rpx)
  662. }
  663. cardBannerImageView.addSubview(vipTimeLabel)
  664. vipTimeLabel.snp.makeConstraints { make in
  665. make.left.equalTo(23.rpx)
  666. make.bottom.equalTo(-19.rpx)
  667. }
  668. scrollView.addSubview(funcBannerImageView)
  669. funcBannerImageView.snp.makeConstraints { make in
  670. make.size.equalTo(CGSize(width: 336.rpx, height: 172.rpx))
  671. make.centerX.equalToSuperview()
  672. make.top.equalTo(cardBannerImageView.snp.bottom).offset(14.rpx)
  673. }
  674. scrollView.addSubview(mainView)
  675. mainView.snp.makeConstraints { make in
  676. make.left.right.equalTo(0)
  677. make.top.equalTo(funcBannerImageView.snp.bottom).offset(-24.rpx)
  678. make.width.equalTo(QSLConst.qsl_kScreenW)
  679. // make.height.equalTo(800.rpx)
  680. }
  681. let goodsBgHeight = 54.rpx + UX.mostCellHeight
  682. mainView.addSubview(goodsBgView)
  683. goodsBgView.snp.makeConstraints { make in
  684. make.top.left.right.equalTo(0)
  685. make.width.equalTo(QSLConst.qsl_kScreenW)
  686. make.height.equalTo(goodsBgHeight)
  687. }
  688. goodsBgView.addSubview(vipGoodsTitleIcon)
  689. vipGoodsTitleIcon.snp.makeConstraints { make in
  690. make.size.equalTo(CGSize(width: 117.rpx, height: 26.rpx))
  691. make.left.equalTo(20.rpx)
  692. make.top.equalTo(16.rpx)
  693. }
  694. goodsBgView.addSubview(resumeBtn)
  695. resumeBtn.snp.makeConstraints { make in
  696. make.size.equalTo(CGSize(width: 75.rpx, height: 16.rpx))
  697. make.right.equalTo(-18.rpx)
  698. make.centerY.equalTo(vipGoodsTitleIcon.snp.centerY)
  699. }
  700. goodsBgView.addSubview(mostCell)
  701. mostCell.snp.makeConstraints { make in
  702. make.left.equalTo(12.rpx)
  703. make.right.equalTo(-16.rpx)
  704. make.height.equalTo(113.rpx)
  705. make.top.equalTo(vipGoodsTitleIcon.snp.bottom).offset(10.rpx)
  706. }
  707. goodsBgView.addSubview(goodsCollectionView)
  708. goodsCollectionView.snp.makeConstraints { make in
  709. make.left.equalTo(12.rpx)
  710. make.right.equalTo(-18.rpx)
  711. make.bottom.equalTo(-20.rpx)
  712. make.top.equalTo(mostCell.snp.bottom).offset(3.rpx)
  713. }
  714. // goodsBgView.addSubview(selectBtn)
  715. // selectBtn.snp.makeConstraints { make in
  716. // make.size.equalTo(CGSize(width: 12.rpx, height: 12.rpx))
  717. // make.left.equalTo(23.rpx)
  718. // make.top.equalTo(goodsCollectionView.snp.bottom).offset(16.rpx)
  719. // }
  720. //
  721. // goodsBgView.addSubview(serviceLabel)
  722. // serviceLabel.snp.makeConstraints { make in
  723. // make.left.equalTo(selectBtn.snp.right).offset(2.rpx)
  724. // make.centerY.equalTo(selectBtn.snp.centerY)
  725. // }
  726. mainView.addSubview(commentView)
  727. commentView.snp.makeConstraints { make in
  728. make.left.right.equalTo(0)
  729. make.top.equalTo(goodsBgView.snp.bottom).offset(8.rpx)
  730. make.height.equalTo(525.rpx + QSLConst.qsl_kTabbarBottom)
  731. make.bottom.equalTo(0)
  732. }
  733. commentView.addSubview(commentTitleIcon)
  734. commentTitleIcon.snp.makeConstraints { make in
  735. make.size.equalTo(CGSize(width: 83.rpx, height: 26.rpx))
  736. make.top.equalTo(16.rpx)
  737. make.left.equalTo(12.rpx)
  738. }
  739. let commentHeight1 = "上班没时间,远程遛娃,非常方便很好用。".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx
  740. commentView.addSubview(comment1)
  741. comment1.snp.makeConstraints { make in
  742. make.left.right.equalTo(0)
  743. make.top.equalTo(commentTitleIcon.snp.bottom).offset(16.rpx)
  744. make.height.equalTo(commentHeight1)
  745. }
  746. let commentHeight2 = "用了之后,才发现真的可以找到他。".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx
  747. commentView.addSubview(comment2)
  748. comment2.snp.makeConstraints { make in
  749. make.left.right.equalTo(0)
  750. make.top.equalTo(comment1.snp.bottom).offset(30.rpx)
  751. make.height.equalTo(commentHeight2)
  752. }
  753. let commentHeight3 = "轨迹很准,一目了然,奶奶出门遇到危险直接一键报警,我就收到信息了".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx
  754. commentView.addSubview(comment3)
  755. comment3.snp.makeConstraints { make in
  756. make.left.right.equalTo(0)
  757. make.top.equalTo(comment2.snp.bottom).offset(30.rpx)
  758. make.height.equalTo(commentHeight3)
  759. }
  760. commentView.addSubview(tipTitleLabel)
  761. commentView.addSubview(tipContentLabel)
  762. tipTitleLabel.snp.makeConstraints { make in
  763. make.left.equalTo(16)
  764. make.top.equalTo(comment3.snp.bottom).offset(28)
  765. }
  766. tipContentLabel.snp.makeConstraints { make in
  767. make.left.equalTo(16)
  768. make.right.equalTo(-16)
  769. make.top.equalTo(tipTitleLabel.snp.bottom).offset(11)
  770. }
  771. commentView.addSubview(serviceLabel)
  772. serviceLabel.snp.makeConstraints { make in
  773. make.left.equalTo(16)
  774. make.top.equalTo(tipContentLabel.snp.bottom).offset(5.rpx)
  775. }
  776. scrollView.snp.makeConstraints { make in
  777. make.bottom.equalTo(mainView)
  778. }
  779. self.view.addSubview(bottomView)
  780. bottomView.snp.makeConstraints { make in
  781. make.left.equalTo(12.rpx)
  782. make.right.equalTo(-12.rpx)
  783. make.bottom.equalTo(-QSLConst.qsl_kTabbarBottom)
  784. make.height.equalTo(50.rpx)
  785. }
  786. bottomView.addSubview(unlockBtn)
  787. unlockBtn.snp.makeConstraints { make in
  788. make.right.top.bottom.equalTo(0)
  789. make.width.equalTo(165.rpx)
  790. }
  791. bottomView.addSubview(priceIconLabel)
  792. priceIconLabel.snp.makeConstraints { make in
  793. make.left.equalTo(20.rpx)
  794. make.bottom.equalTo(-12.rpx)
  795. }
  796. bottomView.addSubview(priceLabel)
  797. priceLabel.snp.makeConstraints { make in
  798. make.left.equalTo(priceIconLabel.snp.right).offset(2.rpx)
  799. make.bottom.equalTo(-10.rpx)
  800. }
  801. bottomView.addSubview(goodTypeLabel)
  802. goodTypeLabel.snp.makeConstraints { make in
  803. make.left.equalTo(priceLabel.snp.right).offset(2.rpx)
  804. make.bottom.equalTo(-14.rpx)
  805. }
  806. bottomView.addSubview(goodOriginalPriceLabel)
  807. goodOriginalPriceLabel.snp.makeConstraints { make in
  808. make.left.equalTo(goodTypeLabel.snp.right).offset(2.rpx)
  809. make.centerY.equalTo(goodTypeLabel.snp.centerY)
  810. }
  811. }
  812. }