order_submit.dart 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import 'package:flutter/material.dart';
  2. import 'package:bot_toast/bot_toast.dart';
  3. import 'package:cached_network_image/cached_network_image.dart';
  4. import 'package:provider/provider.dart';
  5. import 'package:twong/api/index.dart';
  6. import 'package:twong/config/pay_config.dart';
  7. import 'package:twong/providers/address.dart';
  8. import 'package:twong/utils/index.dart';
  9. import 'package:twong/config/style.dart';
  10. import 'package:twong/models/index.dart';
  11. import 'package:twong/router/index.dart';
  12. import 'package:twong/widgets/address_bar.dart';
  13. import 'package:twong/widgets/address_item.dart';
  14. import 'package:twong/widgets/app_bar.dart';
  15. import 'package:twong/widgets/circle_check_box.dart';
  16. import 'package:twong/widgets/floading.dart';
  17. import 'package:twong/widgets/payment.dart';
  18. class OrderSubmitPage extends StatefulWidget {
  19. final dynamic info;
  20. OrderSubmitPage(this.info, {Key key}): super(key: key);
  21. @override
  22. State<StatefulWidget> createState() {
  23. return _OrderSubmitPageState();
  24. }
  25. }
  26. class _OrderSubmitPageState extends State<OrderSubmitPage> {
  27. Address _address;
  28. ConfirmInfo _info;
  29. ComputeData _data;
  30. num _integral = 0;
  31. Map<String, num> _priceMap = Map<String, num>();
  32. @override
  33. void initState() {
  34. super.initState();
  35. Utils.loading();
  36. if(widget.info is ProductInfo) {
  37. Network.inst.addCart(productId: widget.info.product_id,
  38. uniqueId: widget.info.unique).then((cartId) {
  39. Network.inst.confirmOrder(cartId).then((confirmInfo) {
  40. setState(() {
  41. _info = confirmInfo;
  42. _address = confirmInfo.addressInfo;
  43. });
  44. _computeOrder();
  45. Utils.closeLoading();
  46. });
  47. });
  48. } else if(widget.info is String) {
  49. Network.inst.confirmOrder(widget.info).then((confirmInfo) {
  50. setState(() {
  51. _info = confirmInfo;
  52. _address = confirmInfo.addressInfo;
  53. });
  54. _computeOrder();
  55. Utils.closeLoading();
  56. });
  57. }
  58. }
  59. @override
  60. Widget build(BuildContext context) {
  61. return Scaffold(
  62. appBar:DAppBar("提交订单"),
  63. body: Container(
  64. color: DColors.back,
  65. padding: EdgeInsets.only(left: 10.px, right: 10.px),
  66. child: ListView(
  67. physics: ClampingScrollPhysics(),
  68. children: [
  69. _buildAddress(),
  70. _buildProducts(),
  71. _buildIntegral(),
  72. _buildExpress(),
  73. _buildExtInfo(),
  74. // _buildPayment(),
  75. _buildResult()
  76. ],
  77. ),
  78. ),
  79. bottomNavigationBar: SafeArea(
  80. child: Container(
  81. height: 40.px,
  82. padding: EdgeInsets.only(left: 16.px, right: 16.px),
  83. child: Row(
  84. children: [
  85. Text("合计:", style: TextStyle(fontSize: 14.px)),
  86. Text(I18n.$, style: TextStyle(fontSize: 12.px, color: DColors.price)),
  87. Text(Utils.formatRMB(_data == null ? 0 : _data.pay_price),
  88. style: TextStyle(fontSize: 18.px, color: DColors.price)),
  89. Spacer(),
  90. FlatButton(
  91. onPressed: _submitOrder,
  92. shape: StadiumBorder(),
  93. child: Text("立即结算", style: TextStyle(color: Colors.white)),
  94. color: Colors.red,
  95. )
  96. ],
  97. ),
  98. ),
  99. ),
  100. );
  101. }
  102. _computeOrder() {
  103. Network.inst.computedOrder(_info.orderKey, addressId: _address.id,
  104. payType: PayConfig.payTypes.first.key, useIntegral: _integral).then((ComputeInfo info) {
  105. setState(() {
  106. _data = info.result;
  107. _priceMap["积分抵扣"] = - info.result.deduction_price.toDouble();
  108. _priceMap["运费"] = info.result.pay_postage;
  109. });
  110. }).catchError((err, stack) {
  111. // Log.d(stack);
  112. BotToast.showText(text: err.toString());
  113. Navigator.pop(context);
  114. });
  115. }
  116. _submitOrder() {
  117. showModalBottomSheet(
  118. context: context,
  119. shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(
  120. topLeft: Radius.circular(10.px), topRight: Radius.circular(10.px)
  121. )),
  122. builder: (BuildContext context) {
  123. return Payment(PaymentInfo(_info.orderKey, _address.id, _integral));
  124. });
  125. }
  126. Widget _styleBox({ Widget child }) {
  127. return Container(
  128. child: child,
  129. margin: EdgeInsets.only(top: 12.px),
  130. padding: EdgeInsets.only(
  131. top: 6.px, bottom: 6.px, left: 12.px, right: 12.px),
  132. decoration: BoxDecoration(
  133. color: Colors.white,
  134. borderRadius: BorderRadius.all(Radius.circular(6.px))
  135. )
  136. );
  137. }
  138. void _selectAddress() {
  139. showModalBottomSheet(
  140. context: context,
  141. shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(
  142. topLeft: Radius.circular(10.px), topRight: Radius.circular(10.px)
  143. )),
  144. builder: (BuildContext context) {
  145. return AddressBar(onSelected: _onSelectedAddress, address: _address);
  146. });
  147. }
  148. void _onSelectedAddress(Address address) {
  149. setState(() {
  150. _address = address;
  151. });
  152. }
  153. Widget _buildAddress() {
  154. return InkWell(
  155. onTap: _selectAddress,
  156. child: _styleBox(
  157. child: _address == null ? Container(
  158. child: Text("设置收货地址", style: TextStyle(fontSize: 16.px)),
  159. ) : AddressItem(_address, editable: false),
  160. ),
  161. );
  162. }
  163. Widget _buildProducts() {
  164. int count = 0;
  165. if (_info != null) {
  166. for (var cart in _info.cartInfo) {
  167. count += cart.cart_num;
  168. }
  169. }
  170. return _styleBox(
  171. child: Column(
  172. crossAxisAlignment: CrossAxisAlignment.start,
  173. children: [
  174. Text("共 $count 件商品"),
  175. Divider(),
  176. _buildProductList()
  177. ],
  178. ),
  179. );
  180. }
  181. Widget _buildProductList() {
  182. List<Widget> widgets = List<Widget>();
  183. if (_info != null) {
  184. for (var info in _info.cartInfo) {
  185. widgets.add(Container(
  186. width: double.infinity,
  187. child: Row(
  188. children: [
  189. Image(
  190. height: 86.px, width: 86.px,
  191. image: CachedNetworkImageProvider(info.productInfo["image"])
  192. ),
  193. Expanded(child: Container(
  194. height: 86.px,
  195. margin: EdgeInsets.only(left: 12.px, right: 12.px),
  196. child: Column(
  197. crossAxisAlignment: CrossAxisAlignment.start,
  198. children: [
  199. Row(
  200. crossAxisAlignment: CrossAxisAlignment.start,
  201. children: [
  202. Expanded(child: Text(
  203. info.productInfo["store_name"])),
  204. Text(" x ${info.cart_num}", style:
  205. TextStyle(color: Colors.grey, fontSize: 16.px)),
  206. ]),
  207. Text(info.productInfo["attrInfo"]["suk"],
  208. style: TextStyle(color: Colors.grey, fontSize: 14.px)),
  209. Spacer(),
  210. Text(Utils.formatRMB(info.truePrice, show: true),
  211. style: TextStyle(
  212. color: Colors.red, fontSize: 16.px)),
  213. ])
  214. ))
  215. ],
  216. ),
  217. ));
  218. }
  219. }
  220. return Column(children: widgets);
  221. }
  222. Widget _buildIntegral() {
  223. return _styleBox(
  224. child: Row(
  225. children: [
  226. Expanded(child: Text("积分抵扣")),
  227. CircleCheckBox((value) {
  228. _integral = value ? num.parse(_info.userInfo.integral) : 0;
  229. _computeOrder();
  230. }, size: 20.px, color: DColors.Main, child: RichText(
  231. text: TextSpan(
  232. text: "当前可用积分: ",
  233. style: TextStyle(color: Colors.black),
  234. children: [
  235. TextSpan(
  236. text: _info == null ? "0" : _info.userInfo.integral,
  237. style: TextStyle(color: Colors.red)
  238. )
  239. ]
  240. ),
  241. ), initValue: _integral > 0)
  242. ],
  243. ),
  244. );
  245. }
  246. Widget _buildExpress() {
  247. var postage = _data == null ? 0 : _data.pay_postage;
  248. return _styleBox(
  249. child: Row(
  250. children: [
  251. Expanded(child:Text("快递费用")),
  252. Text(postage > 0 ? Utils.formatRMB(postage, show: true)
  253. : "免运费", style: TextStyle(color: Colors.grey)),
  254. ],
  255. ),
  256. );
  257. }
  258. Widget _buildExtInfo() {
  259. return _styleBox(
  260. child: Column(
  261. crossAxisAlignment: CrossAxisAlignment.start,
  262. children: [
  263. Text("备注信息"),
  264. TextField(
  265. keyboardType: TextInputType.multiline,
  266. decoration: InputDecoration(
  267. hintText: "请添加备注(150字以内)",
  268. border: InputBorder.none,
  269. ),
  270. )
  271. ],
  272. ),
  273. );
  274. }
  275. Widget _buildResult() {
  276. List<Widget> widgets = List<Widget>();
  277. widgets.add(Row(
  278. children: [
  279. Expanded(child: Text("商品总价")),
  280. Text(_data == null ? "-" : Utils.formatRMB(_data.total_price, show: true))
  281. ],
  282. ));
  283. for(var item in _priceMap.keys) {
  284. var price = _priceMap[item];
  285. if (price != 0) {
  286. var sign = price > 0 ? "+" : "-";
  287. widgets.add(Container(
  288. margin: EdgeInsets.only(top: 4.px),
  289. child: Row(
  290. children: [
  291. Expanded(child: Text(item)),
  292. Text("$sign${Utils.formatRMB(price.abs(), show: true)}",
  293. style: TextStyle(color: Colors.grey))
  294. ],
  295. ),
  296. ));
  297. }
  298. }
  299. return _styleBox(child: Column(children: widgets));
  300. }
  301. }