view.dart 17 KB

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