QSLVipController.swift 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  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 bottomContentView: UIView = {
  253. let view = UIView()
  254. return view
  255. }()
  256. lazy var bottomTopView: UIView = {
  257. let view = UIView()
  258. view.isHidden = true
  259. view.backgroundColor = .hexStringColor(hexString: "#FFFED8")
  260. view.addRadius(radius: 30.rpx)
  261. return view
  262. }()
  263. lazy var bottomTopLabel: UILabel = {
  264. let label = UILabel()
  265. label.text = ""
  266. return label
  267. }()
  268. func bottomTopLabelInfo(_ goodInfo : QSLGoodModel) {
  269. let darkGrayAttributes: [NSAttributedString.Key: Any] = [
  270. .foregroundColor: UIColor.hexStringColor(hexString: "#404040"),
  271. .font: UIFont.systemFont(ofSize: 11),
  272. .paragraphStyle: {
  273. let paragraphStyle = NSMutableParagraphStyle()
  274. paragraphStyle.alignment = .center
  275. return paragraphStyle
  276. }(),
  277. .kern: -1
  278. ]
  279. // 创建绿色文本样式
  280. let greenAttributes: [NSAttributedString.Key: Any] = [
  281. .foregroundColor: UIColor.hexStringColor(hexString: "#EE6C1C"),
  282. .font: UIFont.systemFont(ofSize: 15, weight: .black),
  283. .paragraphStyle: {
  284. let paragraphStyle = NSMutableParagraphStyle()
  285. paragraphStyle.alignment = .center
  286. return paragraphStyle
  287. }(),
  288. .kern: -1
  289. ]
  290. let textArray = goodInfo.text.components(separatedBy: goodInfo.keys.key)
  291. if textArray.count > 0 {
  292. bottomTopView.isHidden = false
  293. let inputtr = NSMutableAttributedString()
  294. let titleOneAttr = NSAttributedString(string: textArray.first ?? "", attributes: darkGrayAttributes)
  295. let titleTwoAttr = NSAttributedString(string: " \(goodInfo.keys.value) ", attributes: greenAttributes)
  296. inputtr.append(titleOneAttr)
  297. inputtr.append(titleTwoAttr)
  298. if textArray.count > 1 {
  299. let titleThreeAttr = NSAttributedString(string: textArray[1], attributes: darkGrayAttributes)
  300. inputtr.append(titleThreeAttr)
  301. }
  302. bottomTopLabel.attributedText = inputtr
  303. } else {
  304. bottomTopView.isHidden = true
  305. }
  306. }
  307. lazy var bottomView: UIView = {
  308. let view = UIView()
  309. view.gradientBackgroundColor(color1: .hexStringColor(hexString: "#00434E"), color2: .hexStringColor(hexString: "#0E5E61"), width: QSLConst.qsl_kScreenW - 24.rpx, height: 50.rpx, direction: .horizontal)
  310. view.addRadius(radius: 25.rpx)
  311. return view
  312. }()
  313. lazy var unlockBtn: UIButton = {
  314. let btn = UIButton()
  315. btn.setBackgroundImage(UIImage(named: "vip_unlock_btn_bg"), for: .normal)
  316. btn.title("立即解锁")
  317. btn.textColor(.hexStringColor(hexString: "#9B3800"))
  318. btn.mediumFont(18)
  319. btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: 30.rpx, bottom: 0, right: 0)
  320. btn.addTarget(self, action: #selector(unlockBtnAction), for: .touchUpInside)
  321. return btn
  322. }()
  323. lazy var priceIconLabel: UILabel = {
  324. let label = UILabel()
  325. label.text("¥")
  326. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  327. label.font(14)
  328. return label
  329. }()
  330. lazy var priceLabel: UILabel = {
  331. let label = UILabel()
  332. label.text("168")
  333. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  334. label.font(24)
  335. return label
  336. }()
  337. lazy var goodTypeLabel: UILabel = {
  338. let label = UILabel()
  339. label.text("/")
  340. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  341. label.font(12)
  342. return label
  343. }()
  344. lazy var goodOriginalPriceLabel: UILabel = {
  345. let label = UILabel()
  346. label.text("原价228")
  347. label.textColor = .hexStringColor(hexString: "#FFF8EF")
  348. label.font(12)
  349. label.centerLineText(lineValue: 1, underlineColor: .hexStringColor(hexString: "#FFF8EF"))
  350. return label
  351. }()
  352. override func viewDidLoad() {
  353. super.viewDidLoad()
  354. initializeView()
  355. updateUI()
  356. requestItemList()
  357. calculateBuyCount()
  358. if let type = self.type {
  359. switch type {
  360. case .homeRoad:
  361. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1001])
  362. case .add:
  363. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1002])
  364. case .friendRoad:
  365. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1003])
  366. case .contact:
  367. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1004])
  368. case .mine:
  369. gravityInstance?.track(QSLGravityConst.vip_show, properties: ["id": 1006])
  370. }
  371. }
  372. }
  373. }
  374. extension QSLVipController {
  375. @objc func privacyAction() {
  376. let vc = QSLWebViewController()
  377. vc.webUrl = QSLConfig.AppPrivacyAgreementLink
  378. vc.title = "隐私政策"
  379. self.navigationController?.pushViewController(vc, animated: true)
  380. }
  381. @objc func serviceAction() {
  382. let vc = QSLWebViewController()
  383. vc.webUrl = QSLConfig.AppServiceAgreementLink
  384. vc.title = "服务协议"
  385. self.navigationController?.pushViewController(vc, animated: true)
  386. }
  387. @objc func subscibeAction() {
  388. let vc = QSLWebViewController()
  389. vc.webUrl = QSLConfig.AppSubscibeAgreementLink
  390. vc.title = "续订说明"
  391. self.navigationController?.pushViewController(vc, animated: true)
  392. }
  393. @objc func selectBtnAction() {
  394. selectBtn.isSelected = !selectBtn.isSelected
  395. }
  396. // 恢复按钮点击
  397. @objc func resumeBtnAction() {
  398. let memberModel = QSLBaseManager.shared.userModel.memberModel
  399. let expired = memberModel.expired
  400. if !expired {
  401. QSLLoading.success(text: "您已经在订阅中,无需恢复")
  402. return
  403. }
  404. QSLLoading.show()
  405. QSLVipManager.shared.restoreAction { isSuccess in
  406. QSLVipManager.shared.isPaying = false
  407. if isSuccess {
  408. QSLNetwork().request(.userMember(dict: [:])) { response in
  409. let model = response.mapObject(QSLMemberModel.self, modelKey: "data")
  410. QSLBaseManager.shared.userModel.memberModel = model
  411. if model.expired {
  412. QSLBaseManager.shared.saveVipExpiredTime(time: 0)
  413. } else {
  414. QSLBaseManager.shared.saveVipExpiredTime(time: model.endTimestamp)
  415. }
  416. QSLBaseManager.shared.saveUserId(id: model.userId)
  417. if model.endTimestamp > memberModel.endTimestamp {
  418. QSLLoading.success(text: "恢复成功")
  419. // 支付成功通知
  420. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
  421. self.navigationController?.popViewController(animated: true)
  422. }
  423. } else {
  424. QSLLoading.error(text: "没有可供恢复的订阅")
  425. }
  426. } fail: { code, error in
  427. QSLLoading.error(text: "没有可供恢复的订阅")
  428. }
  429. } else {
  430. QSLLoading.error(text: "没有可供恢复的订阅")
  431. }
  432. }
  433. }
  434. // 支付按钮点击
  435. @objc func unlockBtnAction() {
  436. switch self.selectGood?.level {
  437. case 100 :
  438. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1006])
  439. break
  440. case 700:
  441. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1005])
  442. break;
  443. case 3100:
  444. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1004])
  445. break;
  446. case 9200:
  447. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1003])
  448. break;
  449. case 36600:
  450. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1002])
  451. break;
  452. case 3660000:
  453. gravityInstance?.track(QSLGravityConst.vip_buy_click, properties: ["id": 1001])
  454. break;
  455. default:
  456. break;
  457. }
  458. // if !selectBtn.isSelected {
  459. // self.view.toast(text: "请先同意《隐私权政策》和《用户协议》")
  460. // return
  461. // }
  462. let memberModel = QSLBaseManager.shared.userModel.memberModel
  463. if let subscriptionExpired = memberModel.subscriptionExpired, !subscriptionExpired {
  464. self.view.toast(text: "你已经订阅了")
  465. return
  466. }
  467. if goodList.count > 0, let selectGood = self.selectGood {
  468. QSLLoading.show()
  469. QSLVipManager.shared.startPay(goods: selectGood) { [self] status, outTradeNo in
  470. QSLVipManager.shared.isPaying = false
  471. if status == .success {
  472. QSLLoading.success(text: "支付成功")
  473. //支付成功埋点
  474. gravityInstance?.track(QSLGravityConst.vip_submit_success, properties: ["id": 01001])
  475. //弹出是否好评的弹窗
  476. QSLGuideusersToCommentManager.commentShare.manageWhetherTriggerPopUpWindow(QSLGuideusersToCommentType.member)
  477. // 引力传递支付事件
  478. if let selectGood = self.selectGood {
  479. gravityInstance?.trackPayEvent(withAmount: Int32(selectGood.amount), withPayType: "CNY", withOrderId: outTradeNo, withPayReason: selectGood.name, withPayMethod: "apple")
  480. }
  481. #if DEBUG
  482. #else
  483. //苹果广告奇异果传递支付事件
  484. QSWikiHandle.shared.addEventResultAttribution(eventDict: ["event_name": "pay", "event_val": selectGood.amount])
  485. #endif
  486. if let type = self.type {
  487. switch type {
  488. case .homeRoad:
  489. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1001])
  490. case .add:
  491. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1002])
  492. case .friendRoad:
  493. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1003])
  494. case .contact:
  495. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1004])
  496. case .mine:
  497. gravityInstance?.track(QSLGravityConst.vip_success_page, properties: ["id": 1006])
  498. }
  499. }
  500. switch self.selectGood?.level {
  501. case 100 :
  502. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 1])
  503. break
  504. case 700:
  505. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 5])
  506. break;
  507. case 3100:
  508. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 9])
  509. break;
  510. case 9200:
  511. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 13])
  512. break;
  513. case 36600:
  514. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 17])
  515. break;
  516. case 3660000:
  517. gravityInstance?.track(QSLGravityConst.vip_success_good, properties: ["id": 21])
  518. break;
  519. default:
  520. break;
  521. }
  522. DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
  523. self.navigationController?.popViewController(animated: true)
  524. NotificationCenter.default.post(name: QSLNotification.QSLRefreshMember, object: nil)
  525. }
  526. } else if status == .cancel {
  527. QSLLoading.error(text: "支付取消")
  528. } else if status == .fail {
  529. gravityInstance?.track(QSLGravityConst.vip_fail)
  530. QSLLoading.error(text: "支付失败")
  531. } else if status == .searchFail {
  532. QSLLoading.error(text: "查询订单失败,请稍后重试")
  533. }
  534. }
  535. }
  536. }
  537. @objc func firstCellClickAction() {
  538. for i in 0..<self.goodList.count {
  539. self.goodList[i].isSelect = false
  540. }
  541. if self.goodList.count > 0 {
  542. self.goodList[0].isSelect = true
  543. self.selectGood = self.goodList[0]
  544. self.mostCell.config(model: self.goodList[0])
  545. }
  546. switch self.selectGood?.level {
  547. case 100 :
  548. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1006])
  549. break
  550. case 700:
  551. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1005])
  552. break;
  553. case 3100:
  554. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1004])
  555. break;
  556. case 9200:
  557. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1003])
  558. break;
  559. case 36600:
  560. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1002])
  561. break;
  562. case 3660000:
  563. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1001])
  564. break;
  565. default:
  566. break;
  567. }
  568. self.goodsCollectionView.reloadData()
  569. }
  570. }
  571. extension QSLVipController {
  572. // 请求商品列表
  573. func requestItemList() {
  574. QSLNetwork().request(.vipItemList(dict: ["itemListType": 2])) { response in
  575. let list = response.mapArray(QSLGoodModel.self, modelKey: "data>list")
  576. self.goodList = list
  577. if self.goodList.count > 0 {
  578. self.goodList[0].isSelect = true
  579. self.selectGood = self.goodList[0]
  580. self.mostCell.config(model: self.goodList[0])
  581. let row = ceil(Double(self.goodList.count - 1) / 3.0)
  582. let height = UX.goodsBgHeight + (row * UX.collectionRowHeight)
  583. self.goodsBgView.gradientBackgroundColor(color1: .hexStringColor(hexString: "#FFF8F2"), color2: .hexStringColor(hexString: "#FFFFFF"), width: QSLConst.qsl_kScreenW, height: height, direction: .vertical)
  584. self.goodsBgView.snp.updateConstraints { make in
  585. make.height.equalTo(height)
  586. }
  587. self.scrollView.snp.makeConstraints { make in
  588. make.bottom.equalTo(self.mainView)
  589. }
  590. self.checkRenewalOfProducts()
  591. }
  592. self.goodsCollectionView.reloadData()
  593. } fail: { code, error in
  594. self.view.toast(text: "加载商品列表失败")
  595. }
  596. }
  597. ///检查有没有续订的产品
  598. func checkRenewalOfProducts() {
  599. let hasSubscribable = self.goodList.contains(where: { model in
  600. return model.subscribable == 1
  601. })
  602. if hasSubscribable == false {
  603. tipContentLabel.isHidden = true
  604. hideSubscribeDescription()
  605. serviceLabel.snp.removeConstraints()
  606. serviceLabel.snp.makeConstraints { make in
  607. make.left.equalTo(16)
  608. make.top.equalTo(comment3.snp.bottom).offset(28.rpx)
  609. }
  610. } else {
  611. tipContentLabel.isHidden = false
  612. showSubscribeDescription()
  613. }
  614. }
  615. // 计算购买人数
  616. func calculateBuyCount() {
  617. var num = 145883
  618. if let localNum = UserDefaults.standard.value(forKey: QSLConfig.user_default_local_buy_count) as? Int {
  619. num = localNum
  620. }
  621. let randomAddCount = Int.random(in: 1...10)
  622. num = num + randomAddCount
  623. UserDefaults.standard.setValue(num, forKey: QSLConfig.user_default_local_buy_count)
  624. self.peopleCountLabel.text("\(num)人 已开通VIP")
  625. }
  626. }
  627. // MARK: - 设置 CollectionView
  628. extension QSLVipController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
  629. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  630. return goodList.count - 1
  631. }
  632. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  633. let cell = collectionView.dequeueReusableCell(cellType: QSLVipGoodCollectionViewCell.self, cellForRowAt: indexPath)
  634. let model = self.goodList[indexPath.row + 1]
  635. if self.goodList.count - 1 == 2 {
  636. cell.config(model: model, type: .big)
  637. } else {
  638. cell.config(model: model, type: .small)
  639. }
  640. return cell
  641. }
  642. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  643. for i in 0..<self.goodList.count {
  644. self.goodList[i].isSelect = false
  645. }
  646. if self.goodList.count > 0 {
  647. self.goodList[indexPath.row + 1].isSelect = true
  648. self.selectGood = self.goodList[indexPath.row + 1]
  649. self.mostCell.config(model: self.goodList[0])
  650. }
  651. switch self.selectGood?.level {
  652. case 100 :
  653. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1006])
  654. break
  655. case 700:
  656. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1005])
  657. break;
  658. case 3100:
  659. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1004])
  660. break;
  661. case 9200:
  662. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1003])
  663. break;
  664. case 36600:
  665. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1002])
  666. break;
  667. case 3660000:
  668. gravityInstance?.track(QSLGravityConst.vip_good_select, properties: ["id": 1001])
  669. break;
  670. default:
  671. break;
  672. }
  673. self.goodsCollectionView.reloadData()
  674. }
  675. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  676. var width = (QSLConst.qsl_kScreenW - 42.0.rpx) / 3.0
  677. if self.goodList.count - 1 == 2 {
  678. width = (QSLConst.qsl_kScreenW - 36.0.rpx) / 2.0
  679. }
  680. return CGSize(width: width, height: 134.0.rpx)
  681. }
  682. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
  683. return 6.rpx
  684. }
  685. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
  686. return 3.rpx
  687. }
  688. }
  689. extension QSLVipController {
  690. func updateUI() {
  691. if QSLBaseManager.shared.isLogin() && QSLBaseManager.shared.isVip() {
  692. let model = QSLBaseManager.shared.userModel.memberModel
  693. if model.permanent {
  694. self.vipTimeLabel.text("您已是尊贵的永久会员")
  695. self.bottomContentView.isHidden = true
  696. } else {
  697. let level = model.memberLevelString()
  698. let endTime = model.endTimestampString()
  699. self.vipTimeLabel.text("\(level):\(endTime)到期")
  700. }
  701. } else {
  702. self.vipTimeLabel.text("升级VIP会员,解锁全部功能")
  703. }
  704. }
  705. func updateSelectGoodUI() {
  706. var priceText = ""
  707. var originalPriceText = ""
  708. if let selectGood = self.selectGood {
  709. if selectGood.amount.truncatingRemainder(dividingBy: 100) == 0 {
  710. priceText = "\(Int(selectGood.amount / 100))"
  711. } else {
  712. priceText = String(format: "%.2lf", selectGood.amount / 100 )
  713. }
  714. if selectGood.originalAmount.truncatingRemainder(dividingBy: 100) == 0 {
  715. originalPriceText = "\(Int(selectGood.originalAmount / 100))"
  716. } else {
  717. originalPriceText = String(format: "%.2lf", selectGood.originalAmount / 100 )
  718. }
  719. }
  720. self.priceLabel.text(priceText)
  721. // self.goodTypeLabel.text("/ \(self.selectGood?.name ?? "")")
  722. self.goodOriginalPriceLabel.text("原价\(originalPriceText)")
  723. ///底部内容
  724. bottomTopLabelInfo(self.selectGood ?? QSLGoodModel())
  725. }
  726. func initializeView() {
  727. self.view.addSubview(vipBg)
  728. vipBg.snp.makeConstraints { make in
  729. make.left.top.right.equalTo(0)
  730. }
  731. self.view.addSubview(backButton)
  732. backButton.snp.makeConstraints { make in
  733. make.size.equalTo(100.rpx)
  734. make.height.equalTo(25.rpx)
  735. make.left.equalTo(12.rpx)
  736. make.top.equalTo(QSLConst.qsl_kStatusBarFrameH)
  737. }
  738. self.view.addSubview(peopleCountView)
  739. peopleCountView.snp.makeConstraints { make in
  740. make.size.equalTo(CGSize(width: 212.rpx, height: 24.rpx))
  741. make.right.equalTo(-13.rpx)
  742. make.centerY.equalTo(backButton.snp.centerY)
  743. }
  744. peopleCountView.addSubview(peopleAvatarImageView)
  745. peopleAvatarImageView.snp.makeConstraints { make in
  746. make.size.equalTo(CGSize(width: 72.rpx, height: 16.6.rpx))
  747. make.left.equalTo(3.rpx)
  748. make.centerY.equalTo(peopleCountView.snp.centerY)
  749. }
  750. peopleCountView.addSubview(peopleCountLabel)
  751. peopleCountLabel.snp.makeConstraints { make in
  752. make.left.equalTo(peopleAvatarImageView.snp.right).offset(7.rpx)
  753. make.centerY.equalTo(peopleCountView.snp.centerY)
  754. }
  755. self.view.addSubview(scrollView)
  756. scrollView.snp.makeConstraints { make in
  757. make.left.right.equalTo(0)
  758. make.top.equalTo(QSLConst.qsl_kNavFrameH)
  759. make.bottom.equalTo(0)
  760. }
  761. scrollView.addSubview(cardBannerImageView)
  762. cardBannerImageView.snp.makeConstraints { make in
  763. make.top.equalTo(0)
  764. make.centerX.equalToSuperview()
  765. make.width.equalTo(336.rpx)
  766. make.height.equalTo(108.rpx)
  767. }
  768. cardBannerImageView.addSubview(vipTimeLabel)
  769. vipTimeLabel.snp.makeConstraints { make in
  770. make.left.equalTo(23.rpx)
  771. make.bottom.equalTo(-19.rpx)
  772. }
  773. scrollView.addSubview(funcBannerImageView)
  774. funcBannerImageView.snp.makeConstraints { make in
  775. make.size.equalTo(CGSize(width: 336.rpx, height: 172.rpx))
  776. make.centerX.equalToSuperview()
  777. make.top.equalTo(cardBannerImageView.snp.bottom).offset(14.rpx)
  778. }
  779. scrollView.addSubview(mainView)
  780. mainView.snp.makeConstraints { make in
  781. make.left.right.equalTo(0)
  782. make.top.equalTo(funcBannerImageView.snp.bottom).offset(-24.rpx)
  783. make.width.equalTo(QSLConst.qsl_kScreenW)
  784. // make.height.equalTo(800.rpx)
  785. }
  786. let goodsBgHeight = 54.rpx + UX.mostCellHeight
  787. mainView.addSubview(goodsBgView)
  788. goodsBgView.snp.makeConstraints { make in
  789. make.top.left.right.equalTo(0)
  790. make.width.equalTo(QSLConst.qsl_kScreenW)
  791. make.height.equalTo(goodsBgHeight)
  792. }
  793. goodsBgView.addSubview(vipGoodsTitleIcon)
  794. vipGoodsTitleIcon.snp.makeConstraints { make in
  795. make.size.equalTo(CGSize(width: 117.rpx, height: 26.rpx))
  796. make.left.equalTo(20.rpx)
  797. make.top.equalTo(16.rpx)
  798. }
  799. goodsBgView.addSubview(resumeBtn)
  800. resumeBtn.snp.makeConstraints { make in
  801. make.size.equalTo(CGSize(width: 75.rpx, height: 16.rpx))
  802. make.right.equalTo(-18.rpx)
  803. make.centerY.equalTo(vipGoodsTitleIcon.snp.centerY)
  804. }
  805. goodsBgView.addSubview(mostCell)
  806. mostCell.snp.makeConstraints { make in
  807. make.left.equalTo(12.rpx)
  808. make.right.equalTo(-16.rpx)
  809. make.height.equalTo(113.rpx)
  810. make.top.equalTo(vipGoodsTitleIcon.snp.bottom).offset(10.rpx)
  811. }
  812. goodsBgView.addSubview(goodsCollectionView)
  813. goodsCollectionView.snp.makeConstraints { make in
  814. make.left.equalTo(12.rpx)
  815. make.right.equalTo(-18.rpx)
  816. make.bottom.equalTo(-20.rpx)
  817. make.top.equalTo(mostCell.snp.bottom).offset(3.rpx)
  818. }
  819. // goodsBgView.addSubview(selectBtn)
  820. // selectBtn.snp.makeConstraints { make in
  821. // make.size.equalTo(CGSize(width: 12.rpx, height: 12.rpx))
  822. // make.left.equalTo(23.rpx)
  823. // make.top.equalTo(goodsCollectionView.snp.bottom).offset(16.rpx)
  824. // }
  825. //
  826. // goodsBgView.addSubview(serviceLabel)
  827. // serviceLabel.snp.makeConstraints { make in
  828. // make.left.equalTo(selectBtn.snp.right).offset(2.rpx)
  829. // make.centerY.equalTo(selectBtn.snp.centerY)
  830. // }
  831. mainView.addSubview(commentView)
  832. commentView.snp.makeConstraints { make in
  833. make.left.right.equalTo(0)
  834. make.top.equalTo(goodsBgView.snp.bottom).offset(8.rpx)
  835. make.height.equalTo(525.rpx + QSLConst.qsl_kTabbarBottom)
  836. make.bottom.equalTo(0)
  837. }
  838. commentView.addSubview(commentTitleIcon)
  839. commentTitleIcon.snp.makeConstraints { make in
  840. make.size.equalTo(CGSize(width: 83.rpx, height: 26.rpx))
  841. make.top.equalTo(16.rpx)
  842. make.left.equalTo(12.rpx)
  843. }
  844. let commentHeight1 = "上班没时间,远程遛娃,非常方便很好用。".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx
  845. commentView.addSubview(comment1)
  846. comment1.snp.makeConstraints { make in
  847. make.left.right.equalTo(0)
  848. make.top.equalTo(commentTitleIcon.snp.bottom).offset(16.rpx)
  849. make.height.equalTo(commentHeight1)
  850. }
  851. let commentHeight2 = "用了之后,才发现真的可以找到他。".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx
  852. commentView.addSubview(comment2)
  853. comment2.snp.makeConstraints { make in
  854. make.left.right.equalTo(0)
  855. make.top.equalTo(comment1.snp.bottom).offset(30.rpx)
  856. make.height.equalTo(commentHeight2)
  857. }
  858. let commentHeight3 = "轨迹很准,一目了然,奶奶出门遇到危险直接一键报警,我就收到信息了".heightAccording(width: QSLConst.qsl_kScreenW - 52.rpx - 12.rpx, font: .textF(15), lineSpacing: 2) + 35.rpx
  859. commentView.addSubview(comment3)
  860. comment3.snp.makeConstraints { make in
  861. make.left.right.equalTo(0)
  862. make.top.equalTo(comment2.snp.bottom).offset(30.rpx)
  863. make.height.equalTo(commentHeight3)
  864. }
  865. // commentView.addSubview(tipTitleLabel)
  866. // tipTitleLabel.snp.makeConstraints { make in
  867. // make.left.equalTo(16)
  868. // make.top.equalTo(comment3.snp.bottom).offset(28)
  869. // }
  870. commentView.addSubview(tipContentLabel)
  871. tipContentLabel.snp.makeConstraints { make in
  872. make.left.equalTo(16)
  873. make.right.equalTo(-16)
  874. make.top.equalTo(comment3.snp.bottom).offset(11)
  875. }
  876. commentView.addSubview(serviceLabel)
  877. serviceLabel.snp.makeConstraints { make in
  878. make.left.equalTo(16)
  879. make.top.equalTo(tipContentLabel.snp.bottom).offset(28.rpx)
  880. }
  881. scrollView.snp.makeConstraints { make in
  882. make.bottom.equalTo(mainView)
  883. }
  884. self.view.addSubview(bottomContentView)
  885. bottomContentView.snp.makeConstraints { make in
  886. make.left.equalTo(12.rpx)
  887. make.right.equalTo(-12.rpx)
  888. make.bottom.equalTo(-QSLConst.qsl_kTabbarBottom)
  889. make.height.equalTo(72.rpx)
  890. }
  891. bottomContentView.addSubview(bottomTopView)
  892. bottomTopView.snp.makeConstraints { make in
  893. make.left.equalToSuperview()
  894. make.right.equalToSuperview()
  895. make.top.equalToSuperview()
  896. make.height.equalTo(60.rpx)
  897. }
  898. bottomTopView.addSubview(bottomTopLabel)
  899. bottomTopLabel.snp.makeConstraints { make in
  900. make.left.equalToSuperview().offset(22)
  901. make.top.equalToSuperview()
  902. make.height.equalTo(21.rpx)
  903. }
  904. bottomContentView.addSubview(bottomView)
  905. bottomView.snp.makeConstraints { make in
  906. make.left.equalToSuperview()
  907. make.right.equalToSuperview()
  908. make.bottom.equalToSuperview()
  909. make.height.equalTo(50.rpx)
  910. }
  911. bottomView.addSubview(unlockBtn)
  912. unlockBtn.snp.makeConstraints { make in
  913. make.right.top.bottom.equalTo(0)
  914. make.width.equalTo(165.rpx)
  915. }
  916. bottomView.addSubview(priceIconLabel)
  917. priceIconLabel.snp.makeConstraints { make in
  918. make.left.equalTo(20.rpx)
  919. make.bottom.equalTo(-12.rpx)
  920. }
  921. bottomView.addSubview(priceLabel)
  922. priceLabel.snp.makeConstraints { make in
  923. make.left.equalTo(priceIconLabel.snp.right).offset(2.rpx)
  924. make.bottom.equalTo(-10.rpx)
  925. }
  926. bottomView.addSubview(goodTypeLabel)
  927. goodTypeLabel.snp.makeConstraints { make in
  928. make.left.equalTo(priceLabel.snp.right).offset(2.rpx)
  929. make.bottom.equalTo(-14.rpx)
  930. }
  931. bottomView.addSubview(goodOriginalPriceLabel)
  932. goodOriginalPriceLabel.snp.makeConstraints { make in
  933. make.left.equalTo(goodTypeLabel.snp.right).offset(2.rpx)
  934. make.centerY.equalTo(goodTypeLabel.snp.centerY)
  935. }
  936. }
  937. }