view.dart 17 KB

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