view.dart 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. import 'package:electronic_assistant/base/base_page.dart';
  2. import 'package:electronic_assistant/data/bean/payment_way.dart';
  3. import 'package:electronic_assistant/resource/assets.gen.dart';
  4. import 'package:electronic_assistant/resource/colors.gen.dart';
  5. import 'package:electronic_assistant/router/app_pages.dart';
  6. import 'package:electronic_assistant/utils/expand.dart';
  7. import 'package:flutter/material.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:get/get.dart';
  10. import '../../data/bean/store_item.dart';
  11. import '../../data/consts/Constants.dart';
  12. import 'controller.dart';
  13. enum StoreFromType { home, mine, analyse }
  14. class StorePage extends BasePage<StoreController> {
  15. const StorePage({super.key});
  16. static start({StoreFromType? fromType}) {
  17. Get.toNamed(RoutePath.store, arguments: {'fromType': fromType});
  18. }
  19. @override
  20. Color backgroundColor() {
  21. return "#071935".color;
  22. }
  23. @override
  24. Color navigationBarColor() {
  25. return "#283B58".color;
  26. }
  27. @override
  28. bool statusBarDarkFont() {
  29. return false;
  30. }
  31. @override
  32. bool immersive() {
  33. return true;
  34. }
  35. //47.67
  36. @override
  37. Widget buildBody(BuildContext context) {
  38. return Stack(
  39. children: [
  40. SingleChildScrollView(
  41. child: _buildStoreContent(),
  42. ),
  43. Align(
  44. alignment: Alignment.bottomCenter,
  45. child: _buildBottomButton(),
  46. ),
  47. Positioned(
  48. left: 0,
  49. right: 0,
  50. child: AppBar(
  51. backgroundColor: Colors.transparent,
  52. scrolledUnderElevation: 0,
  53. leading: IconButton(
  54. color: Colors.white,
  55. icon: const Icon(Icons.arrow_back_ios_new_rounded),
  56. onPressed: () {
  57. Get.back();
  58. },
  59. ),
  60. actions: [_buildElectricBalance()],
  61. ),
  62. ),
  63. ],
  64. );
  65. }
  66. _buildElectricBalance() {
  67. return Container(
  68. padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.w),
  69. margin: EdgeInsets.only(right: 12.w),
  70. decoration: BoxDecoration(
  71. borderRadius: BorderRadius.circular(100.w),
  72. border: Border.all(
  73. color: "#7688B1".toColor(),
  74. width: 1.w,
  75. )),
  76. child: Row(
  77. children: [
  78. Assets.images.iconStoreLogo.image(width: 20.w, height: 20.w),
  79. Container(
  80. margin: EdgeInsets.symmetric(horizontal: 3.w),
  81. child: Text("电量",
  82. style: TextStyle(color: Colors.white, fontSize: 12.w)),
  83. ),
  84. Obx(() {
  85. return Text('${controller.userInfo?.memberInfo?.electric ?? '0'}',
  86. style: TextStyle(color: Colors.white, fontSize: 12.w));
  87. }),
  88. ],
  89. ),
  90. );
  91. }
  92. _buildStoreContent() {
  93. return Stack(
  94. children: [
  95. _buildTopBanner(),
  96. Column(
  97. children: [
  98. Container(
  99. margin: EdgeInsets.only(top: 315.w),
  100. height: 154.w,
  101. child: Obx(() => ListView.builder(
  102. itemBuilder: _buildStoreItem,
  103. itemCount: controller.storeItems.length,
  104. scrollDirection: Axis.horizontal,
  105. )),
  106. ),
  107. Container(
  108. margin: EdgeInsets.only(left: 12.w, right: 12.w, top: 18.w),
  109. alignment: Alignment.centerLeft,
  110. child: Obx(() => Text(
  111. " · ${controller.currentSelectedStoreItem.value?.itemDesc}",
  112. style: TextStyle(
  113. fontSize: 10.sp,
  114. color: "#AFAFAF".color,
  115. fontWeight: FontWeight.bold))),
  116. ),
  117. Visibility(
  118. visible: GetPlatform.isAndroid,
  119. child: _buildPaymentWays(),
  120. ),
  121. _buildService(),
  122. _buildRule(),
  123. SizedBox(height: 80.w)
  124. ],
  125. ),
  126. ],
  127. );
  128. }
  129. _buildTopBanner() {
  130. return Stack(alignment: AlignmentDirectional.bottomStart, children: [
  131. Assets.images.bgStoreTop.image(),
  132. Container(
  133. margin: EdgeInsets.only(left: 12.w, bottom: 73.33.w),
  134. child: Assets.images.iconStoreDescripe.image(width: 268.w))
  135. ]);
  136. }
  137. Widget _buildStoreItem(BuildContext context, int index) {
  138. StoreItem storeItem = controller.storeItems[index];
  139. return GestureDetector(
  140. onTap: () => controller.onStoreItemClick(storeItem),
  141. child: Container(
  142. margin: EdgeInsets.only(
  143. left: index == 0 ? 12.w : 10.w,
  144. right: index == controller.storeItems.length - 1 ? 12.w : 0),
  145. child: Stack(
  146. children: [
  147. Obx(() =>
  148. controller.currentSelectedStoreItem.value?.id == storeItem.id
  149. ? _buildSelectedItemContent(storeItem)
  150. : _buildUnselectedItemContent(storeItem)),
  151. Visibility(
  152. visible: storeItem.popular,
  153. child: Container(
  154. padding: EdgeInsets.only(
  155. left: 8.w, right: 8.w, top: 2.w, bottom: 10.w),
  156. decoration: BoxDecoration(
  157. image: DecorationImage(
  158. image: Assets.images.iconStoreGoodTag.provider(),
  159. fit: BoxFit.fill,
  160. ),
  161. ),
  162. child: Text("最多人购买",
  163. style: TextStyle(
  164. color: "#703D27".color,
  165. fontSize: 12.sp,
  166. fontWeight: FontWeight.bold)),
  167. ),
  168. ),
  169. ],
  170. ),
  171. ),
  172. );
  173. }
  174. Widget _buildSelectedItemContent(StoreItem storeItem) {
  175. return Container(
  176. width: 132.w,
  177. margin: EdgeInsets.only(top: 9.w),
  178. decoration: BoxDecoration(
  179. borderRadius: BorderRadius.circular(12.w),
  180. gradient: LinearGradient(
  181. colors: ['#9075FF'.color, '#4366FF'.color],
  182. begin: Alignment.centerLeft,
  183. end: Alignment.centerRight,
  184. stops: const [0.0, 1.0],
  185. ),
  186. ),
  187. child: Container(
  188. margin: EdgeInsets.all(2.w),
  189. decoration: BoxDecoration(
  190. gradient: LinearGradient(
  191. colors: ['#DADBFF'.color, '#FFF3F6'.color],
  192. begin: Alignment.centerLeft,
  193. end: Alignment.centerRight,
  194. stops: const [0.0, 1.0],
  195. ),
  196. borderRadius: BorderRadius.circular(12.w),
  197. ),
  198. child: _buildItemContent(storeItem, true),
  199. ),
  200. );
  201. }
  202. Widget _buildUnselectedItemContent(StoreItem storeItem) {
  203. return Container(
  204. width: 132.w,
  205. margin: EdgeInsets.only(top: 9.w),
  206. padding: EdgeInsets.all(2.w),
  207. decoration: BoxDecoration(
  208. borderRadius: BorderRadius.circular(12.w), color: "#40567D".color),
  209. child: _buildItemContent(storeItem, false),
  210. );
  211. }
  212. Widget _buildItemContent(StoreItem storeItem, bool isSelect) {
  213. return Column(
  214. children: [
  215. Container(
  216. margin: EdgeInsets.only(top: 14.w),
  217. child: Text(storeItem.name,
  218. style: TextStyle(
  219. color: isSelect ? "#6177F2".color : Colors.white,
  220. fontSize: 13.sp,
  221. fontWeight: FontWeight.bold)),
  222. ),
  223. Container(
  224. margin: EdgeInsets.only(top: 10.w),
  225. child: RichText(
  226. text: TextSpan(
  227. children: [
  228. TextSpan(
  229. text: "¥",
  230. style: TextStyle(
  231. color: isSelect ? "#6177F2".color : Colors.white,
  232. fontSize: 16.sp,
  233. ),
  234. ),
  235. TextSpan(
  236. text: storeItem.amountText,
  237. style: TextStyle(
  238. color: isSelect ? "#6177F2".color : Colors.white,
  239. fontSize: 39.sp,
  240. fontWeight: FontWeight.bold,
  241. ),
  242. ),
  243. ],
  244. )),
  245. ),
  246. Text("¥${storeItem.originalAmountText}",
  247. style: TextStyle(
  248. color: "#AFAFAF".color,
  249. fontSize: 14.sp,
  250. decoration: TextDecoration.lineThrough,
  251. decorationColor: "#AFAFAF".color)),
  252. Container(
  253. padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.w),
  254. decoration: isSelect
  255. ? BoxDecoration(
  256. gradient: LinearGradient(
  257. colors: ['#9075FF'.color, '#4366FF'.color],
  258. begin: Alignment.topCenter,
  259. end: Alignment.bottomCenter,
  260. stops: const [0.0, 1.0],
  261. ),
  262. borderRadius: BorderRadius.circular(12.w),
  263. )
  264. : BoxDecoration(
  265. color: "#7688B1".toColor(),
  266. borderRadius: BorderRadius.circular(12.w),
  267. ),
  268. child: Row(
  269. mainAxisSize: MainAxisSize.min,
  270. children: [
  271. SizedBox(
  272. width: 16.w,
  273. height: 16.w,
  274. child: Assets.images.iconStoreGoodFlash.image(),
  275. ),
  276. Text(
  277. "${storeItem.authValue}电量",
  278. style: TextStyle(
  279. color: Colors.white,
  280. fontSize: 13.sp,
  281. fontWeight: FontWeight.bold,
  282. ),
  283. ),
  284. ],
  285. ),
  286. ),
  287. ],
  288. );
  289. }
  290. Widget _buildPaymentWays() {
  291. return Container(
  292. margin: EdgeInsets.only(top: 10.w),
  293. child: ExpansionTile(
  294. initiallyExpanded: true,
  295. onExpansionChanged: (value) {
  296. controller.isPaymentWayExpanded.value = value;
  297. },
  298. title: Padding(
  299. padding: EdgeInsets.symmetric(horizontal: 12.w),
  300. child: Row(
  301. children: [
  302. Text("支付方式",
  303. style: TextStyle(color: Colors.white, fontSize: 14.sp)),
  304. const Spacer(),
  305. Obx(() =>
  306. controller.currentSelectedPaymentWay.value?._icon ??
  307. Container()),
  308. Container(
  309. margin: EdgeInsets.only(left: 6.w, right: 4.w),
  310. child: Obx(() => Text(
  311. controller.currentSelectedPaymentWay.value?.title ?? "",
  312. style: TextStyle(color: Colors.white, fontSize: 14.sp))),
  313. ),
  314. Obx(() => controller.isPaymentWayExpanded.value
  315. ? Assets.images.iconArrowUpWhite
  316. .image(width: 16.w, height: 16.w)
  317. : Assets.images.iconArrowDownWhite
  318. .image(width: 16.w, height: 16.w)),
  319. ],
  320. ),
  321. ),
  322. showTrailingIcon: false,
  323. shape: const RoundedRectangleBorder(
  324. side: BorderSide(color: Colors.transparent),
  325. ),
  326. collapsedShape: const RoundedRectangleBorder(
  327. side: BorderSide(color: Colors.transparent),
  328. ),
  329. minTileHeight: 15.w,
  330. tilePadding: EdgeInsets.zero,
  331. children: [
  332. Obx(() => ListView.builder(
  333. shrinkWrap: true,
  334. physics: const NeverScrollableScrollPhysics(),
  335. padding: EdgeInsets.symmetric(horizontal: 12.w),
  336. itemBuilder: _buildPaymentWayItem,
  337. itemCount: controller.paymentWays.length,
  338. scrollDirection: Axis.vertical,
  339. )),
  340. ],
  341. ),
  342. );
  343. }
  344. Widget _buildPaymentWayItem(BuildContext context, int index) {
  345. PaymentWay paymentWay = controller.paymentWays[index];
  346. return GestureDetector(
  347. onTap: () => controller.onPaymentWayItemClick(paymentWay),
  348. child: Padding(
  349. padding: EdgeInsets.symmetric(vertical: 6.w),
  350. child: Row(
  351. children: [
  352. paymentWay._icon,
  353. Expanded(
  354. child: Container(
  355. margin: EdgeInsets.only(left: 8.w),
  356. child: Text(controller.paymentWays[index].title,
  357. style: TextStyle(color: Colors.white, fontSize: 14.sp)),
  358. ),
  359. ),
  360. Obx(() => SizedBox(
  361. width: 20.w,
  362. height: 20.w,
  363. child: controller.currentSelectedPaymentWay.value?.id ==
  364. paymentWay.id
  365. ? Assets.images.iconSelectTrue.image()
  366. : Assets.images.iconSelectFalse.image())),
  367. ],
  368. ),
  369. ),
  370. );
  371. }
  372. Widget _buildService() {
  373. return Container(
  374. margin: EdgeInsets.only(left: 12.w, right: 12.w, top: 30.w),
  375. child: Column(
  376. children: [
  377. Row(
  378. children: [
  379. Container(
  380. width: 4.w,
  381. height: 16.h,
  382. decoration: BoxDecoration(
  383. color: Colors.white,
  384. borderRadius: BorderRadius.circular(2),
  385. gradient: LinearGradient(
  386. colors: [
  387. '#357AFF'.toColor(),
  388. '#E389FF'.toColor(),
  389. '#ffffff'.toColor()
  390. ],
  391. begin: Alignment.topCenter,
  392. end: Alignment.bottomCenter,
  393. stops: const [0.0, 0.5, 1.0],
  394. ),
  395. ),
  396. ),
  397. SizedBox(
  398. width: 6.w,
  399. ),
  400. Text(
  401. "多种专属服务·高效辅助办公",
  402. style: TextStyle(
  403. fontSize: 15.sp,
  404. color: Colors.white,
  405. fontWeight: FontWeight.w500,
  406. ),
  407. ),
  408. ],
  409. ),
  410. Container(
  411. margin: EdgeInsets.only(top: 16.w),
  412. child: Row(
  413. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  414. children: [
  415. _buildServiceItem(
  416. Assets.images.iconStoreServiceSum.image(),
  417. "智能谈话总结",
  418. ),
  419. _buildServiceItem(
  420. Assets.images.iconStoreServiceRemain.image(),
  421. "待办任务处理",
  422. ),
  423. _buildServiceItem(
  424. Assets.images.iconStoreServiceAdvice.image(),
  425. "专业工作建议",
  426. ),
  427. _buildServiceItem(
  428. Assets.images.iconStoreServiceDeal.image(),
  429. "处理交代事宜",
  430. ),
  431. ],
  432. ),
  433. )
  434. ],
  435. ),
  436. );
  437. }
  438. Widget _buildServiceItem(Image icon, String title) {
  439. return Column(
  440. children: [
  441. SizedBox(
  442. width: 32.w,
  443. child: icon,
  444. ),
  445. SizedBox(
  446. height: 2.h,
  447. ),
  448. Text(
  449. title,
  450. style: TextStyle(
  451. color: ColorName.white.withOpacity(0.8),
  452. fontSize: 11.sp,
  453. ),
  454. ),
  455. ],
  456. );
  457. }
  458. Container _buildRule() {
  459. return Container(
  460. margin: EdgeInsets.only(top: 26.w, left: 12.w, right: 12.w),
  461. width: double.infinity,
  462. padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
  463. decoration: BoxDecoration(
  464. color: "#40567D".toColor().withOpacity(0.2),
  465. borderRadius: BorderRadius.circular(8),
  466. ),
  467. child: Column(
  468. crossAxisAlignment: CrossAxisAlignment.start,
  469. children: [
  470. Text(
  471. "扣电规则",
  472. style: TextStyle(
  473. fontSize: 12,
  474. fontWeight: FontWeight.w500,
  475. color: Colors.white.withOpacity(0.6),
  476. ),
  477. ),
  478. SizedBox(
  479. height: 6.h,
  480. ),
  481. Text(
  482. "1、小听每听5分钟扣1电量,不满5分钟按5分钟算。",
  483. style: TextStyle(
  484. fontSize: 12,
  485. color: Colors.white.withOpacity(0.6),
  486. ),
  487. ),
  488. Text(
  489. "2、大文件、超大文件生成新的总结,每次扣1电量。",
  490. style: TextStyle(
  491. fontSize: 12,
  492. fontWeight: FontWeight.w500,
  493. color: Colors.white.withOpacity(0.6),
  494. ),
  495. ),
  496. Text(
  497. "3、用大文件和小听对话,每次对话扣1电量。",
  498. style: TextStyle(
  499. fontSize: 12,
  500. fontWeight: FontWeight.w500,
  501. color: Colors.white.withOpacity(0.6),
  502. ),
  503. ),
  504. ],
  505. ),
  506. );
  507. }
  508. Widget _buildBottomButton() {
  509. return Container(
  510. width: double.infinity,
  511. padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.w),
  512. decoration: BoxDecoration(
  513. color: "#283B58".color,
  514. borderRadius: BorderRadius.only(
  515. topLeft: Radius.circular(12.w),
  516. topRight: Radius.circular(12.w),
  517. ),
  518. ),
  519. child: GestureDetector(
  520. onTap: () => controller.onBuyClick(),
  521. child: Container(
  522. height: 48.w,
  523. alignment: Alignment.center,
  524. decoration: BoxDecoration(
  525. gradient: LinearGradient(
  526. colors: ['#9075FF'.color, '#4366FF'.color],
  527. begin: Alignment.centerLeft,
  528. end: Alignment.centerRight,
  529. stops: const [0.0, 1.0],
  530. ),
  531. borderRadius: BorderRadius.circular(8.w),
  532. ),
  533. child: _buildBuyButton(),
  534. ),
  535. ),
  536. );
  537. }
  538. Widget _buildBuyButton() {
  539. return Obx(() => Text(
  540. "立即购买 ¥${controller.currentSelectedStoreItem.value?.amountText}",
  541. style: TextStyle(
  542. fontWeight: FontWeight.bold,
  543. fontSize: 16.sp,
  544. color: Colors.white),
  545. ));
  546. }
  547. }
  548. extension on PaymentWay {
  549. get _icon {
  550. switch (payMethod) {
  551. case PayMethod.alipay:
  552. return Assets.images.iconStoreAlipay.image(width: 20.w, height: 20.w);
  553. case PayMethod.wechat:
  554. return Assets.images.iconStoreWechatPay
  555. .image(width: 20.w, height: 20.w);
  556. default:
  557. return Container();
  558. }
  559. }
  560. }