rewards_detail_page.dart 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. import 'package:cpt_rewards/modules/rewards_confirm/rewards_confirm_page.dart';
  2. import 'package:cs_resources/generated/l10n.dart';
  3. import 'package:cs_resources/theme/app_colors_theme.dart';
  4. import 'package:domain/entity/rewards_detail_entity.dart';
  5. import 'package:flutter/cupertino.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:auto_route/auto_route.dart';
  8. import 'package:flutter_hooks/flutter_hooks.dart';
  9. import 'package:hooks_riverpod/hooks_riverpod.dart';
  10. import 'package:router/ext/auto_router_extensions.dart';
  11. import 'package:shared/utils/log_utils.dart';
  12. import 'package:shared/utils/color_utils.dart';
  13. import 'package:widgets/ext/ex_widget.dart';
  14. import 'package:widgets/load_state_layout.dart';
  15. import 'package:widgets/my_appbar.dart';
  16. import 'package:widgets/my_load_image.dart';
  17. import 'package:widgets/my_text_view.dart';
  18. import 'package:widgets/shatter/picker_container.dart';
  19. import 'package:widgets/widget_export.dart';
  20. import 'package:cs_resources/generated/assets.dart';
  21. import '../../../router/page/rewards_page_router.dart';
  22. import './rewards_detail_vm.dart';
  23. @RoutePage()
  24. class RewardsDetailPage extends HookConsumerWidget {
  25. final int? id;
  26. const RewardsDetailPage({Key? key, @PathParam('id') required this.id})
  27. : super(key: key);
  28. //启动当前页面
  29. static void startInstance({
  30. BuildContext? context,
  31. int? id,
  32. }) {
  33. if (context != null) {
  34. context.router.push(RewardsDetailPageRoute(id: id));
  35. } else {
  36. appRouter.push(RewardsDetailPageRoute(id: id));
  37. }
  38. }
  39. // listitem
  40. Widget _buildSaleItem(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  41. String title = detailInfo!.title ?? "";
  42. String createdAt = detailInfo.createdAt ?? "";
  43. List? resources = detailInfo!.resources ?? [];
  44. int point = detailInfo.point ?? 0;
  45. int originalPoint = detailInfo.originalPoint ?? 0;
  46. String description = detailInfo.description ?? "";
  47. bool reservation = detailInfo!.reservation;
  48. String redeemedStart = detailInfo.redeemedStart ?? "";
  49. String redeemedEnd = detailInfo.redeemedEnd ?? "";
  50. String redeemedDate = '$redeemedStart-$redeemedEnd';
  51. return Column(
  52. children: [
  53. Container(
  54. decoration: const BoxDecoration(
  55. color: Colors.white,
  56. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  57. boxShadow: [
  58. BoxShadow(
  59. color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)
  60. ],
  61. ),
  62. width: MediaQuery.of(context).size.width - 30,
  63. // height: 420,
  64. // margin: const EdgeInsets.only(left: 15, right: 15, top: 12.5),
  65. child: Column(
  66. children: [
  67. resources!.length > 0
  68. ? MyLoadImage(
  69. resources[0] ?? '',
  70. width: MediaQuery.of(context).size.width,
  71. height: 150,
  72. )
  73. : Container(),
  74. Column(
  75. crossAxisAlignment: CrossAxisAlignment.start,
  76. mainAxisAlignment: MainAxisAlignment.start,
  77. children: [
  78. Text(
  79. maxLines: 1, // 设置最大行数为2
  80. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  81. title,
  82. style: const TextStyle(
  83. fontSize: 16.0,
  84. color: Colors.black,
  85. fontWeight: FontWeight.w500),
  86. ),
  87. Text(
  88. maxLines: 1, // 设置最大行数为2
  89. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  90. '${S.current.published_date}: $createdAt',
  91. style: TextStyle(
  92. fontSize: 13.0,
  93. color: ColorUtils.string2Color('#808DAF'),
  94. fontWeight: FontWeight.w400),
  95. ).marginOnly(bottom: 5),
  96. Row(
  97. children: [
  98. Text(
  99. '$point',
  100. style: const TextStyle(
  101. fontSize: 19.0,
  102. color: Colors.black,
  103. fontWeight: FontWeight.w500),
  104. ),
  105. Text(
  106. '$originalPoint',
  107. style: TextStyle(
  108. decoration: TextDecoration.lineThrough,
  109. decorationColor:
  110. ColorUtils.string2Color('#808DAF'),
  111. decorationStyle: TextDecorationStyle.solid,
  112. fontSize: 12.0,
  113. color: ColorUtils.string2Color('#808DAF'),
  114. fontWeight: FontWeight.w400),
  115. ).marginOnly(left: 5, right: 5),
  116. Text(
  117. S.current.points,
  118. style: const TextStyle(
  119. fontSize: 13.0,
  120. color: Colors.black,
  121. fontWeight: FontWeight.w400),
  122. ),
  123. ],
  124. ),
  125. Text(
  126. description,
  127. style: TextStyle(
  128. fontSize: 13.0,
  129. color: ColorUtils.string2Color('#808DAF'),
  130. fontWeight: FontWeight.w400),
  131. ).marginOnly(bottom: 10, top: 10),
  132. Container(
  133. height: 28,
  134. decoration: BoxDecoration(
  135. color: ColorUtils.string2Color('#F2F3F6'),
  136. borderRadius:
  137. const BorderRadius.all(Radius.circular(6.0)),
  138. ),
  139. child: Row(
  140. mainAxisSize: MainAxisSize.min,
  141. mainAxisAlignment: MainAxisAlignment.start,
  142. crossAxisAlignment: CrossAxisAlignment.center,
  143. children: [
  144. const MyAssetImage(
  145. Assets.rewardsRewardsDetailDay,
  146. width: 25,
  147. height: 25,
  148. ).marginOnly(right: 5),
  149. Text(
  150. maxLines: 1, // 设置最大行数为2
  151. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  152. redeemedDate,
  153. style: TextStyle(
  154. fontSize: 12.0,
  155. color: ColorUtils.string2Color('#808DAF'),
  156. fontWeight: FontWeight.w400),
  157. )
  158. ],
  159. ).paddingOnly(left: 7, right: 12)),
  160. Container(
  161. height: 28,
  162. decoration: BoxDecoration(
  163. color: ColorUtils.string2Color('#F2F3F6'),
  164. borderRadius:
  165. const BorderRadius.all(Radius.circular(6.0)),
  166. ),
  167. child: Row(
  168. mainAxisSize: MainAxisSize.min,
  169. mainAxisAlignment: MainAxisAlignment.start,
  170. crossAxisAlignment: CrossAxisAlignment.center,
  171. children: [
  172. const MyAssetImage(
  173. Assets.rewardsRewardsDetailRequired,
  174. width: 25,
  175. height: 25,
  176. ).marginOnly(right: 5),
  177. Text(
  178. maxLines: 1, // 设置最大行数为2
  179. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  180. reservation
  181. ? S.current.reservation_required
  182. : S.current.no_reservation_required,
  183. style: TextStyle(
  184. fontSize: 14.0,
  185. color: ColorUtils.string2Color('#808DAF'),
  186. fontWeight: FontWeight.w400),
  187. )
  188. ],
  189. ).paddingOnly(left: 7, right: 12))
  190. .marginOnly(top: 8, bottom: 25)
  191. ],
  192. ).paddingOnly(left: 15, right: 15, top: 10),
  193. ],
  194. )),
  195. ],
  196. ).marginOnly(left: 15, bottom: 15, right: 15);
  197. }
  198. Widget _buildDeal(BuildContext context, WidgetRef ref, _vm) {
  199. return Column(
  200. children: [
  201. Container(
  202. decoration: const BoxDecoration(
  203. color: Colors.white,
  204. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  205. boxShadow: [
  206. BoxShadow(
  207. color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)
  208. ],
  209. ),
  210. width: MediaQuery.of(context).size.width - 30,
  211. child: Column(
  212. crossAxisAlignment: CrossAxisAlignment.start,
  213. children: [
  214. Row(
  215. mainAxisSize: MainAxisSize.min,
  216. mainAxisAlignment: MainAxisAlignment.start,
  217. crossAxisAlignment: CrossAxisAlignment.center,
  218. children: [
  219. const MyAssetImage(
  220. Assets.rewardsRewardsDetailDeal,
  221. width: 25,
  222. height: 25,
  223. ).marginOnly(right: 10),
  224. Text(
  225. S.current.redeem_deal_at,
  226. style: TextStyle(
  227. fontSize: 15.0,
  228. color: ColorUtils.string2Color('#000000'),
  229. fontWeight: FontWeight.w500),
  230. )
  231. ],
  232. ),
  233. Container(
  234. height: 77,
  235. decoration: BoxDecoration(
  236. color: ColorUtils.string2Color('#F2F3F6'),
  237. borderRadius:
  238. const BorderRadius.all(Radius.circular(6.0)),
  239. ),
  240. child: Row(
  241. mainAxisSize: MainAxisSize.max,
  242. mainAxisAlignment: MainAxisAlignment.start,
  243. crossAxisAlignment: CrossAxisAlignment.center,
  244. children: [
  245. const MyAssetImage(
  246. Assets.rewardsRewardsIndex1,
  247. width: 60,
  248. height: 60,
  249. ).marginOnly(right: 15),
  250. Column(
  251. crossAxisAlignment: CrossAxisAlignment.start,
  252. children: [
  253. Text(
  254. maxLines: 1, // 设置最大行数为2
  255. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  256. 'Delibowl Group',
  257. style: TextStyle(
  258. fontSize: 15.0,
  259. color: ColorUtils.string2Color('#54638C'),
  260. fontWeight: FontWeight.w500),
  261. ).marginOnly(bottom: 8),
  262. Text(
  263. maxLines: 1, // 设置最大行数为2
  264. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  265. '#01-136, SingPost Center, 408600',
  266. style: TextStyle(
  267. fontSize: 14.0,
  268. color: ColorUtils.string2Color('#54638C'),
  269. fontWeight: FontWeight.w400),
  270. )
  271. ],
  272. ).paddingOnly(
  273. top: 5,
  274. )
  275. ],
  276. ).paddingOnly(left: 12, right: 12, bottom: 9, top: 9))
  277. .marginOnly(top: 12, bottom: 12),
  278. Row(
  279. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  280. crossAxisAlignment: CrossAxisAlignment.center,
  281. children: [
  282. Text(
  283. 'Also redeemable in 1 more location',
  284. style: TextStyle(
  285. fontSize: 15.0,
  286. color: ColorUtils.string2Color('#54638C'),
  287. fontWeight: FontWeight.w400),
  288. ),
  289. const MyAssetImage(
  290. Assets.rewardsRewardsRight,
  291. width: 12,
  292. height: 16,
  293. ),
  294. ],
  295. ),
  296. ],
  297. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  298. ),
  299. ],
  300. ).marginOnly(left: 15, bottom: 15, right: 15);
  301. }
  302. Widget _buildPackage(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  303. String package = detailInfo.package ?? "";
  304. return Column(
  305. children: [
  306. Container(
  307. decoration: const BoxDecoration(
  308. color: Colors.white,
  309. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  310. boxShadow: [
  311. BoxShadow(
  312. color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)
  313. ],
  314. ),
  315. width: MediaQuery.of(context).size.width - 30,
  316. child: Column(
  317. crossAxisAlignment: CrossAxisAlignment.start,
  318. children: [
  319. Row(
  320. mainAxisSize: MainAxisSize.min,
  321. mainAxisAlignment: MainAxisAlignment.start,
  322. crossAxisAlignment: CrossAxisAlignment.center,
  323. children: [
  324. const MyAssetImage(
  325. Assets.rewardsRewardsDetailPackage,
  326. width: 25,
  327. height: 25,
  328. ).marginOnly(right: 10),
  329. Text(
  330. 'What’s In The Package',
  331. style: TextStyle(
  332. fontSize: 15.0,
  333. color: ColorUtils.string2Color('#000000'),
  334. fontWeight: FontWeight.w500),
  335. )
  336. ],
  337. ).marginOnly(bottom: 10),
  338. Column(
  339. crossAxisAlignment: CrossAxisAlignment.start,
  340. children: [
  341. Text(
  342. package,
  343. style: TextStyle(
  344. fontSize: 15.0,
  345. color: ColorUtils.string2Color('#54638C'),
  346. fontWeight: FontWeight.w400),
  347. ),
  348. ],
  349. ),
  350. ],
  351. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  352. ),
  353. ],
  354. ).marginOnly(left: 15, bottom: 15, right: 15);
  355. }
  356. Widget _buildNotice(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  357. String notice = detailInfo.notice ?? "";
  358. return Column(
  359. children: [
  360. Container(
  361. decoration: const BoxDecoration(
  362. color: Colors.white,
  363. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  364. boxShadow: [
  365. BoxShadow(
  366. color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)
  367. ],
  368. ),
  369. width: MediaQuery.of(context).size.width - 30,
  370. child: Column(
  371. crossAxisAlignment: CrossAxisAlignment.start,
  372. children: [
  373. Row(
  374. mainAxisSize: MainAxisSize.min,
  375. mainAxisAlignment: MainAxisAlignment.start,
  376. crossAxisAlignment: CrossAxisAlignment.center,
  377. children: [
  378. const MyAssetImage(
  379. Assets.rewardsRewardsDetailNotice,
  380. width: 25,
  381. height: 25,
  382. ).marginOnly(right: 10),
  383. Text(
  384. S.current.redemption_notice,
  385. style: TextStyle(
  386. fontSize: 15.0,
  387. color: ColorUtils.string2Color('#000000'),
  388. fontWeight: FontWeight.w500),
  389. )
  390. ],
  391. ).marginOnly(bottom: 10),
  392. Column(
  393. crossAxisAlignment: CrossAxisAlignment.start,
  394. children: [
  395. Text(
  396. notice,
  397. style: TextStyle(
  398. fontSize: 15.0,
  399. color: ColorUtils.string2Color('#54638C'),
  400. fontWeight: FontWeight.w400),
  401. ),
  402. ],
  403. ),
  404. ],
  405. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  406. ),
  407. ],
  408. ).marginOnly(left: 15, bottom: 15, right: 15);
  409. }
  410. Widget _buildInstructions(BuildContext context, WidgetRef ref, _vm) {
  411. return Column(
  412. children: [
  413. Container(
  414. decoration: const BoxDecoration(
  415. color: Colors.white,
  416. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  417. boxShadow: [
  418. BoxShadow(
  419. color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)
  420. ],
  421. ),
  422. width: MediaQuery.of(context).size.width - 30,
  423. child: Column(
  424. crossAxisAlignment: CrossAxisAlignment.start,
  425. children: [
  426. Row(
  427. mainAxisSize: MainAxisSize.min,
  428. mainAxisAlignment: MainAxisAlignment.start,
  429. crossAxisAlignment: CrossAxisAlignment.center,
  430. children: [
  431. const MyAssetImage(
  432. Assets.rewardsRewardsDetailInstructions,
  433. width: 25,
  434. height: 25,
  435. ).marginOnly(right: 10),
  436. Text(
  437. S.current.redemption_instructions,
  438. style: TextStyle(
  439. fontSize: 15.0,
  440. color: ColorUtils.string2Color('#000000'),
  441. fontWeight: FontWeight.w500),
  442. )
  443. ],
  444. ).marginOnly(bottom: 10),
  445. Column(
  446. crossAxisAlignment: CrossAxisAlignment.start,
  447. children: [
  448. Text(
  449. S.current.redemption_reservation_txt,
  450. style: TextStyle(
  451. fontSize: 15.0,
  452. color: ColorUtils.string2Color('#54638C'),
  453. fontWeight: FontWeight.w400),
  454. ),
  455. ],
  456. ),
  457. ],
  458. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  459. ),
  460. ],
  461. ).marginOnly(left: 15, bottom: 15, right: 15);
  462. }
  463. Widget _buildRedeemable(
  464. BuildContext context, WidgetRef ref, _vm, detailInfo) {
  465. List? redeemable = detailInfo!.redeemable ?? [];
  466. return Column(
  467. children: [
  468. Container(
  469. decoration: const BoxDecoration(
  470. color: Colors.white,
  471. borderRadius: BorderRadius.all(Radius.circular(6.0)),
  472. boxShadow: [
  473. BoxShadow(
  474. color: Color.fromRGBO(184, 191, 217, 0.3), blurRadius: 6)
  475. ],
  476. ),
  477. width: MediaQuery.of(context).size.width - 30,
  478. child: Column(
  479. crossAxisAlignment: CrossAxisAlignment.start,
  480. children: [
  481. Row(
  482. mainAxisSize: MainAxisSize.min,
  483. mainAxisAlignment: MainAxisAlignment.start,
  484. crossAxisAlignment: CrossAxisAlignment.center,
  485. children: [
  486. const MyAssetImage(
  487. Assets.rewardsRewardsDetailNotice,
  488. width: 25,
  489. height: 25,
  490. ).marginOnly(right: 10),
  491. Text(
  492. S.current.redeemable_on,
  493. style: TextStyle(
  494. fontSize: 15.0,
  495. color: ColorUtils.string2Color('#000000'),
  496. fontWeight: FontWeight.w500),
  497. )
  498. ],
  499. ).marginOnly(bottom: 10),
  500. Column(
  501. crossAxisAlignment: CrossAxisAlignment.start,
  502. children: List.generate(
  503. redeemable!.length,
  504. (index) {
  505. final item = redeemable[index];
  506. return Text(
  507. '${item.day}: ${item.time}',
  508. style: TextStyle(
  509. fontSize: 15.0,
  510. color: ColorUtils.string2Color('#54638C'),
  511. fontWeight: FontWeight.w400),
  512. );
  513. },
  514. ),
  515. ),
  516. ],
  517. ).paddingOnly(left: 15, right: 15, top: 12, bottom: 20),
  518. ),
  519. ],
  520. ).marginOnly(left: 15, bottom: 15, right: 15);
  521. }
  522. @override
  523. Widget build(BuildContext context, WidgetRef ref) {
  524. final _vm = ref.read(rewardsDetailVmProvider.notifier);
  525. final state = ref.watch(rewardsDetailVmProvider);
  526. RewardsDetailEntity? detailInfo = state.detailInfo;
  527. useEffect(() {
  528. // 组件挂载时执行 - 执行接口请求
  529. Future.microtask(() => _vm.initPageData(id: id));
  530. return () {
  531. // 组件卸载时执行
  532. Log.d("property_news_page 组件卸载时执行");
  533. };
  534. }, []);
  535. return Scaffold(
  536. appBar: MyAppBar.appBar(
  537. context,
  538. S.current.detail,
  539. backgroundColor: context.appColors.whiteBG,
  540. ),
  541. body: LoadStateLayout(
  542. state: state.loadingState,
  543. errorMessage: state.errorMessage,
  544. errorRetry: () {
  545. _vm.retryRequest(id: id);
  546. },
  547. successWidget: Column(
  548. children: [
  549. Expanded(
  550. child: SingleChildScrollView(
  551. scrollDirection: Axis.vertical,
  552. physics: const BouncingScrollPhysics(),
  553. clipBehavior: Clip.none,
  554. child: Column(
  555. children: [
  556. Container(
  557. color: ColorUtils.string2Color('#F2F3F6'),
  558. padding: const EdgeInsets.only(top: 15),
  559. child: Column(
  560. children: [
  561. _buildSaleItem(context, ref, _vm, detailInfo),
  562. // _buildDeal(context, ref, _vm),
  563. _buildPackage(context, ref, _vm, detailInfo),
  564. _buildNotice(context, ref, _vm, detailInfo),
  565. // _buildInstructions(context, ref, _vm),
  566. _buildRedeemable(
  567. context, ref, _vm, detailInfo),
  568. ],
  569. )),
  570. ],
  571. ))),
  572. Container(
  573. height: 50,
  574. color: ColorUtils.string2Color('#4161D0'),
  575. child: Flex(
  576. direction: Axis.horizontal,
  577. children: [
  578. Expanded(
  579. flex: 1,
  580. child: Container(
  581. color: ColorUtils.string2Color('#4161D0'),
  582. height: 100,
  583. child: Row(
  584. mainAxisAlignment: MainAxisAlignment.center,
  585. crossAxisAlignment: CrossAxisAlignment.center,
  586. children: [
  587. MyTextView(
  588. S.current.redeem,
  589. fontSize: 16,
  590. textColor: Colors.white,
  591. isFontMedium: true,
  592. ),
  593. ],
  594. ),
  595. ).onTap(() {
  596. RewardsConfirmPage.startInstance(id: detailInfo?.id);
  597. }),
  598. ),
  599. ],
  600. ),
  601. )
  602. ],
  603. )),
  604. );
  605. }
  606. }