view.dart 17 KB

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