member_page.dart 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. import 'dart:io';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/gestures.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter/src/widgets/framework.dart';
  7. import 'package:flutter_screenutil/flutter_screenutil.dart';
  8. import 'package:get/get.dart';
  9. import 'package:get/get_core/src/get_main.dart';
  10. import 'package:location/base/base_page.dart';
  11. import 'package:location/module/member/member_controller.dart';
  12. import 'package:location/resource/assets.gen.dart';
  13. import 'package:location/resource/colors.gen.dart';
  14. import 'package:location/utils/common_expand.dart';
  15. import 'package:location/utils/project_expand.dart';
  16. import 'package:location/widget/auto_scroll_list_view.dart';
  17. import '../../data/bean/member_status_info.dart';
  18. import '../../data/bean/pay_item_bean.dart';
  19. import '../../data/consts/payment_type.dart';
  20. import '../../resource/fonts.gen.dart';
  21. import '../../resource/string.gen.dart';
  22. import '../../router/app_pages.dart';
  23. import '../../utils/date_util.dart';
  24. import '../../widget/animated_switcher_widget.dart';
  25. import 'member_discount_countdown_widget.dart';
  26. import 'member_evaluate_bean.dart';
  27. import 'member_header_cycle_widget.dart';
  28. ///进入会员类型
  29. enum MemberPageType {
  30. ///通用进入
  31. universalAccessEnter,
  32. ///倒计时试用完会员进入
  33. afeterTrialMemberEnter,
  34. ///加好友进入
  35. addFriendToEnter,
  36. }
  37. class MemberPage extends BasePage<MemberController> {
  38. MemberPage({super.key,this.pageType});
  39. late MemberPageType? pageType = MemberPageType.universalAccessEnter;
  40. static void start({MemberPageType? enterTyp = MemberPageType.universalAccessEnter}) {
  41. Get.toNamed(RoutePath.member,arguments: enterTyp);
  42. }
  43. @override
  44. bool immersive() {
  45. return true;
  46. }
  47. @override
  48. bool statusBarDarkFont() {
  49. return false;
  50. }
  51. @override
  52. Widget buildBody(BuildContext context) {
  53. return PopScope(
  54. canPop: false,
  55. onPopInvokedWithResult: (bool didPop, dynamic result) async {
  56. controller.onPopBack();
  57. },
  58. child: Stack(
  59. children: [
  60. SingleChildScrollView(
  61. physics: const ClampingScrollPhysics(),
  62. controller: controller.scrollController,
  63. child: Stack(
  64. children: [
  65. MemberHeaderCycleWidget(),
  66. Column(
  67. children: [
  68. SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top),
  69. Container(
  70. decoration: BoxDecoration(
  71. color: ColorName.white,
  72. borderRadius: BorderRadius.only(
  73. topLeft: Radius.circular(20.w),
  74. topRight: Radius.circular(20.w)),
  75. ),
  76. child: Stack(
  77. children: [
  78. Container(
  79. decoration: BoxDecoration(
  80. borderRadius: BorderRadius.only(
  81. topLeft: Radius.circular(20.w),
  82. topRight: Radius.circular(20.w)),
  83. image: DecorationImage(
  84. image: Assets.images.iconMemberVipMiddleBg.provider(),
  85. )
  86. ),
  87. width: double.infinity,
  88. height: 174,
  89. ),
  90. Container(
  91. //width: double.infinity,
  92. decoration: BoxDecoration(
  93. borderRadius: BorderRadius.only(
  94. topLeft: Radius.circular(20.w),
  95. topRight: Radius.circular(20.w)),
  96. image: DecorationImage(image: Assets.images.iconMemberVipMiddleBg.provider())
  97. ),
  98. child: Column(
  99. crossAxisAlignment: CrossAxisAlignment.start,
  100. children: [
  101. SizedBox(height: 15.w),
  102. buildUserInfoView(),
  103. SizedBox(height: 23.w),
  104. buildGoodsList(),
  105. SizedBox(height: 12.w),
  106. buildPrivacyPolicyView(),
  107. buildPayWayView(),
  108. SizedBox(height: 30.w),
  109. Padding(
  110. padding: EdgeInsets.only(left: 12.w),
  111. child: Text(StringName.memberEquityIntroduction,
  112. style: TextStyle(
  113. fontSize: 16.sp,
  114. color: ColorName.black90,
  115. fontWeight: FontWeight.bold)),
  116. ),
  117. SizedBox(height: 19.w),
  118. buildFunctionList(),
  119. SizedBox(height: 40.w),
  120. Padding(
  121. padding: EdgeInsets.only(left: 12.w),
  122. child: Text(StringName.memberUserEvaluate,
  123. style: TextStyle(
  124. fontSize: 16.sp,
  125. color: ColorName.black90,
  126. fontWeight: FontWeight.bold)),
  127. ),
  128. SizedBox(height: 8.w),
  129. buildUserEvaluateList(),
  130. SizedBox(height: 20.w),
  131. Container(
  132. padding: EdgeInsets.all(12.w),
  133. decoration: BoxDecoration(
  134. color: '#F7F7F7'.color,
  135. borderRadius: BorderRadius.circular(6.w)),
  136. margin: EdgeInsets.symmetric(horizontal: 12.w),
  137. child: Text(StringName.memberTips,
  138. style: TextStyle(
  139. fontSize: 12.sp, color: '#A7A7A7'.color)),
  140. ),
  141. SizedBox(height: 100.w)
  142. ],
  143. ),
  144. ),
  145. ],
  146. ),
  147. )
  148. ],
  149. ),
  150. ],
  151. )
  152. /*Stack(
  153. children: [
  154. Assets.images.bgMemberHeader.image(width: double.infinity),
  155. SafeArea(
  156. child: Column(
  157. children: [
  158. SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top),
  159. buildUserInfoView(),
  160. SizedBox(height: 26.w),
  161. Container(
  162. width: double.infinity,
  163. decoration: BoxDecoration(
  164. borderRadius: BorderRadius.only(
  165. topLeft: Radius.circular(14.w),
  166. topRight: Radius.circular(14.w)),
  167. gradient: LinearGradient(
  168. begin: Alignment.topCenter,
  169. end: Alignment.bottomCenter,
  170. stops: [0.0, 0.1],
  171. colors: ['#EFE9FF'.color, Colors.white])),
  172. child: Column(
  173. crossAxisAlignment: CrossAxisAlignment.start,
  174. children: [
  175. SizedBox(height: 23.w),
  176. buildGoodsList(),
  177. SizedBox(height: 12.w),
  178. buildPrivacyPolicyView(),
  179. buildPayWayView(),
  180. SizedBox(height: 30.w),
  181. Padding(
  182. padding: EdgeInsets.only(left: 12.w),
  183. child: Text(StringName.memberEquityIntroduction,
  184. style: TextStyle(
  185. fontSize: 16.sp,
  186. color: ColorName.black90,
  187. fontWeight: FontWeight.bold)),
  188. ),
  189. SizedBox(height: 19.w),
  190. buildFunctionList(),
  191. SizedBox(height: 40.w),
  192. Padding(
  193. padding: EdgeInsets.only(left: 12.w),
  194. child: Text(StringName.memberUserEvaluate,
  195. style: TextStyle(
  196. fontSize: 16.sp,
  197. color: ColorName.black90,
  198. fontWeight: FontWeight.bold)),
  199. ),
  200. SizedBox(height: 8.w),
  201. buildUserEvaluateList(),
  202. SizedBox(height: 20.w),
  203. Container(
  204. padding: EdgeInsets.all(12.w),
  205. decoration: BoxDecoration(
  206. color: '#F7F7F7'.color,
  207. borderRadius: BorderRadius.circular(6.w)),
  208. margin: EdgeInsets.symmetric(horizontal: 12.w),
  209. child: Text(StringName.memberTips,
  210. style: TextStyle(
  211. fontSize: 12.sp, color: '#A7A7A7'.color)),
  212. ),
  213. SizedBox(height: 100.w)
  214. ],
  215. ),
  216. )
  217. ],
  218. ),
  219. )
  220. ],
  221. ),*/
  222. ),
  223. buildHeadBar(),
  224. buildMemberBottomView()
  225. ],
  226. ),
  227. );
  228. }
  229. Widget buildGoodsList() {
  230. return Obx(() {
  231. return SizedBox(
  232. height: 123.w,
  233. child: ListView.builder(
  234. padding: EdgeInsets.only(left: 12.w),
  235. physics: const BouncingScrollPhysics(
  236. parent: AlwaysScrollableScrollPhysics()),
  237. scrollDirection: Axis.horizontal,
  238. itemBuilder: (BuildContext ctx, int index) {
  239. return Obx(() {
  240. final item = controller.goodsList[index];
  241. bool isSelected = controller.selectedGoods?.id == item.id;
  242. return GestureDetector(
  243. behavior: HitTestBehavior.translucent,
  244. onTap: () => controller.onGoodsItemClick(item),
  245. child: Container(
  246. margin: EdgeInsets.only(right: 10.w),
  247. width: 138.w,
  248. height: 123.w,
  249. child: Stack(
  250. children: [
  251. Container(
  252. width: double.infinity,
  253. height: double.infinity,
  254. decoration: BoxDecoration(
  255. color: isSelected
  256. ? '#6BC4BAFF'.color
  257. : ColorName.white20,
  258. borderRadius: BorderRadius.circular(18.w),
  259. border: Border.all(
  260. color: isSelected
  261. ? '#C4BAFF'.color
  262. : '#E8E8E8'.color,
  263. width: 3.w)),
  264. padding: EdgeInsets.only(left: 10.w),
  265. child: Column(
  266. crossAxisAlignment: CrossAxisAlignment.start,
  267. children: [
  268. Spacer(flex: 2),
  269. Text(
  270. item.name,
  271. style: TextStyle(
  272. fontSize: 14.sp,
  273. color: ColorName.black90,
  274. fontWeight: FontWeight.bold),
  275. ),
  276. SizedBox(height: 3.w),
  277. Text('¥${item.originalAmount.divideBy100()}',
  278. style: TextStyle(
  279. decoration: TextDecoration.lineThrough,
  280. fontSize: 10.sp,
  281. color: ColorName.black60)),
  282. Spacer(flex: 1),
  283. RichText(
  284. text: TextSpan(
  285. style: TextStyle(
  286. color: isSelected
  287. ? '#EA1231'.color
  288. : ColorName.black80,
  289. fontWeight: FontWeight.bold),
  290. children: [
  291. TextSpan(
  292. text: '¥',
  293. style: TextStyle(
  294. fontSize: 20.sp, height: 1)),
  295. TextSpan(
  296. text: item.amount.divideBy100(),
  297. style: TextStyle(
  298. fontSize: 34.sp,
  299. height: 1,
  300. fontFamily: FontFamily.oppoSans))
  301. ])),
  302. Padding(
  303. padding: EdgeInsets.only(left: 7.w),
  304. child: Text(item.description ?? '',
  305. style: TextStyle(
  306. fontSize: 12.sp,
  307. color: ColorName.black40)),
  308. ),
  309. Spacer(
  310. flex: 1,
  311. )
  312. ],
  313. ),
  314. ),
  315. Visibility(
  316. visible: item.tag?.isNotEmpty == true,
  317. child: Positioned(
  318. top: 0,
  319. right: 0,
  320. child: Container(
  321. decoration: BoxDecoration(
  322. gradient: LinearGradient(colors: [
  323. '#A26CFF'.color,
  324. '#FF7CD8'.color,
  325. '#898BFF'.color
  326. ]),
  327. borderRadius: BorderRadius.only(
  328. topRight: Radius.circular(11.w),
  329. bottomLeft: Radius.circular(11.w))),
  330. padding: EdgeInsets.symmetric(
  331. horizontal: 10.w, vertical: 4.w),
  332. child: Text(item.tag ?? '',
  333. style: TextStyle(
  334. fontSize: 12.sp,
  335. color: Colors.white)),
  336. ),
  337. ))
  338. ],
  339. )),
  340. );
  341. });
  342. },
  343. itemCount: controller.goodsList.length),
  344. );
  345. });
  346. }
  347. Widget buildMemberBottomView() {
  348. return Obx(() {
  349. return Visibility(
  350. visible: controller.memberStatusInfo == null ||
  351. controller.memberStatusInfo?.permanent == false,
  352. child: Align(
  353. alignment: Alignment.bottomCenter,
  354. child: Container(//top: 98.w,
  355. alignment: Alignment.bottomCenter,
  356. height: 190.w + MediaQuery.of(Get.context!).padding.bottom,
  357. padding: EdgeInsets.only(
  358. left: 12.w, right: 12.w, bottom: 17.w + MediaQuery.of(Get.context!).padding.bottom),
  359. decoration: BoxDecoration(
  360. gradient: LinearGradient(
  361. begin: Alignment.bottomCenter, // 0deg 相当于从底部开始
  362. end: Alignment.topCenter,
  363. colors: [
  364. Colors.white, // #FFF
  365. "#00FFFFFF".color,
  366. ],
  367. stops: [0.4368, 1.0], // 对应 43.68% 和 100%
  368. ),
  369. ),
  370. child: Obx(() {
  371. return Column(
  372. mainAxisAlignment: MainAxisAlignment.end,
  373. children: [
  374. Container(
  375. width: double.infinity, // 设置容器宽度
  376. height: 50.w, // 设置容器高度
  377. padding: EdgeInsets.only(left: 20.w),
  378. decoration: BoxDecoration(
  379. image: DecorationImage(
  380. image: Assets.images.iconMemberSettlementBg.provider(),
  381. fit: BoxFit.fill,
  382. ),
  383. ),
  384. // 实现内阴影效果
  385. child: Row(
  386. children: [
  387. Transform.translate(
  388. offset: Offset(0, 3), // 向下偏移4像素
  389. child: Text('¥',
  390. style: TextStyle(
  391. fontSize: 14.sp,
  392. color: '#FFF8EF'.color,
  393. fontWeight: FontWeight.bold)),
  394. ),
  395. SizedBox(width: 3.w,),
  396. Text(
  397. controller.selectedGoods?.amount.divideBy100() ?? '--',
  398. style: TextStyle(
  399. fontSize: 24.sp,
  400. color: '#FFF8EF'.color,
  401. fontWeight: FontWeight.bold),
  402. ),
  403. SizedBox(width: 3.w,),
  404. Text("/",
  405. style: TextStyle(
  406. fontSize: 12.sp,
  407. fontWeight: FontWeight.w400,
  408. color: "#FFF8EF".color),),
  409. Text('原价${controller.selectedGoods?.originalAmount.divideBy100()}',
  410. style: TextStyle(
  411. decoration: TextDecoration.lineThrough,
  412. decorationColor: Colors.white,
  413. decorationThickness: 1.0,
  414. fontSize: 12.sp,
  415. fontWeight: FontWeight.w400,
  416. color: "#FFF8EF".color)),
  417. Spacer(),
  418. GestureDetector(
  419. onTap: controller.onBuyClick,
  420. child: Container(
  421. decoration: BoxDecoration(
  422. image: DecorationImage(
  423. image: Assets.images.iconMemberSettlementConfirm.provider(),
  424. fit: BoxFit.fill,
  425. )
  426. ),
  427. // width: 164.w,
  428. // height: 44.w,
  429. padding: EdgeInsets.only(left: 64.w,right: 29.w),
  430. child: Center(
  431. child: Text(
  432. controller.memberStatusInfo?.expired == false
  433. ? StringName.memberVipRenew
  434. : StringName.memberVipUnlock,
  435. style: TextStyle(
  436. fontSize: 18.sp,
  437. color: "#9B3800".color,
  438. fontWeight: FontWeight.bold),
  439. ),
  440. ),
  441. ),
  442. )
  443. ],
  444. ),
  445. ),
  446. SizedBox(height: 8.w,),
  447. buildPrivacyPolicyView(),
  448. ],
  449. );
  450. }),
  451. ),
  452. ),
  453. );
  454. });
  455. }
  456. Widget buildUserInfoView() {
  457. return Row(
  458. children: [
  459. SizedBox(width: 18.w),
  460. controller.isLogin ? ClipOval(
  461. child: Container(
  462. width: 32.w,
  463. height: 32.w,
  464. child: CachedNetworkImage(
  465. imageUrl: controller.memberStatusInfo?.avatar ?? "",
  466. fit: BoxFit.cover,
  467. ),
  468. ),
  469. ) : Assets.images.iconMemberAvatar.image(width: 32.w, height: 32.w),
  470. SizedBox(width: 7.w),
  471. Column(
  472. crossAxisAlignment: CrossAxisAlignment.start,
  473. children: [
  474. Obx(() {
  475. return GestureDetector(
  476. onTap: controller.onLoginClick,
  477. child: Text(
  478. controller.phone?.isNotEmpty == true
  479. ? controller.getUserName(controller.phone!)
  480. : StringName.mineAccountGoLogin,
  481. style: TextStyle(
  482. fontSize: 13.sp,
  483. color: "#333333".color,
  484. fontWeight: FontWeight.bold)),
  485. );
  486. }),
  487. Container(
  488. height: 16.w,
  489. width: MediaQuery.of(Get.context!).size.width - 77.w,
  490. child: Row(
  491. // 主轴默认左对齐,通过Spacer推挤右侧内容
  492. children: [
  493. // 左侧内容:会员等级描述 + VIP卡片描述
  494. Visibility(
  495. visible: MemberStatusInfo.getLevelDesc(controller.memberStatusInfo).isNotEmpty,
  496. child: Text(
  497. MemberStatusInfo.getLevelDesc(controller.memberStatusInfo),
  498. style: TextStyle(
  499. fontSize: 11.sp,
  500. fontWeight: FontWeight.w700,
  501. color: '#9144F8'.color
  502. )
  503. ),
  504. ),
  505. buildMemberCardVipDesc(),
  506. Spacer(),
  507. Container(
  508. child: MemberDiscountCountdownWidget(
  509. onExpired: () {
  510. print("sssfsdfs");
  511. controller.isShowCount.value = false;
  512. },
  513. ),
  514. )
  515. ],
  516. ),
  517. )
  518. ],
  519. ),
  520. SizedBox(width: 20.w)
  521. ],
  522. );
  523. }
  524. // Spacer(),
  525. // Container(
  526. // decoration: BoxDecoration(
  527. // color: '#272F51'.color,
  528. // border: Border.all(color: '#99CAB0F0'.color, width: 1.w),
  529. // borderRadius: BorderRadius.circular(100.w),
  530. // ),
  531. // padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 6.w),
  532. // child: Obx(() {
  533. // return Text(
  534. // MemberStatusInfo.getLevelDesc(controller.memberStatusInfo),
  535. // style: TextStyle(fontSize: 12.sp, color: '#D2CCFF'.color));
  536. // })),
  537. Widget buildMemberCardVipDesc() {
  538. return Obx(() {
  539. String desc = '';
  540. if (!controller.isLogin) {
  541. //desc = StringName.memberCardNoLoginDesc;
  542. desc =
  543. '${DateUtil.fromMillisecondsSinceEpoch('yyyy-MM-dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}';
  544. } else if (controller.memberStatusInfo == null ||
  545. controller.memberStatusInfo?.expired == true) {
  546. desc = StringName.memberCardNoVipDesc;
  547. } else if (controller.memberStatusInfo?.expired == false &&
  548. controller.memberStatusInfo?.permanent == true) {
  549. desc = StringName.memberCardPermanentVipDesc;
  550. } else {
  551. desc =
  552. '${DateUtil.fromMillisecondsSinceEpoch('yyyy-MM-dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}';
  553. }
  554. return Text(desc,
  555. style: TextStyle(fontSize: 11.sp, color: ColorName.black50,fontWeight: FontWeight.w400));
  556. });
  557. }
  558. Widget buildHeadBar() {
  559. return Obx(() {
  560. return Stack(
  561. children: [
  562. IgnorePointer(
  563. child: Container(
  564. color: ColorName.colorPrimary.withOpacity(controller.toolBarOpacity),
  565. child: SafeArea(
  566. child: SizedBox(
  567. width: double.infinity,
  568. height: 56.w,
  569. ),
  570. ),
  571. ),
  572. ),
  573. SafeArea(
  574. child: SizedBox(
  575. width: double.infinity,
  576. height: 56.w,
  577. child: Stack(alignment: Alignment.center, children: [
  578. Positioned(
  579. left: 15.w,
  580. child: GestureDetector(
  581. onTap: () => controller.onPopBack(),
  582. child: Assets.images.iconMemberVipBack
  583. .image(width: 26.w, height: 26..w),
  584. )),
  585. Container(
  586. padding: EdgeInsets.only(left: 51.w,right: 12.w),
  587. child: buildVerticalSlideshowWidget())
  588. ]),
  589. ),
  590. ),
  591. ],
  592. );
  593. });
  594. }
  595. Widget buildVerticalSlideshowWidget() {
  596. return Row(
  597. children: [
  598. Visibility(visible: !Platform.isIOS, child: Spacer()),
  599. Container(
  600. width: 192.w,
  601. height: 26.w,
  602. decoration: BoxDecoration(
  603. color: ColorName.black40,
  604. borderRadius: BorderRadius.circular(87.w),
  605. ),
  606. child: Center(
  607. child: AnimatedSwitcherWidget(
  608. controller: controller.switcherController)),
  609. ),
  610. Spacer(),
  611. Visibility(
  612. visible: Platform.isIOS && controller.accountRepository.isLogin.value,
  613. child: GestureDetector(
  614. onTap: controller.clickRecoverSubscribe,
  615. child: Container(
  616. height: 26.w,
  617. decoration: BoxDecoration(
  618. color: ColorName.black40,
  619. borderRadius: BorderRadius.circular(26.w / 2.0),
  620. ),
  621. padding: EdgeInsets.symmetric(horizontal: 10.w),
  622. child: Row(
  623. children: [
  624. Assets.images.iconAppleRecoverSubscribe.image(width: 14.w,height: 14.w),
  625. Text(StringName.appleRecoverSubscribeTxt,
  626. style: TextStyle(
  627. fontSize: 11.sp,
  628. color: ColorName.white,
  629. fontWeight: FontWeight.w500)),
  630. ],
  631. ),
  632. ),
  633. )
  634. )
  635. ],
  636. );
  637. }
  638. Widget buildPrivacyPolicyView() {
  639. return Padding(
  640. padding: EdgeInsets.only(left: 12.w),
  641. child: RichText(
  642. text: TextSpan(
  643. style: TextStyle(fontSize: 12.sp, color: ColorName.black40),
  644. children: [
  645. TextSpan(text: '购买前请先阅读'),
  646. TextSpan(
  647. recognizer: TapGestureRecognizer()
  648. ..onTap = () {
  649. controller.onPrivacyPolicyClick();
  650. },
  651. text: '隐私政策',
  652. style: TextStyle(
  653. color: ColorName.black60,
  654. decoration: TextDecoration.underline)),
  655. TextSpan(text: '&'),
  656. TextSpan(
  657. recognizer: TapGestureRecognizer()
  658. ..onTap = () {
  659. controller.onTermOfServiceClick();
  660. },
  661. text: '服务条款',
  662. style: TextStyle(
  663. color: ColorName.black60,
  664. decoration: TextDecoration.underline)),
  665. ])),
  666. );
  667. }
  668. Widget buildFunctionList() {
  669. return SizedBox(
  670. height: 80.w,
  671. child: AutoScrollListView(
  672. padding: EdgeInsets.only(left: 12.w),
  673. itemBuilder: (ctx, index) {
  674. final item = controller.funList[index];
  675. return Padding(
  676. padding: EdgeInsets.only(right: 20.w),
  677. child: Column(
  678. children: [
  679. Image.asset(item.iconPath, width: 36.w, height: 36.w),
  680. Spacer(flex: 3),
  681. Text(item.funName,
  682. style: TextStyle(
  683. fontSize: 12.8.sp,
  684. color: ColorName.black90,
  685. fontWeight: FontWeight.bold)),
  686. Spacer(flex: 2),
  687. Text(item.funDesc,
  688. style: TextStyle(
  689. fontSize: 10.6.sp,
  690. color: ColorName.black50,
  691. )),
  692. ],
  693. ),
  694. );
  695. },
  696. itemCount: controller.funList.length));
  697. }
  698. Widget buildUserEvaluateList() {
  699. return Column(
  700. children: [
  701. for (int index = 0; index < controller.evaluateList.length; index++)
  702. buildUserEvaluateItem(controller.evaluateList[index],
  703. index == controller.evaluateList.length - 1)
  704. ],
  705. );
  706. }
  707. Widget buildUserEvaluateItem(MemberEvaluateBean item, bool isLast) {
  708. return Column(
  709. crossAxisAlignment: CrossAxisAlignment.start,
  710. children: [
  711. SizedBox(height: 20.w),
  712. Row(
  713. children: [
  714. SizedBox(width: 12.w),
  715. Image.asset(item.avatarPath, width: 24.w, height: 24.w),
  716. SizedBox(width: 8.w),
  717. Text(
  718. item.userName,
  719. style: TextStyle(fontSize: 14.sp, color: Colors.black),
  720. )
  721. ],
  722. ),
  723. SizedBox(height: 1.w),
  724. Padding(
  725. padding: EdgeInsets.only(left: 44.w, right: 12.w),
  726. child: Text(
  727. item.userEvaluate,
  728. style: TextStyle(fontSize: 14.sp, color: '#BF000000'.color),
  729. )),
  730. SizedBox(height: 20.w),
  731. Visibility(
  732. child: Container(
  733. margin: EdgeInsets.only(left: 26.w),
  734. width: 288.w,
  735. color: '#21000000'.color,
  736. height: 1.w),
  737. )
  738. ],
  739. );
  740. }
  741. Widget buildPayWayView() {
  742. return Obx(() {
  743. return Visibility(
  744. visible: Platform.isIOS ? false : controller.payItemList.isNotEmpty,
  745. child: Container(
  746. margin: EdgeInsets.only(top: 7.w),
  747. child: Column(
  748. children: [
  749. for (PayItemBean item in controller.payItemList)
  750. buildPayWayItem(item)
  751. ],
  752. ),
  753. ),
  754. );
  755. });
  756. }
  757. Widget buildPayWayItem(PayItemBean item) {
  758. return GestureDetector(
  759. behavior: HitTestBehavior.translucent,
  760. onTap: () => controller.onPayWayItemClick(item),
  761. child: Obx(() {
  762. bool isSelected = controller.selectedPayWay?.id == item.id;
  763. return Container(
  764. padding: EdgeInsets.symmetric(vertical: 10.w),
  765. child: Row(
  766. children: [
  767. SizedBox(width: 12.w),
  768. Image.asset(
  769. getPaymentIconPath(
  770. payMethod: item.payMethod, payPlatform: item.payPlatform),
  771. width: 24.w,
  772. height: 24.w),
  773. SizedBox(width: 6.w),
  774. Text(item.title,
  775. style: TextStyle(fontSize: 14.sp, color: ColorName.black90)),
  776. Spacer(),
  777. Image.asset(
  778. isSelected
  779. ? Assets.images.iconCbSelected.path
  780. : Assets.images.iconCbUnSelect.path,
  781. width: 20.w,
  782. height: 20.w),
  783. SizedBox(width: 20.w),
  784. ],
  785. ),
  786. );
  787. }),
  788. );
  789. }
  790. }