QSLVipController.swift 38 KB

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