recharge.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. import 'dart:async';
  2. import 'package:fast/model/model.dart';
  3. import 'package:fast/utils/api.dart';
  4. import 'package:fast/utils/global.dart';
  5. import 'package:fast/utils/http_utils.dart';
  6. import 'package:fast/utils/size_fit.dart';
  7. import 'package:fast/view/balance_history.dart';
  8. import 'package:fast/view/component/fast_btn.dart';
  9. import 'package:fast/view/pay_result.dart';
  10. import 'package:flutter/material.dart';
  11. import 'package:get/get.dart';
  12. import 'package:fluwx/fluwx.dart';
  13. import '../constants.dart';
  14. import 'component/navi_bar.dart';
  15. class Recharge extends StatefulWidget {
  16. const Recharge({Key? key}) : super(key: key);
  17. @override
  18. State<Recharge> createState() => _RechargeState();
  19. }
  20. class _RechargeState extends State<Recharge> {
  21. List<RechargeBean> list = [];
  22. StreamSubscription? subscription;
  23. bool isCharging = false;
  24. int balance = 0;
  25. @override
  26. void initState() {
  27. // TODO: implement initState
  28. setState(() {
  29. balance = Global().balance;
  30. });
  31. getSkus();
  32. initWxApi();
  33. super.initState();
  34. }
  35. Future getSkus() async {
  36. Map<String, dynamic> data = await HttpUtils.get(Api.recharge);
  37. List<RechargeBean> array = [];
  38. if (data != null) {
  39. data['data'].forEach((obj) => {array.add(RechargeBean.fromJson(obj))});
  40. }
  41. setState(() {
  42. list = array;
  43. });
  44. }
  45. Future getBalance() async {
  46. Map<String, dynamic> data = await HttpUtils.get(Api.balance);
  47. Global().balance = data['rjv_balance'];
  48. if (mounted) {
  49. setState(() {
  50. balance = Global().balance;
  51. });
  52. }
  53. return data;
  54. }
  55. Future initWxApi() async {
  56. bool isSuccess = await registerWxApi(
  57. appId: 'wxa8557217acf4f532',
  58. universalLink: 'https://api.fast.liveplus.fun/');
  59. if (isSuccess) {
  60. subscription = weChatResponseEventHandler.listen((event) {
  61. if (event is WeChatPaymentResponse) {
  62. isCharging = false;
  63. if (event.isSuccessful) {
  64. print('支付成功');
  65. Get.to(() => PayResult(
  66. success: true,
  67. ));
  68. getBalance();
  69. } else {
  70. print('支付失败');
  71. Get.to(() => PayResult(
  72. success: false,
  73. ));
  74. }
  75. print(event.toString());
  76. } else if (event is WeChatAuthResponse) {
  77. print('9527');
  78. } else if (event is WeChatShareResponse) {}
  79. });
  80. }
  81. }
  82. Future recharge() async {
  83. if (isCharging) {
  84. return;
  85. }
  86. isCharging = true;
  87. String id = '';
  88. list.forEach((e) => {
  89. if (e.def == true) {id = e.id}
  90. });
  91. Map<String, dynamic> data =
  92. await HttpUtils.post(Api.recharge, data: {'channel': 'wx', 'id': id});
  93. if (data != null) {
  94. Map<String, dynamic> info = data['credential']['wx'];
  95. var result = payWithWeChat(
  96. appId: info['sign'],
  97. partnerId: info['partnerId'],
  98. prepayId: info['prepayId'],
  99. packageValue: info['packageValue'],
  100. nonceStr: info['nonceStr'],
  101. timeStamp: int.parse(info['timeStamp']),
  102. sign: info['sign']);
  103. if (result != null) {
  104. print('success');
  105. }
  106. }
  107. }
  108. Widget item(RechargeBean bean) {
  109. return Stack(
  110. children: [
  111. GestureDetector(
  112. onTap: () {
  113. list.forEach((element) {
  114. element.def = false;
  115. });
  116. bean.def = true;
  117. setState(() {
  118. list = [...list];
  119. });
  120. },
  121. child: Container(
  122. width: 310.px,
  123. height: 56.px,
  124. margin: EdgeInsets.only(
  125. bottom: 2.px, top: 8.px, left: 5.px, right: 5.px),
  126. decoration: BoxDecoration(
  127. borderRadius: BorderRadius.all(Radius.circular(28.px)),
  128. color: const Color(0xFF142133),
  129. border: Border.all(
  130. color: bean.def ? kThemeColor : const Color(0xFF142133),
  131. width: 2.px)),
  132. child: Row(
  133. mainAxisAlignment: MainAxisAlignment.center,
  134. children: [
  135. SizedBox(
  136. width: 26.px,
  137. ),
  138. Image.asset(
  139. 'assets/images/stone.png',
  140. width: 24.px,
  141. height: 24.px,
  142. ),
  143. SizedBox(
  144. width: 8.px,
  145. ),
  146. Text(
  147. '×',
  148. style: TextStyle(
  149. color: const Color(0x66C4CCDA),
  150. fontSize: 28.px,
  151. fontFamily: 'Exo2',
  152. fontWeight: FontWeight.bold),
  153. ),
  154. SizedBox(
  155. width: 8.px,
  156. ),
  157. Expanded(
  158. child: Text(
  159. bean.rjv.toString(),
  160. style: TextStyle(
  161. color: kThemeColor,
  162. fontFamily: 'Exo2',
  163. fontWeight: FontWeight.bold,
  164. fontSize: 28.px),
  165. ),
  166. ),
  167. Text(
  168. '¥${bean.amount}',
  169. style: TextStyle(
  170. color: bean.def ? Colors.white : const Color(0xCCC4CCDA),
  171. fontSize: bean.def ? 18.px : 14.px,
  172. fontFamily: 'Exo2'),
  173. ),
  174. SizedBox(
  175. width: 10.px,
  176. ),
  177. Image.asset(
  178. bean.def
  179. ? 'assets/images/checked.png'
  180. : 'assets/images/check.png',
  181. width: 24.px,
  182. height: 24.px,
  183. ),
  184. SizedBox(
  185. width: 16.px,
  186. )
  187. ],
  188. ),
  189. ),
  190. ),
  191. if (bean.tags.isNotEmpty)
  192. Positioned(
  193. left: 0,
  194. top: 0,
  195. child: Container(
  196. padding: EdgeInsets.only(left: 8.px, right: 8.px),
  197. height: 18.px,
  198. alignment: Alignment.center,
  199. decoration: BoxDecoration(
  200. // borderRadius: BorderRadius.all(Radius.circular(9.px)),
  201. borderRadius: BorderRadius.only(
  202. topLeft: Radius.circular(9.px),
  203. topRight: Radius.circular(9.px),
  204. bottomLeft: Radius.circular(9.px)),
  205. gradient: LinearGradient(
  206. begin: Alignment.centerLeft,
  207. end: Alignment.centerRight,
  208. colors: bean.tags == '推荐'
  209. ? [const Color(0xFFFFD500), const Color(0xFFFF8000)]
  210. : [
  211. const Color(0xFFAA00FF),
  212. const Color(0xFF0080FF)
  213. ])),
  214. child: Text(
  215. bean.tags,
  216. style: TextStyle(
  217. color: bean.tags == '推荐' ? Colors.black : Colors.white,
  218. fontWeight: FontWeight.bold,
  219. fontSize: 10.px),
  220. ),
  221. ))
  222. ],
  223. );
  224. }
  225. @override
  226. Widget build(BuildContext context) {
  227. SizeFit.initialize(context);
  228. EdgeInsets safePadding = MediaQuery.of(context).padding;
  229. return Material(
  230. color: kBgColor,
  231. child: Stack(children: [
  232. SizedBox(
  233. height: MediaQuery.of(context).size.height,
  234. child: SingleChildScrollView(
  235. child: Column(children: [
  236. Container(
  237. margin: EdgeInsets.only(top: safePadding.top + 40.px),
  238. ),
  239. SizedBox(
  240. height: 14.px,
  241. ),
  242. Text(
  243. balance.toString(),
  244. style: TextStyle(
  245. color: kThemeColor,
  246. fontSize: 72.px,
  247. fontFamily: 'Exo2',
  248. fontWeight: FontWeight.bold),
  249. ),
  250. SizedBox(
  251. height: 10.px,
  252. ),
  253. Row(
  254. mainAxisAlignment: MainAxisAlignment.center,
  255. crossAxisAlignment: CrossAxisAlignment.center,
  256. children: [
  257. Image.asset(
  258. 'assets/images/stone.png',
  259. width: 16.px,
  260. height: 16.px,
  261. ),
  262. SizedBox(
  263. width: 4.px,
  264. ),
  265. Text(
  266. '逆龄石余额',
  267. style: TextStyle(
  268. color: Colors.white,
  269. fontSize: 16.px,
  270. fontWeight: FontWeight.bold),
  271. )
  272. ],
  273. ),
  274. SizedBox(
  275. height: 20.px,
  276. ),
  277. Row(
  278. mainAxisAlignment: MainAxisAlignment.center,
  279. crossAxisAlignment: CrossAxisAlignment.center,
  280. children: [
  281. GestureDetector(
  282. onTap: () {
  283. Get.to(() => BalanceHistory(
  284. type: 0,
  285. ));
  286. },
  287. child: Container(
  288. alignment: Alignment.center,
  289. width: 80.px,
  290. height: 24.px,
  291. decoration: BoxDecoration(
  292. borderRadius:
  293. BorderRadius.all(Radius.circular(12.px)),
  294. border: Border.all(
  295. color: const Color(0x66FFFFFF), width: 1.px)),
  296. child: Text(
  297. '全部记录',
  298. style: TextStyle(
  299. color: const Color(0x66FFFFFF), fontSize: 12.px),
  300. ),
  301. ),
  302. ),
  303. SizedBox(
  304. width: 16.px,
  305. ),
  306. GestureDetector(
  307. onTap: () {
  308. Get.to(() => BalanceHistory(
  309. type: 1,
  310. ));
  311. },
  312. child: Container(
  313. alignment: Alignment.center,
  314. width: 80.px,
  315. height: 24.px,
  316. decoration: BoxDecoration(
  317. borderRadius:
  318. BorderRadius.all(Radius.circular(12.px)),
  319. border: Border.all(
  320. color: const Color(0x66FFFFFF), width: 1.px)),
  321. child: Text(
  322. '充值记录',
  323. style: TextStyle(
  324. color: const Color(0x66FFFFFF), fontSize: 12.px),
  325. ),
  326. ),
  327. )
  328. ],
  329. ),
  330. SizedBox(
  331. height: 32.px,
  332. ),
  333. ...List<Widget>.generate(list.length, (i) {
  334. return item(list[i]);
  335. }),
  336. SizedBox(
  337. height: 32.px,
  338. ),
  339. FastBtn(
  340. title: '充值',
  341. disable: false,
  342. width: 310.px,
  343. height: 48.px,
  344. callback: () {
  345. recharge();
  346. })
  347. ]))),
  348. NaviBar(
  349. title: '充值',
  350. closeCallback: () {
  351. Get.back();
  352. }),
  353. ]));
  354. }
  355. }