import 'dart:ffi'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:huixiang/view_widget/my_appbar.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:shimmer/shimmer.dart'; import '../../../generated/l10n.dart'; import '../../../retrofit/business_api.dart'; import '../../../retrofit/data/base_data.dart'; import '../../../retrofit/data/business_goods.dart'; import '../../../retrofit/data/product_group_list.dart'; import '../../../utils/business_instance.dart'; import '../../../utils/flutter_utils.dart'; import '../../../utils/font_weight.dart'; import '../../../view_widget/border_text.dart'; import '../../../view_widget/classic_header.dart'; import '../../../view_widget/custom_image.dart'; import '../../../view_widget/my_footer.dart'; import '../../../view_widget/no_data_view.dart'; import '../../../view_widget/round_button.dart'; class BatchShelf extends StatefulWidget { final Map arguments; BatchShelf({this.arguments}); @override State createState() { return _BatchShelf(); } } class _BatchShelf extends State { final RefreshController _refreshController = RefreshController(); final ScrollController controller = ScrollController(); BusinessApiService businessService; ProductGroupList productGroupList; List adminProductVoList = []; List selectedProductVoList = []; List productIds = []; int _loadCount = 0; int _pageIndex = 1; int groupIndex = -1; String networkError = ""; int networkStatus = 0; int groupNum = 1; String titleName; @override void initState() { super.initState(); _onRefresh(); titleName = widget?.arguments["titleName"] ?? ""; groupNum = widget?.arguments["groupNum"] ?? 1; } @override void dispose() { super.dispose(); _refreshController.dispose(); } _onRefresh({isShowLoad = true}) async { if (isShowLoad) EasyLoading.show( status: S.current.zhengzaijiazai, maskType: EasyLoadingMaskType.black); SharedPreferences.getInstance().then((value) { businessService = BusinessApiService( Dio(), context: context, token: BusinessInstance.instance.businessToken, tenant: BusinessInstance.instance.businessTenant, storeId: widget.arguments["storeId"], ); queryProductGroupList(); queryGoodsList( groupIndex != -1 ? productGroupList.records[groupIndex].id : "", isSing: false); }); } addLoadCount() { _loadCount += 1; if (_loadCount == 2) { _loadCount = 0; EasyLoading.dismiss(); if (!mounted) return; if (_refreshController.isRefresh) _refreshController.refreshCompleted(); setState(() {}); } } ///分组列表 queryProductGroupList() async { try { BaseData baseData = await businessService.productGroup({ "current": 1, "map": {}, "model": {"groupImg": "", "groupName": "", "isDelete": 0}, "order": "ascending", "size": 100, "sort": "sort" }).catchError((error) {}); if (!mounted) return; if (baseData != null && baseData.isSuccess) { productGroupList = baseData.data; } else { SmartDialog.showToast(baseData.msg, alignment: Alignment.center); } } finally { addLoadCount(); } } ///商品列表 queryGoodsList(groupId, {isSing = true}) async { try { BaseData baseData = await businessService.findAdminProductLis({ "groupId": groupId, "hasStock": "", "keyword": "", "pageIndex": _pageIndex, "pageSize": 10, "status": "1" }).catchError((error) { networkError = AppUtils.dioErrorTypeToString(error.type); networkStatus = -1; _refreshController.refreshFailed(); _refreshController.loadFailed(); }); if (!mounted) return; if (baseData != null && baseData.isSuccess) { adminProductVoList.addAll(baseData?.data?.adminProductVOList ?? []); // 判断新列表中是否又选中过的商品 if (selectedProductVoList.isNotEmpty) { adminProductVoList.forEach((element) { element.isSelect = selectedProductVoList.any((e) => e.id == element.id); }); } if ((baseData?.data?.adminProductVOList ?? []).isEmpty || adminProductVoList.length == baseData.data.total) { _refreshController.loadNoData(); } else { _refreshController.loadComplete(); } networkStatus = 1; } else { SmartDialog.showToast(baseData.msg, alignment: Alignment.center); } } finally { if (isSing) { setState(() {}); } else { addLoadCount(); } } } queryGoodsUpdate() async { try { EasyLoading.show( status: S.current.zhengzaijiazai, maskType: EasyLoadingMaskType.black); if (businessService == null) { businessService = BusinessApiService(Dio(), context: context, token: BusinessInstance.instance.businessToken, tenant: BusinessInstance.instance.businessTenant, storeId: widget.arguments["storeId"]); } BaseData baseData = await businessService.goodsUpdate({ "productId": 0, "productIds": productIds ?? [], "sell": false, }).catchError((error) {}); if (baseData != null && baseData.isSuccess) { _pageIndex = 1; adminProductVoList.clear(); await queryGoodsList( groupIndex == -1 ? "" : productGroupList?.records[groupIndex]?.id ?? "", isSing: false); setState(() {}); SmartDialog.showToast("商品下架成功", alignment: Alignment.center); } else { SmartDialog.showToast(baseData.msg, alignment: Alignment.center); } } finally { EasyLoading.dismiss(); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: MyAppBar( title: titleName, titleColor: Colors.black, background: Colors.white, leadingColor: Colors.black, brightness: Brightness.dark, action: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { List> goodsMeal = []; if (titleName == "批量下架") { if (productIds.length != 0) productIds.clear(); adminProductVoList.forEach((element) { if (element.isSelect) productIds.add(element.id); }); if (productIds.length == 0) { SmartDialog.showToast("请选择要下架的商品", alignment: Alignment.center); return; } else { showGoodsStateDialog(); } } else { if (goodsMeal.length != 0) goodsMeal.clear(); if (groupNum != selectedProductVoList.length) { SmartDialog.showToast("选择的商品与分组总数不一致", alignment: Alignment.center); return; } goodsMeal = selectedProductVoList.map((e) => { "productId": e.id, "storeId": e.storeId, "skuInfoList": e.productSkuVOList, "productAttrInfoList": e.attrList, "productName": e.productName, "number": e.goodsNumber.toString() }).toList(); if (goodsMeal.length == 0) { SmartDialog.showToast("请选择要增加的商品", alignment: Alignment.center); return; } Navigator.of(context).pop(goodsMeal); } }, child: Container( alignment: Alignment.center, child: Text( "${S.of(context).queren}(${selectedProductVoList.length}/${groupNum})", style: TextStyle( color: Color(0xFF30415B), fontSize: 14.sp, fontWeight: MyFontWeight.semi_bold, ), ), ), ), ), body: networkStatus == -1 ? noNetwork() : Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 100.w, height: double.infinity, padding: EdgeInsets.only(bottom: 70.h), color: Color(0xFFFAFAFA), child: networkStatus == 0 ? ListView.builder( itemCount: 10, physics: BouncingScrollPhysics(), shrinkWrap: true, itemBuilder: (context, position) { return shelfLeftItemSm(); }, ) : ListView.builder( itemCount: productGroupList?.records?.length ?? 0, physics: BouncingScrollPhysics(), shrinkWrap: true, itemBuilder: (context, position) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { groupIndex = position; _pageIndex = 1; adminProductVoList.clear(); queryGoodsList( productGroupList?.records[position].id, ); }, child: shelfLeftItem( productGroupList.records[position], position), ); }, ), ), Container( width: MediaQuery.of(context).size.width - 100.w, child: SmartRefresher( controller: _refreshController, enablePullDown: true, enablePullUp: adminProductVoList.length != 0 ? true : false, header: MyHeader( color: Color(0xFF30415B), ), physics: BouncingScrollPhysics(), footer: CustomFooter( builder: (context, mode) { return MyFooter(mode); }, ), onLoading: () { _pageIndex++; queryGoodsList(groupIndex == -1 ? "" : productGroupList?.records[groupIndex].id); }, onRefresh: () { _pageIndex = 1; adminProductVoList.clear(); _onRefresh(isShowLoad: false); }, child: Container( color: Colors.white, child: networkStatus == 0 ? ListView.builder( itemCount: 10, physics: BouncingScrollPhysics(), shrinkWrap: true, itemBuilder: (context, position) { return shelfGoodsItemSm(); }, ) : ((adminProductVoList == null || adminProductVoList.length == 0) ? NoDataView( src: "assets/image/bs_no data_logo.webp", isShowBtn: false, text: "该分组暂无添加商品", fontSize: 16.sp, margin: EdgeInsets.all(20.h), ) : ListView.builder( itemCount: adminProductVoList?.length ?? 0, controller: controller, physics: BouncingScrollPhysics(), shrinkWrap: true, itemBuilder: (context, position) { return shelfGoodsItem( adminProductVoList[position]); }, )))), ), ], ), ); } ///商品确认下架提示弹窗 showGoodsStateDialog() { showDialog( context: context, builder: (context) { return AlertDialog( content: Container( width: MediaQuery.of(context).size.width - 84, height: 139.h, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "选中数据将被下架, 是否继续?", style: TextStyle( color: Color(0xFFF4524D), fontSize: 16.sp, fontWeight: MyFontWeight.regular, ), ), SizedBox( height: 35.h, ), Row( children: [ Expanded( child: InkWell( child: BorderText( text: S.of(context).quxiao, textColor: Color(0xFF30415B), fontSize: 16.sp, fontWeight: FontWeight.bold, borderColor: Color(0xFF30415B), radius: 4, padding: EdgeInsets.all(12), borderWidth: 1, ), onTap: () { Navigator.of(context).pop(); }, ), flex: 1, ), SizedBox( width: 16.w, ), Expanded( child: InkWell( child: RoundButton( text: S.of(context).queren, textColor: Colors.white, radius: 4, padding: EdgeInsets.all(12), backgroup: Color(0xFF30415B), fontSize: 16.sp, fontWeight: FontWeight.bold, ), onTap: () { Navigator.of(context).pop(); queryGoodsUpdate(); }, ), flex: 1, ), ], ) ], ), ), ); }, ); } ///左边list Widget shelfLeftItem(Records records, index) { return Container( color: groupIndex == index ? Colors.white : Color(0xFFFAFAFA), alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 14.w), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Text( records?.groupName ?? "", textAlign: TextAlign.center, style: TextStyle( color: groupIndex == index ? Color(0xFF30415B) : Color(0xFF626264), fontSize: 12.sp, fontWeight: groupIndex == index ? MyFontWeight.semi_bold : MyFontWeight.regular, ), )), ], ), ); } Widget shelfGoodsItem(AdminProductVoList adminProductVo) { return Container( margin: EdgeInsets.only(bottom: 21.h, left: 16.w), child: Row( children: [ MImage( adminProductVo?.productImg ?? "", width: 77.h, height: 77.h, fit: BoxFit.cover, radius: BorderRadius.circular(4), ), SizedBox( width: 12.w, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.only(top: 2.h), child: Text( adminProductVo?.productName ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 14.sp, fontWeight: MyFontWeight.medium, color: Color(0xFF000000), ), )), Row( children: [ Text( "库存${adminProductVo?.stock ?? 0}", style: TextStyle( fontSize: 10.sp, fontWeight: MyFontWeight.regular, color: Color(0xFFA29E9E), ), ), SizedBox( width: 8.w, ), Expanded( child: Text( "销量${adminProductVo?.sellCount ?? 0}", style: TextStyle( fontSize: 10.sp, fontWeight: MyFontWeight.regular, color: Color(0xFF999999), ), )), Checkbox( value: adminProductVo.isSelect, onChanged: (a) { if (!adminProductVo.isSelect) { if (selectedProductVoList.length >= groupNum) { SmartDialog.showToast("商品分组总数只有${groupNum}个,无法添加更多", alignment: Alignment.center); return; } } setState(() { adminProductVo.isSelect = !adminProductVo.isSelect; if (adminProductVo.isSelect) { selectedProductVoList.add(adminProductVo); } else { selectedProductVoList.remove(adminProductVo); } }); }, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(2.0), ), checkColor: Color(0xFFFFFFFF), fillColor: MaterialStateProperty.all(Color(0xFF30415B)), ), ], ), SizedBox( height: 7.h, ), Row( children: [ Expanded( child: Text.rich( TextSpan( children: [ TextSpan( text: "¥", style: TextStyle( fontSize: 12.sp, fontWeight: MyFontWeight.medium, color: Color(0xFFF4524D), ), ), TextSpan( text: adminProductVo?.price ?? "", style: TextStyle( fontSize: 18.sp, fontWeight: MyFontWeight.medium, color: Color(0xFFF4524D), ), ), ], ), )), if (titleName == "选择商品") GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { setState(() { if (adminProductVo.goodsNumber <= 1) return; adminProductVo?.goodsNumber = adminProductVo.goodsNumber - 1; }); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 10.w), child: Icon( Icons.remove_circle_outline, color: Color(0xFF30415B), size: 24, ))), if (titleName == "选择商品") Text( adminProductVo?.goodsNumber?.toString() ?? "", style: TextStyle( color: Color(0xD9000000), fontSize: 20.sp, fontWeight: MyFontWeight.regular, ), ), if (titleName == "选择商品") GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { setState(() { adminProductVo.goodsNumber = adminProductVo.goodsNumber + 1; }); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 10.w), child: Icon( Icons.add_circle, color: Color(0xFF30415B), size: 24, )), ), ], ), ], )), ], ), ); } Widget shelfLeftItemSm() { return Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 14.w), child: Shimmer.fromColors( baseColor: Color(0XFFD8D8D8), highlightColor: Color(0XFFD8D8D8), child: Container( decoration: BoxDecoration( color: Color(0XFFD8D8D8), borderRadius: BorderRadius.circular(2), ), width: 48.w, height: 30.h, ), ), ); } Widget shelfGoodsItemSm() { return Container( margin: EdgeInsets.only(bottom: 21.h, left: 16.w, right: 16.w, top: 10.h), child: Row( children: [ Shimmer.fromColors( baseColor: Color(0XFFD8D8D8), highlightColor: Color(0XFFD8D8D8), child: Container( decoration: BoxDecoration( color: Color(0XFFD8D8D8), borderRadius: BorderRadius.circular(4), ), width: 70.h, height: 70.h, ), ), SizedBox( width: 12.w, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.only(bottom: 11.h, top: 2.h), child: Shimmer.fromColors( baseColor: Color(0XFFD8D8D8), highlightColor: Color(0XFFD8D8D8), child: Container( decoration: BoxDecoration( color: Color(0XFFD8D8D8), borderRadius: BorderRadius.circular(2), ), width: 124.w, height: 20.h, ), ), ), Row( children: [ Shimmer.fromColors( baseColor: Color(0XFFD8D8D8), highlightColor: Color(0XFFD8D8D8), child: Container( decoration: BoxDecoration( color: Color(0XFFD8D8D8), borderRadius: BorderRadius.circular(2), ), width: 43.w, height: 18.h, ), ), SizedBox( width: 8.w, ), Shimmer.fromColors( baseColor: Color(0XFFD8D8D8), highlightColor: Color(0XFFD8D8D8), child: Container( decoration: BoxDecoration( color: Color(0XFFD8D8D8), borderRadius: BorderRadius.circular(2), ), width: 43.w, height: 18.h, ), ), Spacer(), Shimmer.fromColors( baseColor: Color(0XFFD8D8D8), highlightColor: Color(0XFFD8D8D8), child: Container( decoration: BoxDecoration( color: Color(0XFFD8D8D8), borderRadius: BorderRadius.circular(2), ), width: 16.h, height: 16.h, ), ), ], ), SizedBox( height: 7.h, ), Shimmer.fromColors( baseColor: Color(0XFFD8D8D8), highlightColor: Color(0XFFD8D8D8), child: Container( decoration: BoxDecoration( color: Color(0XFFD8D8D8), borderRadius: BorderRadius.circular(2), ), width: 28.w, height: 20.h, ), ), ], )), ], ), ); } Widget noNetwork() { return Container( color: Colors.white, width: double.infinity, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( networkError.substring(0, networkError.indexOf(",")), style: TextStyle( fontSize: 14.sp, color: Color(0xFF0D0D0D), fontWeight: MyFontWeight.bold), ), Padding( padding: EdgeInsets.symmetric(vertical: 10.h), child: Text( "请检查网络设置或稍后重试", style: TextStyle( fontSize: 12.sp, color: Color(0xFF7A797F), fontWeight: MyFontWeight.regular), ), ), GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { _onRefresh(); }, child: Container( decoration: BoxDecoration( color: Color(0xFF30415B), borderRadius: BorderRadius.circular(15), ), padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 3.h), child: Text( "重试", style: TextStyle( fontSize: 14.sp, color: Colors.white, fontWeight: MyFontWeight.regular), )), ) ], ), ); } }