product_attr.dart 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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:twong/api/index.dart';
  5. import 'package:twong/utils/index.dart';
  6. import 'package:twong/config/style.dart';
  7. import 'package:twong/models/index.dart';
  8. import 'package:twong/router/index.dart';
  9. import 'package:twong/widgets/num_counter.dart';
  10. class ProductAttrPage extends StatefulWidget {
  11. final Details data;
  12. final bool showAll;
  13. final bool isCart;
  14. final Function(ProductInfo) cartBack;
  15. final Function(ProductInfo) callback;
  16. ProductAttrPage(this.data, {Key key, this.isCart = false, this.showAll = false,
  17. this.callback, this.cartBack }): super(key: key);
  18. @override
  19. State<StatefulWidget> createState() {
  20. return _ProductAttrPageState();
  21. }
  22. }
  23. class _ProductAttrPageState extends State<ProductAttrPage> {
  24. int _buyCount = 1;
  25. ProductInfo _selectAttr;
  26. List<String> _selectSuk = List<String>();
  27. @override
  28. void initState() {
  29. super.initState();
  30. if(widget.data.productAttr.length > 0) {
  31. var attrList = widget.data.productValue as Map<String, dynamic>;
  32. for (var i in widget.data.productAttr) {
  33. // var sku = i.attr_values.firstWhere((element) {
  34. // return attrList.containsKey(element);
  35. // });
  36. var sku = i.attr_values.first;
  37. _selectSuk.add(sku);
  38. }
  39. _selectAttr = ProductInfo.fromJson(attrList.values.first);
  40. } else {
  41. _setDefault();
  42. }
  43. }
  44. void _setDefault({int stock }) {
  45. _selectAttr = ProductInfo();
  46. _selectAttr.image = widget.data.storeInfo.image;
  47. _selectAttr.product_id = widget.data.storeInfo.id;
  48. _selectAttr.price = widget.data.storeInfo.price;
  49. _selectAttr.vip_price = widget.data.storeInfo.vip_price;
  50. _selectAttr.stock = stock == null ? widget.data.storeInfo.stock : stock;
  51. }
  52. void _updateSelect() {
  53. var attrList = widget.data.productValue as Map<String, dynamic>;
  54. var _skuKey = "";
  55. for(var sku in _selectSuk) {
  56. _skuKey = "$_skuKey,$sku";
  57. }
  58. var key = _skuKey.replaceFirst(",", "");
  59. if(attrList.containsKey(key)) {
  60. setState(() {
  61. _selectAttr =
  62. ProductInfo.fromJson(attrList[key]);
  63. });
  64. } else {
  65. Log.w("not fond [$key] in sku values");
  66. setState(() {
  67. _setDefault(stock: 0);
  68. });
  69. }
  70. }
  71. Widget _buildHeader() {
  72. return Container(
  73. height: 100.px,
  74. padding: EdgeInsets.all(10.px),
  75. child: Flex(
  76. direction: Axis.horizontal,
  77. children: [
  78. InkWell(
  79. onTap: () {
  80. Utils.showPhoto(image: _selectAttr.image);
  81. },
  82. child: CachedNetworkImage(imageUrl: _selectAttr.image),
  83. ),
  84. Expanded(
  85. child: Container(
  86. padding: EdgeInsets.only(left: 10.px),
  87. child: Column(
  88. children: [
  89. Row(
  90. crossAxisAlignment: CrossAxisAlignment.start,
  91. children: [
  92. Expanded(child: Container(
  93. height: 38.px,
  94. width: double.infinity,
  95. child: Text(widget.data.storeInfo.store_name),
  96. )),
  97. InkWell(
  98. onTap: () => Navigator.pop(context),
  99. child: Icon(
  100. Icons.close, color: Colors.grey, size: 18.px),
  101. )
  102. ],
  103. ),
  104. Spacer(),
  105. Flex(
  106. direction: Axis.horizontal,
  107. children: [
  108. Text(Utils.formatRMB(Cache.isVip ? _selectAttr.vip_price
  109. : _selectAttr.price, show: true),
  110. style: TextStyle(
  111. color: DColors.price, fontSize: 16.px)),
  112. Spacer(),
  113. Text('库存:${_selectAttr.stock}', style:
  114. TextStyle(color: Colors.grey,
  115. fontWeight: FontWeight.w300,
  116. fontSize: 12.px)),
  117. Spacer(),
  118. Text('销量:${_selectAttr.sales}', style:
  119. TextStyle(color: Colors.grey,
  120. fontWeight: FontWeight.w300,
  121. fontSize: 12.px)),
  122. Container(width: 12.px)
  123. ],
  124. )
  125. ],
  126. ),
  127. )
  128. ),
  129. ],
  130. ),
  131. );
  132. }
  133. Widget _buildAttrButton(String name, int idx) {
  134. if (_selectSuk.contains(name)) {
  135. return Container(
  136. height: 30.px,
  137. margin: EdgeInsets.all(3.px),
  138. padding: EdgeInsets.only(left: 16.px, right: 16.px, top: 6.px),
  139. child: Text(
  140. name, style: TextStyle(color: Colors.white, fontSize: 12.px)),
  141. decoration: BoxDecoration(
  142. color: DColors.Main,
  143. borderRadius: BorderRadius.all(Radius.circular(20.px))
  144. ),
  145. );
  146. }
  147. return InkWell(
  148. onTap: () {
  149. _selectSuk[idx] = name;
  150. _updateSelect();
  151. },
  152. child: Container(
  153. height: 30.px,
  154. margin: EdgeInsets.all(3.px),
  155. padding: EdgeInsets.only(left: 16.px, right: 16.px, top: 6.px),
  156. decoration: ShapeDecoration(
  157. color: Colors.white,
  158. shape: RoundedRectangleBorder(side: BorderSide(width: 0.5.px, color: DColors.Main),
  159. borderRadius: BorderRadius.all(Radius.circular(20.px))),
  160. ),
  161. child: Text(
  162. name, style: TextStyle(color: DColors.Main, fontSize: 12.px)),
  163. ),
  164. );
  165. }
  166. Widget _buildAttr(ProductAttr attr, int idx) {
  167. var widgets = List<Widget>();
  168. for(var attrName in attr.attr_values) {
  169. widgets.add(_buildAttrButton(attrName, idx));
  170. }
  171. return Flex(
  172. direction: Axis.vertical,
  173. crossAxisAlignment: CrossAxisAlignment.start,
  174. children: [
  175. Container(
  176. width: double.infinity,
  177. padding: EdgeInsets.only(bottom: 2.px),
  178. child: Text(attr.attr_name),
  179. ),
  180. Container(
  181. child: Wrap(
  182. direction: Axis.horizontal,
  183. children: widgets,
  184. ),
  185. )
  186. ],
  187. );
  188. }
  189. Widget _buildProductAttr () {
  190. var widgets = List<Widget>();
  191. var idx = 0;
  192. for(var attr in widget.data.productAttr) {
  193. widgets.add(_buildAttr(attr, idx++));
  194. }
  195. return Container(
  196. width: MediaQuery.of(context).size.width,
  197. padding: EdgeInsets.all(12.px),
  198. child: ListView(
  199. children: widgets,
  200. ),
  201. );
  202. }
  203. @override
  204. Widget build(BuildContext context) {
  205. return SafeArea(child: Container(
  206. height: widget.data.productAttr.length > 0 ? null : 260.px,
  207. child: Column(
  208. children: [
  209. _buildHeader(),
  210. Expanded(child: _buildProductAttr()),
  211. _buildCounter(),
  212. _buildButtons(),
  213. Container(height: 6.px)
  214. ],
  215. ),
  216. ));
  217. }
  218. Widget _buildCounter() {
  219. return Container(
  220. margin: EdgeInsets.only(left: 12.px, right: 12.px, bottom: 6.px),
  221. child: Row(
  222. children: [
  223. Text("购买数量"),
  224. Spacer(),
  225. NumCounter(num: 1, onChange: (value) {
  226. _buyCount = value;
  227. }, max: _selectAttr.stock),
  228. ],
  229. ),
  230. );
  231. }
  232. Widget _buildButtons() {
  233. if (_selectAttr.stock < 1) {
  234. return Container(
  235. width: 400.px,
  236. margin: EdgeInsets.only(left: 10.px, right: 10.px),
  237. child: FlatButton(
  238. color: DColors.Main,
  239. shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
  240. onPressed: null,
  241. disabledColor: Colors.grey,
  242. child: Text("暂时无货", style: TextStyle(color: Colors.white)),
  243. ),
  244. );
  245. }
  246. if (!widget.showAll) {
  247. return Container(
  248. width: 400.px,
  249. margin: EdgeInsets.only(left: 10.px, right: 10.px),
  250. child: FlatButton(
  251. color: DColors.Main,
  252. shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
  253. onPressed: _submitClick,
  254. child: Text(widget.isCart ? "加入购物车" : "立即购买", style: TextStyle(color: Colors.white)),
  255. ),
  256. );
  257. } else {
  258. return Row(
  259. children: [
  260. Expanded(child: Container(
  261. margin: EdgeInsets.only(left: 12.px, right: 10.px),
  262. child: FlatButton(
  263. color: DColors.Main,
  264. shape: StadiumBorder(),
  265. onPressed: _toCart,
  266. child: Text("加入购物车", style: TextStyle(color: Colors.white)),
  267. ),
  268. )),Expanded(child: Container(
  269. margin: EdgeInsets.only(left: 12.px, right: 10.px),
  270. child: FlatButton(
  271. color: DColors.Main,
  272. shape: StadiumBorder(),
  273. onPressed: _toBuy,
  274. child: Text("立即购买", style: TextStyle(color: Colors.white)),
  275. ),
  276. ))
  277. ],
  278. );
  279. }
  280. }
  281. void _submitClick() {
  282. if(widget.isCart) {
  283. _toCart();
  284. } else {
  285. _toBuy();
  286. }
  287. }
  288. void _toBuy() {
  289. Navigator.pop(context);
  290. Navigator.pushNamed(context, RouteNames.submitOrder, arguments: _selectAttr);
  291. widget.callback?.call(_selectAttr);
  292. }
  293. void _toCart() {
  294. Network.inst.addCart(cartNum: _buyCount, productId: _selectAttr.product_id,
  295. uniqueId: _selectAttr.unique, news: 0).then((res) {
  296. Log.d(res);
  297. BotToast.showText(text:"商品已经添加到购物车!");
  298. Navigator.pop(context);
  299. widget.cartBack?.call(_selectAttr);
  300. });
  301. }
  302. }