QSLVipController.swift 43 KB

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