From 5b53c1043686d62d1f3afd05053d2b2b5f2b431f Mon Sep 17 00:00:00 2001 From: wurong <953969641@qq.com> Date: Fri, 19 Jan 2024 11:34:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B7=BB=E5=8A=A0=E5=95=86?= =?UTF-8?q?=E5=93=81=E5=AE=9E=E4=BD=93=E7=B1=BB=EF=BC=9B=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=95=86=E5=AE=B6=E7=AB=AF=E6=BB=91=E5=8A=A8=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=AA=8C=E8=AF=81=E6=96=87=E4=BB=B6=EF=BC=9B=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BC=96=E8=BE=91=E8=A7=84=E6=A0=BC=E6=98=8E?= =?UTF-8?q?=E7=BB=86=E9=A1=B5=E9=9D=A2=EF=BC=8C=E4=B8=94=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E5=B7=B2=E5=AE=8C=E6=88=90=EF=BC=9B=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BC=96=E8=BE=91=E8=A7=84=E6=A0=BC=E6=98=8E?= =?UTF-8?q?=E7=BB=86=E5=AE=9E=E4=BD=93=E7=B1=BB=EF=BC=9B=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=9C=8D=E5=8A=A1=E5=A5=97=E9=A4=90=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E6=9C=AC=E4=BB=8B=E7=BB=8D=EF=BC=9B=EF=BC=88ui=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E4=B8=BA=E4=BB=85=E6=98=BE=E7=A4=BA=E4=B8=80=E5=BC=A0?= =?UTF-8?q?=E5=9B=BE=E7=89=87=EF=BC=8C=E6=8E=A5=E5=8F=A3=E6=9C=AA=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=AF=A5=E5=AD=97=E6=AE=B5=EF=BC=9B=E5=BE=85=E5=BC=80?= =?UTF-8?q?=E5=8F=91=EF=BC=8C=E6=8E=A5=E5=85=A5=E6=95=B0=E6=8D=AE=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=8D=B3=E5=8F=AF=EF=BC=9B=EF=BC=89=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=9C=8D=E5=8A=A1=E5=A5=97=E9=A4=90=E8=B4=AD=E4=B9=B0?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=AE=9E=E4=BD=93=E7=B1=BB=EF=BC=9B=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9C=8D=E5=8A=A1=E5=A5=97=E9=A4=90=E8=B4=AD?= =?UTF-8?q?=E4=B9=B0=E8=AE=B0=E5=BD=95=E9=A1=B5=E9=9D=A2=EF=BC=9B=EF=BC=88?= =?UTF-8?q?=E8=AF=A5=E9=A1=B5=E9=9D=A2=E5=B7=B2=E5=AE=8C=E6=88=90=E5=88=9D?= =?UTF-8?q?=E6=AD=A5ui=E8=AE=BE=E8=AE=A1=EF=BC=8C=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=B7=B2=E5=AF=B9=E6=8E=A5=EF=BC=8C=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=86=85=E5=AE=B9=E6=9A=82=E6=9C=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=EF=BC=8C=E6=9A=82=E6=97=B6=E9=9A=90=E8=97=8F=EF=BC=89=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AE=BE=E7=BD=AE=E5=95=86=E5=93=81=E8=A7=84?= =?UTF-8?q?=E6=A0=BC=E9=A1=B5=E9=9D=A2=EF=BC=9B=EF=BC=88=E5=B7=B2=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E6=95=B0=E6=8D=AE=E7=9A=84=E4=BA=A4=E4=BA=92=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=EF=BC=89=20=E6=96=B0=E5=A2=9E=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=95=86=E5=93=81=E8=A7=84=E6=A0=BC=E5=80=BC=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=EF=BC=9B=E5=B7=B2=E5=AE=8C=E6=88=90=E6=95=B0=E6=8D=AE=E7=9A=84?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E6=B5=81=E7=A8=8B=EF=BC=89=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=AE=BE=E7=BD=AE=E5=A5=97=E9=A4=90=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=9B=EF=BC=88=E5=B7=B2=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=95=86=E5=93=81=E8=B7=B3=E8=BD=AC=EF=BC=8C?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=95=86=E5=93=81=E6=95=B0=E6=8D=AE=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E7=9A=84=E4=BA=A4=E4=BA=92=E6=B5=81=E7=A8=8B=EF=BC=89?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9E=E8=AE=BE=E7=BD=AE=E8=A7=84=E6=A0=BC?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=AE=9E=E4=BD=93=E7=B1=BB=EF=BC=9B=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AE=BE=E7=BD=AE=E8=A7=84=E6=A0=BC=E5=A5=97?= =?UTF-8?q?=E9=A4=90=E5=88=97=E8=A1=A8=E5=AE=9E=E4=BD=93=E7=B1=BB=EF=BC=9B?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9E=E8=AE=BE=E7=BD=AE=E8=A7=84=E6=A0=BC?= =?UTF-8?q?=E5=80=BC=E5=88=97=E8=A1=A8=E5=AE=9E=E4=BD=93=E7=B1=BB=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/image/2x/register_account.webp | Bin 0 -> 1760 bytes assets/image/2x/retrieve_password.webp | Bin 0 -> 1584 bytes assets/image/3x/register_account.webp | Bin 0 -> 5942 bytes assets/image/3x/retrieve_password.webp | Bin 0 -> 4724 bytes assets/image/register_account.webp | Bin 0 -> 968 bytes assets/image/retrieve_password.webp | Bin 0 -> 888 bytes .../goods/add_goods/add_goods_page.dart | 1211 +++++++++++++++++ .../goods/add_goods/edit_specs_detail.dart | 440 ++++++ .../goods/add_goods/set_goods_specs.dart | 444 ++++++ .../add_goods/set_goods_specs_value.dart | 252 ++++ .../goods/add_goods/set_meal.dart | 491 +++++++ .../captcha/bus_block_puzzle_captcha.dart | 551 ++++++++ .../login/captcha/bus_click_word_captcha.dart | 367 +++++ .../login/register_retrieve_password.dart | 760 +++++++++++ .../function_version_detail.dart | 44 + .../service_purchase_record.dart | 459 +++++++ lib/main.dart | 12 + lib/retrofit/data/edit_specs_detail_list.dart | 32 + lib/retrofit/data/service_bug_list.dart | 313 +++++ lib/retrofit/data/set_specs_list.dart | 19 + lib/retrofit/data/set_specs_meal_list.dart | 34 + lib/retrofit/data/set_specs_value_list.dart | 10 + 22 files changed, 5439 insertions(+) create mode 100644 assets/image/2x/register_account.webp create mode 100644 assets/image/2x/retrieve_password.webp create mode 100644 assets/image/3x/register_account.webp create mode 100644 assets/image/3x/retrieve_password.webp create mode 100644 assets/image/register_account.webp create mode 100644 assets/image/retrieve_password.webp create mode 100644 lib/business_system/goods/add_goods/add_goods_page.dart create mode 100644 lib/business_system/goods/add_goods/edit_specs_detail.dart create mode 100644 lib/business_system/goods/add_goods/set_goods_specs.dart create mode 100644 lib/business_system/goods/add_goods/set_goods_specs_value.dart create mode 100644 lib/business_system/goods/add_goods/set_meal.dart create mode 100644 lib/business_system/login/captcha/bus_block_puzzle_captcha.dart create mode 100644 lib/business_system/login/captcha/bus_click_word_captcha.dart create mode 100644 lib/business_system/login/register_retrieve_password.dart create mode 100644 lib/business_system/mine/service_subscription/function_version_detail.dart create mode 100644 lib/business_system/mine/service_subscription/service_purchase_record.dart create mode 100644 lib/retrofit/data/edit_specs_detail_list.dart create mode 100644 lib/retrofit/data/service_bug_list.dart create mode 100644 lib/retrofit/data/set_specs_list.dart create mode 100644 lib/retrofit/data/set_specs_meal_list.dart create mode 100644 lib/retrofit/data/set_specs_value_list.dart diff --git a/assets/image/2x/register_account.webp b/assets/image/2x/register_account.webp new file mode 100644 index 0000000000000000000000000000000000000000..c2305773cd00f2601b366a231435d9ab1efcc1bd GIT binary patch literal 1760 zcmaKpdpy%?9LFEWBn+$2jR@hmZ77wOsCHsQnIYE^vnjc(nWWr{6k$~AwQ|=)4q+y8 zIo3raq9i-SvQ`u;>6lf{Z#m~xe{|0G`F+2?_w)UJUeEJ=o(GS$vm06lfXANQxc#_o zp7Ht-oG&l)U-SB9LgCI5t z{(%F3U?PPo(Puy!>#)!$$zBqZoDNP3cXx&U%OO_>kpK_u!EVX&FfuDo+;O-GX%)fOnfK-W^N6{ zu(@+KIG_DfU(qk#=`5#xJXdh=*^?@caCWXIX{Q#>m|HjFfg?CpJIlZ-sN00kyw@8{ z7_eY4d6w^jn^D%H2KM3lDpn=+R;!ra+SB!Nl%Cu!yMfYvi8zQq@Uc%@7M4`J+GH|G z!OwJ$s*1G(eOXo+X4lR0&)G__vwpSZiNz7*$IH%c@X~!uRJ$dLlLIDr9N+9UN*F!s zND?N)SH=@+_R7hv)ID|*w)S@Rxp754+#DlJ4TU2+wRWY(!sV1OTDy{AdANsTiLjNm zE3Pp~y;5s+Cy2&>hIFhSyaK}@KxcNz*)VQH828?BwmEiW({`>UQNLNd*U3XxGwrpl zw0%x7V$kOx?dX`|zpsioPq5w0G-GUuM9)3n^-nghk>_ts-l#3H+6+~(Ki{Ac>s$@He z-!EG=y8vsTwC|8i52{Mkv)In^zc+sI;t_5%iNDymdSD3dUjDRH=l5q7Xwtiby2B|5 z3s%{Ue6=H2bM}?h=uPsx`)vMr!RhdfCAW=L%1lSlTyhY)}|NNh_t=;(parBuXgHshRhjO)kv**kPNd+ zAO2AA*)-;R8f zVp}peKlQ+hw=iIvO0`e!R*3E>!*g>+Lh6w9jX9WjZENilhOHHK&4zYgE`3}PjK*JT z+*dVs;IO!FKhv;3^@10(zq;!IDJo&Xs3 zlxs8A+ZVB&GoBDqup-WBB=5_kt{794fAl;>qitx>=&S`yGj~4dk(rJ6QNgB!#!RFt zzfA{LFcIs?r!NX$7V6lSK283vPIG% zYz+`Q3BtAkvCB&eN`PttK=2?(*InG6iuTNxN6ZXv`}7BDdI zw=ghlJC6`Ugh@eSQ6ktl79h!#md3#FX*mM}ZzKbQ@C612u4u3vkig+K1)!7+&|UdJ zn9h*HkjkLI;K`83kj$V5WElY?)sVpq7{fkRK=bwW4{!^-e{42M#dGD`oz`*e28`Se z%J1ws1)V4UyXoM3NHC|N@Nl7uXIF5!ao6JcCs>xLF8ut<@XahG?k#=NoCn|tne z+`9fI-n`5A>*u8ZV&i#}P+oboYHz;K&a;nav+hsm%|5q(e?#fMHy?lUuQ8ptpnLhR zHNHB_LwSjX#`XPy|!?$~Sh?^eXeBKeLN_RQORm$=+|+Q#(u z%|1q0??? z!C9@JvtzcFuw<%T{#TuLE?~pqwShZ+SN~sa?IZi=V#1EMyX|-A%H%wH_e_2J*DJT~ zJ)C&&7Ej&OKTn?pPtR&k_5r72dAj-rfKAr*40@%at(B?*X5zWz76G=bXM#abWWO?7d%k|7!2= z3tU^ko}Ouw`Sz~D`(^9mCoX;wu*&&U!WWHCo97ot6qt)InEdQ#_O-kZ#fL-;|Mp$i zp0lj-6-&etw{44y9_z=fQywCOnVt>9Lr4_2MC`sk1y<&Al|2P6>h%rQKduQ>R|q)xRln z-n1of;iWNENhj3eJAx|Ma+FLCOmtF={bMKkDMJ3Ox|C5{`Bf~`_op1H$CPg zIlrFI@#xCuZY7MiF+e7a*jj2c1FrTwJY^d7; z^!~xre5=mD^fOjzpB4apn|(I@y<%hF@t9Xno;26KyE0|7->$0>;2^Ke$$L(wrO*9dBlEFl&ZiogFEw+%*2sLXnfKtU&6EG2}n literal 0 HcmV?d00001 diff --git a/assets/image/3x/register_account.webp b/assets/image/3x/register_account.webp new file mode 100644 index 0000000000000000000000000000000000000000..c3bb79f365ae27aec8a3eaa54ba2e5aaa1fdbd46 GIT binary patch literal 5942 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 Wd%^YOeapW;{POQl{(Zmq>I?u&)d!9M literal 0 HcmV?d00001 diff --git a/lib/business_system/goods/add_goods/add_goods_page.dart b/lib/business_system/goods/add_goods/add_goods_page.dart new file mode 100644 index 00000000..27932ed1 --- /dev/null +++ b/lib/business_system/goods/add_goods/add_goods_page.dart @@ -0,0 +1,1211 @@ +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:flutter_screenutil/flutter_screenutil.dart'; +import '../../../generated/l10n.dart'; +import '../../../retrofit/business_api.dart'; +import '../../../retrofit/data/base_data.dart'; +import '../../../retrofit/data/goods_category_list.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/settlement_tips_dialog.dart'; + +class AddGoodsPage extends StatefulWidget { + final Map arguments; + + AddGoodsPage({this.arguments}); + + @override + State createState() { + return _AddGoodsPage(); + } +} + +class _AddGoodsPage extends State { + TextEditingController goodsNameController = TextEditingController(); + TextEditingController profileController = TextEditingController(); + TextEditingController skuController = TextEditingController(); + TextEditingController heftController = TextEditingController(); + TextEditingController priceController = TextEditingController(); + TextEditingController originalPriceController = TextEditingController(); + TextEditingController packingChargeController = TextEditingController(); + TextEditingController stockController = TextEditingController(); + BusinessApiService businessService; + ProductGroupList productGroupList; + List goodsCategoryList = []; + String networkError = ""; + int networkStatus = 0; + String categoryName = ""; + int categoryIndex = 0; + String categoryId = ""; + String groupName = ""; + int groupIndex = 0; + String groupId = ""; + bool isLogistics = false; + bool isGround = true; + bool isOversold = true; + bool isSetMeal = false; + bool isAttrStyle = false; + bool isKeyBoardShow = false; + FocusNode _focusNode = FocusNode(); + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + print("object: ${MediaQuery.of(context).viewInsets.bottom}"); + if (MediaQuery.of(context).viewInsets.bottom == 0) { + if (isKeyBoardShow) { + isKeyBoardShow = false; + //关闭键盘 软键盘关闭了, 清除输入控件的焦点, 否则重新进入页面会导致软键盘再弹出问题 + FocusScope.of(context).requestFocus(FocusNode()); + } + } else { + isKeyBoardShow = true; + } + }); + }); + _onRefresh(); + } + + ///离开页面记着销毁和清除 + @override + void dispose() { + _focusNode.unfocus(); + super.dispose(); + } + + _onRefresh() async { + EasyLoading.show( + status: S.current.zhengzaijiazai, + maskType: EasyLoadingMaskType.black); + await queryProductGroupList(); + await queryCategorize(); + EasyLoading.dismiss(); + if (mounted) + setState(() {}); + } + + ///分组列表 + queryProductGroupList() async { + if (businessService == null) { + businessService = BusinessApiService(Dio(), + context: context, + token: BusinessInstance.instance.businessToken, + tenant: BusinessInstance.instance.businessTenant, + storeId: widget.arguments["storeId"]); + } + BaseData baseData = await businessService.productGroup({ + "current": 1, + "map": {}, + "model": {"groupImg": "", "groupName": "", "isDelete": 0}, + "order": "ascending", + "size": 100, + "sort": "sort" + }).catchError((error) { + networkError = AppUtils.dioErrorTypeToString(error.type); + networkStatus = -1; + setState(() {}); + }); + if (baseData != null && baseData.isSuccess) { + productGroupList = baseData.data; + networkStatus = 1; + } + } + + ///分类列表 + queryCategorize() async { + if (businessService == null) { + businessService = BusinessApiService(Dio(), + context: context, + token: BusinessInstance.instance.businessToken, + tenant: BusinessInstance.instance.businessTenant, + storeId: widget.arguments["storeId"]); + } + BaseData> baseData = await businessService.findCategoryListByDepth().catchError((error) {}); + if (baseData != null && baseData.isSuccess) { + goodsCategoryList = baseData.data; + } + } + + ///新建商品 + addGoods() async { + try { + if (businessService == null) { + businessService = BusinessApiService(Dio(), + context: context, + token: BusinessInstance.instance.businessToken, + tenant: BusinessInstance.instance.businessTenant, + storeId: widget.arguments["storeId"]); + } + BaseData baseData = await businessService.productSave({ + "storeId": widget.arguments["storeId"], + "attrStyle": isAttrStyle == true ? 0:1,//款式类型:1-多款式 0-单款式 + "categoryId": "1343391656220557312",//分类id + "oversold": isOversold == true ? 1:0,//允许超卖:1-允许 0-不允许 + "setMeal": isSetMeal == true ? 0:1,//套餐专属商品 0是 1不是 + "groupId": "1693436138259218432",//分组id + "imgs": [ + { + "imgPath": "https://pos.upload.lotus-wallet.com/1195/2023/10/1ba87000-d940-49e5-a6ca-f15623d5f841.jpg" + } + ],//商品图片 + "needLogistics": isLogistics == true ? 1:0,//需要物流:1-需要 0-不需要 + "productName": "新建商品",//商品名字 + "productType": 0,//商品类型(0:普通类型;1:拼盘类型)app新增商品用不到,默认传0 + "shortName": "商品简介",//商品简介 + "skuAttrList": [ + { + "attrCode": "",//规格的数据编码,app新增商品用不到,但必须传"" + "attrName": "",//属性名称,app新增商品用不到,但必须传"" + "needImg": 0,//是否需要图片,app新增商品用不到,但必须传0 + "attrValueList": [ + {"attrValue": "商品规格",//商品规格 + "attrValueCode": "", //规格值的数据编码,app新增商品用不到,但必须传"" + }]//规格对应的规格值 + } + ],//规格列表 + "skuList": [ + { + "applyPrice": "234",//商品原价 + "skuAttrCodeDTOList": [{"attrCode": "", "attrValueCode": ""}],//sku对应的规格编码,app新增商品用不到,但必须传该段 + "skuPrice": "123",//商品售价 + "packagingFee": "789",//打包费 + "skuStock": "666",//库存 + "weight": "222"//重量 + }],//商品sku列表 + "status":isGround == true ? 1:0 //状态:1-上架 0-下架 + }).catchError((error) { + networkError = AppUtils.dioErrorTypeToString(error.type); + networkStatus = -1; + setState(() {}); + }); + if (!mounted) return; + if (baseData != null && baseData.isSuccess) { + SmartDialog.show( + widget: SettlementTips( + () {}, + text: "新建商品成功", + color: Color(0xFF30415B), + )); + networkStatus = 1; + setState(() {}); + } else { + SmartDialog.show( + widget: SettlementTips( + () {}, + text: baseData.msg, + color: Color(0xFF30415B), + )); + } + } finally {} + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: Color(0xFFF8F8FA), + appBar: MyAppBar( + title: "新建商品", + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + brightness: Brightness.dark, + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 15.h, bottom: 15.h, left: 16.w), + child: Text( + "基本信息", + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ), + basicInformation(), + Container( + color: Colors.white, + margin: EdgeInsets.symmetric(vertical: 12.h), + padding: EdgeInsets.only(top: 16.h), + child: Column( + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: (){ + officialCategory(); + }, + child:textSelectItem("官方分类",categoryName == "" ? "请选择":categoryName), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: (){ + goodsGroup(); + }, + child:textSelectItem("商品分组",groupName == "" ? "请选择":groupName)), + ], + ), + ), + buttonSelect(), + Container( + color: Colors.white, + margin: EdgeInsets.only(top: 12.h), + child: Column( + children: [ + Padding(padding: EdgeInsets.only(top: 18.h,left: 16.w,right: 16.w), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 20.h), + child: Text( + "多规格", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + )), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap:(){ + setState((){ + isAttrStyle = !isAttrStyle; + }); + }, + child: Image.asset( + isAttrStyle == true ? "assets/image/reservation_switch.webp":"assets/image/reservation_unswitch.webp", + width: 44.w, + height: 24.h, + ), + ), + ], + )), + Container( + width: double.infinity, + height: 1.w, + color: Color(0x14000000), + margin: EdgeInsets.only(top: 16.h,left: 16.w,right: 16.w), + ), + isAttrStyle == true ? GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: (){ + Navigator.of(context).pushNamed( + '/router/set_goods_specs'); + }, + child:Container( + padding: EdgeInsets.only(left: 16.w,right: 16.w,top: 16.h), + child:Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded(child:Text( + "商品规格", + style: TextStyle( + color: Color(0xFF0D0D0D), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + )), + Text( + "请设置商品规格", + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + ), + Image.asset( + "assets/image/bs_right.webp", + width: 16.h, + height: 16.h, + ), + ], + ), + Container( + margin: EdgeInsets.only(top: 16.h), + color: Color(0x14000000), + height: 1.h, + width: double.infinity, + ), + ], + ), + ), + ): textItem("商品规格", skuController, "请输入商品规格"), + if(isAttrStyle == false) + textItem("商品重量", heftController, "请输入商品重量"), + if(isAttrStyle == false) + textItem("商品售价", priceController, "请输入商品售卖价格"), + if(isAttrStyle == false) + textItem("商品原价", originalPriceController, "请输入商品划线价格"), + if(isAttrStyle == false) + textItem("打包费", packingChargeController, "请输入商品打包费用"), + if(isAttrStyle == false) + textItem("商品库存", stockController, "请输入商品库存"), + if(isAttrStyle == false) + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap:(){ + Navigator.of(context).pushNamed( + '/router/set_meal',arguments:{"storeId":widget.arguments["storeId"]}); + }, + child: Padding(padding: EdgeInsets.symmetric(horizontal: 16.w,vertical:16.h), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child:Text( + "设置套餐", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + ), + ), + Text( + "套餐选择", + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + ), + Image.asset( + "assets/image/bs_right.webp", + width: 16.h, + height: 16.h, + ), + ], + ), + Container( + margin:EdgeInsets.only(top: 16.h), + color: Color(0x14000000), + height: 1.h, + width: double.infinity, + ), + ], + ),), + ), + Container( + width: double.infinity, + padding: EdgeInsets.symmetric(vertical: 16.h), + margin: EdgeInsets.only(top: 111.h, bottom: 34.h,left:16.w,right:16.w), + decoration: BoxDecoration( + color: Color(0xFF30415B), + borderRadius: BorderRadius.circular(27), + ), + alignment: Alignment.center, + child: Text( + S + .of(context) + .baocun, + style: TextStyle( + color: Colors.white, + fontSize: 16.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ], + ), + ) + ], + ), + ), + ), + ); + } + + ///基础信息1 + Widget basicInformation() { + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.w), + color: Colors.white, + child: Column( + children: [ + mustTextItem("商品名称", goodsNameController, "请输入商品名称"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: "*", + style: TextStyle( + color: Color(0xFFE02020), + fontSize: 14.sp, + fontWeight: FontWeight.w500, + ), + ), + TextSpan( + text: "商品图片", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ], + ), + ), + ), + Container( + padding: EdgeInsets.all(15), + margin: EdgeInsets.only(right: 4.w), + decoration: BoxDecoration( + color: Color(0xFFF0F0F0), + borderRadius: BorderRadius.circular(4), + ), + child: Icon( + Icons.add, + size: 24, + color: Color(0xFFD8D8D8), + ), + ), + Image.asset( + "assets/image/vip_code.webp", + fit: BoxFit.cover, + width: 54.h, + height: 54.h, + ), + ], + ), + Container( + margin: EdgeInsets.symmetric(vertical: 16.h), + color: Color(0x14000000), + height: 1.h, + width: double.infinity, + ), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + TextSpan( + text: "*", + style: TextStyle( + color: Color(0xFFE02020), + fontSize: 14.sp, + fontWeight: FontWeight.w500, + ), + ), + TextSpan( + text: "商品简介", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ], + ), + ), + Expanded( + child: Container( + padding: EdgeInsets.only(left: 8.w), + margin: EdgeInsets.only(left: 22.w, bottom: 16.h), + decoration: BoxDecoration( + color: Color(0xFFFCFCFC), + border: Border.all( + color: Color(0xFFEBEBEB), + width: 1, + ), + borderRadius: BorderRadius.circular(2), + ), + alignment: Alignment.topLeft, + child: TextField( + maxLines: 5, + controller: profileController, + onChanged: (value) { + setState(() { + // textLength = value.length; + }); + }, + decoration: InputDecoration( + border: InputBorder.none, + hintText: "请输入商品商品简介", + hintStyle: TextStyle( + fontSize: 12.sp, + fontWeight: MyFontWeight.bold, + color: Color(0xFF7A797F), + ), + ), + ), + )) + ], + ), + ], + ), + ); + } + + ///按钮选择板块 + Widget buttonSelect() { + return Container( + padding: EdgeInsets.only(left: 17.w, top: 16.h), + color: Colors.white, + child: Column( + children: [ + Row( + children: [ + Expanded( + child:Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 20.h), + child: Text( + "需要物流", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + )), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap:(){ + setState((){ + isLogistics = !isLogistics; + }); + }, + child: Image.asset( + isLogistics == true ? "assets/image/reservation_switch.webp":"assets/image/reservation_unswitch.webp", + width: 44.w, + height: 24.h, + ), + ), + ], + ), + ), + Expanded( + child:Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 20.h), + child: Text( + "上架状态", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + )), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap:(){ + setState((){ + isGround = !isGround; + }); + }, + child: Image.asset( + isGround == true ? "assets/image/reservation_switch.webp":"assets/image/reservation_unswitch.webp", + width: 44.w, + height: 24.h, + ), + ), + ], + ), + ), + ], + ), + Container( + width: double.infinity, + height: 1.w, + color: Color(0x14000000), + margin: EdgeInsets.symmetric(vertical: 16.h), + ), + Row( + children: [ + Expanded( + child:Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 20.h), + child: Text( + "允许超卖", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + )), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap:(){ + setState((){ + isOversold = !isOversold; + }); + }, + child: Image.asset( + isOversold == true ? "assets/image/reservation_switch.webp":"assets/image/reservation_unswitch.webp", + width: 44.w, + height: 24.h, + ), + ), + ], + ), + ), Expanded( + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 20.h), + child: Text( + "套餐商品", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + )), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap:(){ + setState((){ + isSetMeal = !isSetMeal; + }); + }, + child: Image.asset( + isSetMeal == true ? "assets/image/reservation_switch.webp":"assets/image/reservation_unswitch.webp", + width: 44.w, + height: 24.h, + ), + ), + ], + ), + ) + ], + ), + Container( + width: double.infinity, + height: 1.w, + color: Color(0x14000000), + margin: EdgeInsets.symmetric(vertical: 16.h), + ), + ], + ), + ); + } + + Widget textSelectItem(left,selectName) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: "*", + style: TextStyle( + color: Color(0xFFE02020), + fontSize: 14.sp, + fontWeight: FontWeight.w500, + ), + ), + TextSpan( + text: left, + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ], + ), + ), + ), + Text( + selectName, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ), + ), + Image.asset( + "assets/image/bs_right.webp", + width: 16.h, + height: 16.h, + ), + ], + ), + Container( + margin: EdgeInsets.symmetric(vertical: 16.h), + color: Color(0x14000000), + height: 1.h, + width: double.infinity, + ), + ], + )); + } + + Widget mustTextItem(left, rightController, right) { + return Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: "*", + style: TextStyle( + color: Color(0xFFE02020), + fontSize: 14.sp, + fontWeight: FontWeight.w500, + ), + ), + TextSpan( + text: left, + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ], + ), + ), + ), + Expanded( + child: TextField( + controller: rightController, + decoration: InputDecoration( + hintText: right ?? "", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold), + ), + flex: 2, + ), + ], + ), + Container( + margin: EdgeInsets.only(bottom: 16.h), + color: Color(0x14000000), + height: 1.h, + width: double.infinity, + ), + ], + )); + } + + Widget textItem(left, rightController, right) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + left, + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + Expanded( + child: TextField( + controller: rightController, + decoration: InputDecoration( + hintText: right ?? "", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold), + ), + flex: 2, + ), + ], + ), + Container( + color: Color(0x14000000), + height: 1.h, + width: double.infinity, + ), + ], + )); + } + + ///官方分类弹窗选择 + officialCategory() { + showModalBottomSheet( + context: context, + backgroundColor: Colors.transparent, + builder: (context) { + return StatefulBuilder(builder: ( + context, + state, + ) { + return Container( + width: double.infinity, + height: 365.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8), + topRight: Radius.circular(8), + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Container( + alignment: Alignment.center, + margin: EdgeInsets.only( + top: 12.h, bottom: 12.h, left: 41.w), + child: Text( + "选择官方分类", + style: TextStyle( + fontWeight: MyFontWeight.bold, + fontSize: 16.sp, + color: Color(0xFF1A1A1A), + ), + ), + )), + GestureDetector( + onTap: () { + state(() { + Navigator.of(context).pop(); + }); + }, + child: Padding( + padding: EdgeInsets.only(right: 16.w), + child: Image.asset( + "assets/image/cancel.webp", + width: 25.h, + height: 25.h, + ), + ), + ), + ], + ), + Expanded(child:ListView.builder( + padding: EdgeInsets.zero, + itemCount: goodsCategoryList?.length ??0, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, position) { + return GestureDetector( + onTap: () { + state(() { + categoryIndex = position; + }); + }, + child: categoryItem(goodsCategoryList[position],position), + ); + }, + )), + GestureDetector( + onTap: () { + setState(() { + categoryName = goodsCategoryList[categoryIndex].categoryName; + Navigator.of(context).pop(); + }); + }, + child: Container( + width: double.infinity, + alignment: Alignment.center, + margin: EdgeInsets.symmetric(vertical:25.h,horizontal:16.w), + padding: EdgeInsets.symmetric(vertical: 16.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(27), + color: Color(0xFF30415B)), + child: Text( + S.of(context).queding, + style: TextStyle( + fontWeight: MyFontWeight.semi_bold, + fontSize: 16.sp, + color: Colors.white, + ), + ), + ), + ) + ], + ), + ); + }); + }); + } + + Widget categoryItem(GoodsCategoryList goodsCategoryList,index){ + return Container( + height: 52.h, + margin: EdgeInsets.only(bottom: 12,left:16.w,right: 16.w), + child: Stack( + alignment: Alignment.bottomRight, + children: [ + Container( + height: 52.h, + width: double.infinity, + decoration: BoxDecoration( + color: categoryIndex == index + ? Color(0xFFEFF5FF) + : Color(0xFFF7F7F7), + borderRadius: BorderRadius.circular(4.w), + border: Border.all( + color: categoryIndex == index + ? Color(0xFF30415B) + : Colors.white, + width: categoryIndex == index ? 1.w : 0, + ), + ), + padding: EdgeInsets.only( + top: 16.h, + bottom: 16.h, + left: 16.w, + right: 17.w), + child: Text( + goodsCategoryList?.categoryName ?? "", + style: TextStyle( + fontSize: 14.sp, + fontWeight: MyFontWeight.medium, + color: categoryIndex == index + ? Color(0xFF30415B) + : Color(0xFF0D0D0D)), + ), + ), + if (categoryIndex == index) + Image.asset( + "assets/image/bs_shop.webp", + width: 20, + height: 20, + fit: BoxFit.fill, + ), + ], + ), + ); + } + + ///商品分组弹窗选择 + goodsGroup() { + showModalBottomSheet( + context: context, + backgroundColor: Colors.transparent, + builder: (context) { + return StatefulBuilder(builder: ( + context, + state, + ) { + return Container( + width: double.infinity, + height: 365.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8), + topRight: Radius.circular(8), + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Container( + alignment: Alignment.center, + margin: EdgeInsets.only( + top: 12.h, bottom: 12.h, left: 41.w), + child: Text( + "选择官方分类", + style: TextStyle( + fontWeight: MyFontWeight.bold, + fontSize: 16.sp, + color: Color(0xFF1A1A1A), + ), + ), + )), + GestureDetector( + onTap: () { + state(() { + Navigator.of(context).pop(); + }); + }, + child: Padding( + padding: EdgeInsets.only(right: 16.w), + child: Image.asset( + "assets/image/cancel.webp", + width: 25.h, + height: 25.h, + ), + ), + ), + ], + ), + Expanded(child:ListView.builder( + padding: EdgeInsets.zero, + itemCount: productGroupList?.records?.length ?? 0, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, position) { + return GestureDetector( + onTap: () { + state(() { + groupIndex = position; + }); + }, + child: groupItem(productGroupList.records[position],position), + ); + }, + )), + GestureDetector( + onTap: () { + setState(() { + groupName = productGroupList?.records[groupIndex]?.groupName ?? ""; + Navigator.of(context).pop(); + }); + }, + child: Container( + width: double.infinity, + alignment: Alignment.center, + margin: EdgeInsets.symmetric(vertical:25.h,horizontal:16.w), + padding: EdgeInsets.symmetric(vertical: 16.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(27), + color: Color(0xFF30415B)), + child: Text( + S.of(context).queding, + style: TextStyle( + fontWeight: MyFontWeight.semi_bold, + fontSize: 16.sp, + color: Colors.white, + ), + ), + ), + ) + ], + ), + ); + }); + }); + } + + Widget groupItem(Records records,index){ + return Container( + height: 52.h, + margin: EdgeInsets.only(bottom: 12,left:16.w,right: 16.w), + child: Stack( + alignment: Alignment.bottomRight, + children: [ + Container( + height: 52.h, + width: double.infinity, + decoration: BoxDecoration( + color: groupIndex == index + ? Color(0xFFEFF5FF) + : Color(0xFFF7F7F7), + borderRadius: BorderRadius.circular(4.w), + border: Border.all( + color: groupIndex == index + ? Color(0xFF30415B) + : Colors.white, + width: groupIndex == index ? 1.w : 0, + ), + ), + padding: EdgeInsets.only( + top: 16.h, + bottom: 16.h, + left: 16.w, + right: 17.w), + child: Text( + records?.groupName ?? "", + style: TextStyle( + fontSize: 14.sp, + fontWeight: MyFontWeight.medium, + color: categoryIndex == index + ? Color(0xFF30415B) + : Color(0xFF0D0D0D)), + ), + ), + if (groupIndex == index) + Image.asset( + "assets/image/bs_shop.webp", + width: 20, + height: 20, + fit: BoxFit.fill, + ), + ], + ), + ); + } +} diff --git a/lib/business_system/goods/add_goods/edit_specs_detail.dart b/lib/business_system/goods/add_goods/edit_specs_detail.dart new file mode 100644 index 00000000..8941c6ad --- /dev/null +++ b/lib/business_system/goods/add_goods/edit_specs_detail.dart @@ -0,0 +1,440 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:huixiang/view_widget/my_appbar.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../../generated/l10n.dart'; +import '../../../retrofit/business_api.dart'; +import '../../../retrofit/data/edit_specs_detail_list.dart'; +import '../../../utils/font_weight.dart'; +import '../../../view_widget/settlement_tips_dialog.dart'; + +class EditSpecsDetail extends StatefulWidget { + final Map arguments; + + EditSpecsDetail({this.arguments}); + + @override + State createState() { + return _EditSpecsDetail(); + } +} + +class _EditSpecsDetail extends State { + List editSpecsDetailList = []; + bool isKeyBoardShow = false; + FocusNode _focusNode = FocusNode(); + BusinessApiService businessService; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + print("object: ${MediaQuery.of(context).viewInsets.bottom}"); + if (MediaQuery.of(context).viewInsets.bottom == 0) { + if (isKeyBoardShow) { + isKeyBoardShow = false; + //关闭键盘 软键盘关闭了, 清除输入控件的焦点, 否则重新进入页面会导致软键盘再弹出问题 + FocusScope.of(context).requestFocus(FocusNode()); + } + } else { + isKeyBoardShow = true; + } + }); + }); + List skus = widget?.arguments["skus"] ?? []; + List> specsDetails = + widget.arguments["specsDetails"] ?? []; + skus.forEach((element) { + var edit = EditSpecsDetailList(element); + for(var e1 in specsDetails){ + if(e1["skuName"] == element){ + edit.goodPriceController.text = e1["goodPrice"]; + edit.originalPriceController.text = e1["originalPrice"]; + edit.packagingFeeController.text = e1["packagingFee"]; + edit.specsWeightController.text = e1["specsWeight"]; + edit.skuStockController.text = e1["skuStock"]; + break; + } + } + editSpecsDetailList.add(edit); + }); + } + + ///离开页面记着销毁和清除 + @override + void dispose() { + _focusNode.unfocus(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + appBar: MyAppBar( + title: "编辑规格明细", + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + brightness: Brightness.dark, + ), + body: Stack( + children: [ + Container( + margin: EdgeInsets.only(bottom: 120.h), + child: ListView.builder( + padding: EdgeInsets.zero, + itemCount: editSpecsDetailList.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, position) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + FocusScope.of(context).unfocus(); + }); + }, + child: editSpecsItem(position)); + }, + ), + ), + + ///确认 + Align( + alignment: Alignment.bottomCenter, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + bool flag = false; + String editType = ""; + List> specsDetail = []; + editSpecsDetailList.forEach((element) { + if (element.goodPriceController.text.trim() == "") { + flag = true; + editType = "请输入商品售价"; + return; + } else if (element.originalPriceController.text.trim() == + "") { + flag = true; + editType = "请输入商品原价"; + return; + } + specsDetail.add({ + "skuName": element.specsDetailName, + "goodPrice": element.goodPriceController.text, + "originalPrice": element.originalPriceController.text, + "packagingFee": element.packagingFeeController.text, + "specsWeight": element.specsWeightController.text, + "skuStock": element.skuStockController.text + }); + }); + if (flag) { + SmartDialog.show( + clickBgDismissTemp: false, + widget: SettlementTips( + () {}, + text: editType, + color: Color(0xFF30415B), + )); + } else { + Navigator.of(context).pop(specsDetail); + } + }, + child: Container( + color: Colors.white, + width: double.infinity, + padding: EdgeInsets.only( + top: 10.h, left: 16.w, right: 16.w, bottom: 34.h), + child: Container( + alignment: Alignment.center, + height: 54.h, + decoration: BoxDecoration( + color: Color(0xFF30415B), + borderRadius: BorderRadius.circular(27), + ), + child: Text( + S.of(context).baocun, + style: TextStyle( + color: Colors.white, + fontSize: 16.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ), + )) + ], + ), + ); + } + + ///编辑规格list + Widget editSpecsItem(index) { + return Container( + color: Colors.white, + margin: EdgeInsets.symmetric(vertical: 12.h), + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + editSpecsDetailList[index].specsDetailName ?? "", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + Container( + width: double.infinity, + height: 1.h, + margin: EdgeInsets.only(top: 20.h), + color: Color(0x14000000), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: "*", + style: TextStyle( + color: Color(0xFFE02020), + fontSize: 14.sp, + fontWeight: FontWeight.w500, + ), + ), + TextSpan( + text: "商品售价", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ], + ), + ), + ), + Expanded( + child: TextField( + controller: editSpecsDetailList[index].goodPriceController, + decoration: InputDecoration( + hintText: "请输入商品售卖价格", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + flex: 2, + ), + ], + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: "*", + style: TextStyle( + color: Color(0xFFE02020), + fontSize: 14.sp, + fontWeight: FontWeight.w500, + ), + ), + TextSpan( + text: "商品原价", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ], + ), + ), + ), + Expanded( + child: TextField( + controller: + editSpecsDetailList[index].originalPriceController, + decoration: InputDecoration( + hintText: "请输入商品划线价格", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + flex: 2, + ), + ], + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "商品打包费", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ), + Expanded( + child: TextField( + controller: editSpecsDetailList[index].packagingFeeController, + decoration: InputDecoration( + hintText: "请输入商品打包费", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + flex: 2, + ), + ], + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "商品重量", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ), + Expanded( + child: TextField( + controller: editSpecsDetailList[index].specsWeightController, + decoration: InputDecoration( + hintText: "请输入商品重量(单位kg)", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + flex: 2, + ), + ], + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "商品库存", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ), + Expanded( + child: TextField( + controller: editSpecsDetailList[index].skuStockController, + decoration: InputDecoration( + hintText: "请输入商品库存", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + flex: 2, + ), + ], + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + ], + ), + ); + } +} diff --git a/lib/business_system/goods/add_goods/set_goods_specs.dart b/lib/business_system/goods/add_goods/set_goods_specs.dart new file mode 100644 index 00000000..7c7611d4 --- /dev/null +++ b/lib/business_system/goods/add_goods/set_goods_specs.dart @@ -0,0 +1,444 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:huixiang/view_widget/my_appbar.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../../retrofit/business_api.dart'; +import '../../../retrofit/data/edit_specs_detail_list.dart'; +import '../../../retrofit/data/set_specs_list.dart'; +import '../../../utils/font_weight.dart'; +import '../../../view_widget/settlement_tips_dialog.dart'; + +class SetGoodsSpecs extends StatefulWidget { + final Map arguments; + + SetGoodsSpecs({this.arguments}); + + @override + State createState() { + return _SetGoodsSpecs(); + } +} + +class _SetGoodsSpecs extends State { + List specs = []; + List> specsDetails = []; + bool isKeyBoardShow = false; + FocusNode _focusNode = FocusNode(); + BusinessApiService businessService; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + print("object: ${MediaQuery.of(context).viewInsets.bottom}"); + if (MediaQuery.of(context).viewInsets.bottom == 0) { + if (isKeyBoardShow) { + isKeyBoardShow = false; + //关闭键盘 软键盘关闭了, 清除输入控件的焦点, 否则重新进入页面会导致软键盘再弹出问题 + FocusScope.of(context).requestFocus(FocusNode()); + } + } else { + isKeyBoardShow = true; + } + }); + }); + } + + ///离开页面记着销毁和清除 + @override + void dispose() { + _focusNode.unfocus(); + super.dispose(); + } + + ///sku计算 + List mergeArr(List> arr) { + var result = arr.removeAt(0); + while (arr.isNotEmpty) { + var curArr = arr.removeAt(0); + var lastArr = result; + result = []; + for (var lastVal in lastArr) { + for (var curVal in curArr) { + result.add("$lastVal $curVal"); + } + } + } + return result; + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: MyAppBar( + title: "设置商品规格", + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + brightness: Brightness.dark, + ), + body: Stack( + children: [ + SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Container( + margin: EdgeInsets.only(bottom: 150.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.builder( + padding: EdgeInsets.zero, + itemCount: specs.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, position) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: specsText(position)); + }, + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + specs.add(SetSpecsList()); + }); + }, + child: Container( + color: Colors.white, + padding: EdgeInsets.symmetric(vertical: 20.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.add_circle, + color: Color(0xFF30415B), + size: 20, + ), + Padding( + padding: EdgeInsets.only(left: 7.w), + child: Text( + "添加规格", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ], + ), + ), + ), + if (specs.length > 0) + Padding( + padding: EdgeInsets.all(16), + child: Text( + "设置库存/价格等规格明细", + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 12.sp, + fontWeight: MyFontWeight.bold, + ), + )), + if (specs.length > 0) + Container( + color: Colors.white, + padding: EdgeInsets.only( + top: 20.h, + bottom: 20.h, + left: 16.w, + right: 20.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "规格明细", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + )), + Expanded( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + bool flag = false; + String tipText = ""; + specs.forEach((element) { + if (element.specsNameController.text + .trim() == + "") { + flag = true; + tipText = "规格名称未输入,请先输入规格名称"; + return; + } else if (element + .specsValues.length == + 0) { + flag = true; + tipText = "未添加规格值,请先添加规格值"; + return; + } + }); + if (flag) { + SmartDialog.show( + clickBgDismissTemp: false, + widget: SettlementTips( + () {}, + text: tipText, + color: Color(0xFF30415B), + )); + } else { + List skus = mergeArr(specs + .map((e) => e.specsValues) + .toList()); + Navigator.of(context).pushNamed( + '/router/edit_specs_detail', + arguments: { + "skus": skus, + "specsDetails": specsDetails + }).then((value) { + if (value != null){ + specsDetails.clear(); + specsDetails.addAll(value); + setState((){}); + } + }); + } + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.end, + children: [ + Padding( + padding: + EdgeInsets.only(right: 5.w), + child: Text( + "去设置", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + Image.asset( + "assets/image/bs_right.webp", + width: 16.h, + height: 16.h, + ), + ], + ))) + ], + ), + ), + ], + ), + )), + + ///确认 + Align( + alignment: Alignment.bottomCenter, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () {}, + child: Container( + color: Colors.white, + width: double.infinity, + padding: EdgeInsets.only( + top: 10.h, left: 16.w, right: 16.w, bottom: 34.h), + child: Container( + alignment: Alignment.center, + height: 54.h, + decoration: BoxDecoration( + color: Color(0xFF30415B), + borderRadius: BorderRadius.circular(27), + ), + child: Text( + "确认", + style: TextStyle( + color: Colors.white, + fontSize: 16.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ), + )) + ], + ), + )); + } + + ///添加规格样式 + Widget specsText(index) { + return Container( + color: Colors.white, + margin: EdgeInsets.symmetric(vertical: 12.h), + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "添加规格", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + Expanded( + child: TextField( + controller: specs[index].specsNameController, + decoration: InputDecoration( + hintText: "请输入规格名称", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF0D0D0D), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold), + ), + flex: 2, + ), + ], + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 16.h), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + flex: 1, + child: Text( + "规格植", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + Expanded( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pushNamed( + '/router/set_goods_specs_value', + arguments: { + "storeId": "", + "specsValues": specs[index].specsValues + }).then((value) { + if (value != null) + setState(() { + specs[index].specsValues = value; + }); + }); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Text( + specs[index].specsValues.length != 0 + ? specs[index] + .specsValues + .map((e) => e) + .toString() + .replaceAll("(", "") + .replaceAll(")", "") + : "请添加规格值", + overflow: TextOverflow.ellipsis, + maxLines: 1, + textAlign: TextAlign.end, + style: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + )), + Image.asset( + "assets/image/bs_right.webp", + width: 16.h, + height: 16.h, + ), + ], + ), + ), + flex: 2, + ), + ], + )), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + margin: EdgeInsets.only(bottom: 18.h), + ), + GestureDetector( + onTap: () { + setState(() { + specs.removeAt(index); + }); + }, + child: Padding( + padding: EdgeInsets.only(bottom: 20.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Icon( + Icons.remove_circle, + color: Color(0xFFFA5151), + size: 24, + ), + Padding( + padding: EdgeInsets.only(left: 7.w), + child: Text( + "删除", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ], + )), + ) + ], + ), + ); + } +} diff --git a/lib/business_system/goods/add_goods/set_goods_specs_value.dart b/lib/business_system/goods/add_goods/set_goods_specs_value.dart new file mode 100644 index 00000000..de56fb95 --- /dev/null +++ b/lib/business_system/goods/add_goods/set_goods_specs_value.dart @@ -0,0 +1,252 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:huixiang/view_widget/my_appbar.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../../retrofit/business_api.dart'; +import '../../../retrofit/data/set_specs_list.dart'; +import '../../../retrofit/data/set_specs_value_list.dart'; +import '../../../utils/font_weight.dart'; +import '../../../view_widget/settlement_tips_dialog.dart'; + +class SetGoodsSpecsValue extends StatefulWidget { + final Map arguments; + + SetGoodsSpecsValue({this.arguments}); + + @override + State createState() { + return _SetGoodsSpecsValue(); + } +} + +class _SetGoodsSpecsValue extends State { + List specsValue = []; + bool isKeyBoardShow = false; + FocusNode _focusNode = FocusNode(); + BusinessApiService businessService; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + print("object: ${MediaQuery.of(context).viewInsets.bottom}"); + if (MediaQuery.of(context).viewInsets.bottom == 0) { + if (isKeyBoardShow) { + isKeyBoardShow = false; + //关闭键盘 软键盘关闭了, 清除输入控件的焦点, 否则重新进入页面会导致软键盘再弹出问题 + FocusScope.of(context).requestFocus(FocusNode()); + } + } else { + isKeyBoardShow = true; + } + }); + }); + List specsValues = widget.arguments["specsValues"] ?? []; + specsValues.forEach((element) { + var temp = SetSpecsValueList(); + temp.specsValueNameController.text = element; + specsValue.add(temp); + }); + } + + ///离开页面记着销毁和清除 + @override + void dispose() { + _focusNode.unfocus(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: MyAppBar( + title: "设置商品规格值", + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + brightness: Brightness.dark, + ), + body: Stack( + children: [ + SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Container( + margin: EdgeInsets.only(bottom: 150.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + color: Colors.white, + child: ListView.builder( + padding: EdgeInsets.zero, + itemCount: specsValue.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, position) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() {}); + }, + child: specsValueText(position)); + }, + )), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + specsValue.add(SetSpecsValueList()); + FocusScope.of(context).unfocus(); + }); + }, + child: Container( + color: Colors.white, + padding: EdgeInsets.symmetric(vertical: 20.h), + margin: EdgeInsets.only(top: 12.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.add_circle, + color: Color(0xFF30415B), + size: 20, + ), + Padding( + padding: EdgeInsets.only(left: 7.w), + child: Text( + "添加规格值", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ], + ), + ), + ), + ], + ), + )), + + ///确认 + Align( + alignment: Alignment.bottomCenter, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + bool flag = false; + List values = []; + specsValue.forEach((element) { + if (element.specsValueNameController.text == "") { + flag = true; + return; + } + values.add(element.specsValueNameController.text); + }); + if (flag) { + SmartDialog.show( + clickBgDismissTemp: false, + widget: SettlementTips( + () {}, + text: "还有规格未输入值,请输入完整", + color: Color(0xFF30415B), + )); + } else { + Navigator.of(context).pop(values); + } + }, + child: Container( + color: Colors.white, + width: double.infinity, + padding: EdgeInsets.only( + top: 10.h, left: 16.w, right: 16.w, bottom: 34.h), + child: Container( + alignment: Alignment.center, + height: 54.h, + decoration: BoxDecoration( + color: Color(0xFF30415B), + borderRadius: BorderRadius.circular(27), + ), + child: Text( + "确认", + style: TextStyle( + color: Colors.white, + fontSize: 16.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ), + )) + ], + ), + )); + } + + ///添加规格样式 + Widget specsValueText(index) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + setState(() { + specsValue.removeAt(index); + }); + }, + child: Container( + padding: EdgeInsets.only(right: 12.w), + child: Icon( + Icons.remove_circle, + color: Color(0xFFFA5151), + size: 24, + ), + ), + ), + Expanded( + child: TextField( + controller: specsValue[index].specsValueNameController, + decoration: InputDecoration( + hintText: "请输入规格值名称", + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + border: InputBorder.none, + ), + style: TextStyle( + color: Color(0xFF0D0D0D), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold), + ), + flex: 2, + ), + ], + ), + if (specsValue.length - 1 > index) + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + ], + ), + ); + } +} diff --git a/lib/business_system/goods/add_goods/set_meal.dart b/lib/business_system/goods/add_goods/set_meal.dart new file mode 100644 index 00000000..4aa5b01d --- /dev/null +++ b/lib/business_system/goods/add_goods/set_meal.dart @@ -0,0 +1,491 @@ +import 'package:flutter/material.dart'; +import 'package:huixiang/view_widget/my_appbar.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../../retrofit/business_api.dart'; +import '../../../retrofit/data/set_specs_meal_list.dart'; +import '../../../utils/font_weight.dart'; + +class SetMeal extends StatefulWidget { + final Map arguments; + + SetMeal({this.arguments}); + + @override + State createState() { + return _SetMeal(); + } +} + +class _SetMeal extends State { + List specsMeal = []; + bool isKeyBoardShow = false; + FocusNode _focusNode = FocusNode(); + BusinessApiService businessService; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + print("object: ${MediaQuery.of(context).viewInsets.bottom}"); + if (MediaQuery.of(context).viewInsets.bottom == 0) { + if (isKeyBoardShow) { + isKeyBoardShow = false; + //关闭键盘 软键盘关闭了, 清除输入控件的焦点, 否则重新进入页面会导致软键盘再弹出问题 + FocusScope.of(context).requestFocus(FocusNode()); + } + } else { + isKeyBoardShow = true; + } + }); + }); + } + + ///离开页面记着销毁和清除 + @override + void dispose() { + _focusNode.unfocus(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: MyAppBar( + title: "套餐选择", + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + brightness: Brightness.dark, + action: GestureDetector( + onTap: () { + }, + child: Text( + "确定", + style: TextStyle( + color: Color(0xFF30415B), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ), + body: Stack( + children: [ + SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Container( + margin: EdgeInsets.only(bottom: 150.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.builder( + padding: EdgeInsets.zero, + itemCount: specsMeal.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, position) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() {}); + }, + child: specsValueText(position)); + }, + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + specsMeal.add(SetSpecsMealList()); + }); + }, + child: Container( + color: Colors.white, + padding: EdgeInsets.symmetric(vertical: 20.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.add_circle, + color: Color(0xFF30415B), + size: 20, + ), + Padding( + padding: EdgeInsets.only(left: 7.w), + child: Text( + "添加分组", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ], + ), + ), + ), + ], + ), + )), + ], + ), + )); + } + + ///添加规格样式 + Widget specsValueText(index) { + return Column( + children: [ + Container( + color: Colors.white, + margin: EdgeInsets.symmetric(vertical: 12.h), + padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 12.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "分组1", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + Expanded( + child: TextField( + controller: specsMeal[index].groupsNameController, + decoration: InputDecoration( + hintText: "请输入分组名称", + hintTextDirection: TextDirection.rtl, + hintStyle: TextStyle( + color: Color(0xFF7A797F), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + border: InputBorder.none, + ), + textAlign: TextAlign.right, + style: TextStyle( + color: Color(0xFF0D0D0D), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold), + ), + flex: 2, + ), + ], + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 14.h), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "分组总数", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + if (specsMeal[index].groupsTotal <= 1) return; + specsMeal[index].groupsTotal = + specsMeal[index].groupsTotal - 1; + }); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20.w), + child: Icon( + Icons.remove_circle_outline, + color: Color(0xFF30415B), + size: 24, + ))), + Text( + specsMeal[index].groupsTotal.toString(), + style: TextStyle( + color: Color(0xD9000000), + fontSize: 20.sp, + fontWeight: MyFontWeight.regular, + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + specsMeal[index].groupsTotal = + specsMeal[index].groupsTotal + 1; + }); + }, + child: Container( + padding: EdgeInsets.only(left: 20.w), + child: Icon( + Icons.add_circle, + color: Color(0xFF30415B), + size: 24, + )), + ), + ], + )), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + margin: EdgeInsets.only(bottom: 18.h), + ), + Padding( + padding: EdgeInsets.only(bottom: 14.h), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + "可选数量", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + if (specsMeal[index].optionalNum <= 1) return; + specsMeal[index].optionalNum = + specsMeal[index].optionalNum - 1; + }); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20.w), + child: Icon( + Icons.remove_circle_outline, + color: Color(0xFF30415B), + size: 24, + ))), + Text( + specsMeal[index].optionalNum.toString(), + style: TextStyle( + color: Color(0xD9000000), + fontSize: 20.sp, + fontWeight: MyFontWeight.regular, + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + specsMeal[index].optionalNum = + specsMeal[index].optionalNum + 1; + }); + }, + child: Container( + padding: EdgeInsets.only(left: 20.w), + child: Icon( + Icons.add_circle, + color: Color(0xFF30415B), + size: 24, + )), + ), + ], + )), + Container( + width: double.infinity, + height: 1.h, + color: Color(0x14000000), + margin: EdgeInsets.only(bottom: 18.h), + ), + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pushNamed('/router/batch_shelf', + arguments: { + "storeId": widget.arguments["storeId"], + "titleName": "选择商品" + }).then((value) { + specsMeal[index].goodsMeal.clear(); + specsMeal[index].goodsMeal.addAll(value); + setState(() {}); + }); + }, + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.only( + left: 8.w, right: 8.w, bottom: 3.h), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: Color(0xFF2E3552), + width: 1, + ), + borderRadius: BorderRadius.circular(100), + ), + child: Text( + "+增加商品", + style: TextStyle( + color: Color(0xFF30415B), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + )), + Spacer(), + GestureDetector( + onTap: () { + setState(() { + specsMeal.removeAt(index); + }); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Icon( + Icons.remove_circle, + color: Color(0xFFFA5151), + size: 24, + ), + Padding( + padding: EdgeInsets.only(left: 7.w), + child: Text( + "删除分组", + style: TextStyle( + color: Color(0xD9000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.bold, + ), + ), + ), + ], + ), + ) + ], + ), + ), + Text( + "*请添加或减少商品,直到达到分组总数", + style: TextStyle( + color: Color(0xFFFA5151), + fontSize: 12.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ], + ), + ), + ListView.builder( + itemCount: specsMeal[index]?.goodsMeal?.length ?? 0, + physics: BouncingScrollPhysics(), + shrinkWrap: true, + itemBuilder: (context, position) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () {}, + child: specsInfoItem(index, position), + ); + }, + ) + ], + ); + } + + ///规格信息样式 + Widget specsInfoItem(specsIndex, index) { + return Container( + color: Colors.white, + margin: EdgeInsets.symmetric(vertical: 12.h), + padding: EdgeInsets.only( + left: 16.w, + top: 20.h, + bottom: 20.h, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + specsMeal[specsIndex]?.goodsMeal[index]["goodsName"] ?? "", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Color(0xFF000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + flex: 2, + ), + Expanded( + child: Text( + "所有规格", + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + ), + ), + Expanded( + child: Text( + specsMeal[specsIndex]?.goodsMeal[index]["goodsNum"] ?? "", + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF000000), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular, + ), + )), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + specsMeal[specsIndex].goodsMeal.removeAt(index); + }); + }, + child: Container( + padding: EdgeInsets.only(right: 31.h), + child: Icon( + Icons.remove_circle, + color: Color(0xFFFA5151), + size: 20, + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/business_system/login/captcha/bus_block_puzzle_captcha.dart b/lib/business_system/login/captcha/bus_block_puzzle_captcha.dart new file mode 100644 index 00000000..0f7c5e16 --- /dev/null +++ b/lib/business_system/login/captcha/bus_block_puzzle_captcha.dart @@ -0,0 +1,551 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:huixiang/login/captcha/click_word_captcha.dart'; + +import '../../../retrofit/business_api.dart'; +import '../../../utils/captcha_util.dart'; +import '../../../utils/widget_util.dart'; + +typedef VoidSuccessCallback = dynamic Function(String v); + +class BusBlockPuzzleCaptchaPage extends StatefulWidget { + final VoidSuccessCallback onSuccess; //拖放完成后验证成功回调 + final VoidCallback onFail; //拖放完成后验证失败回调 + + BusBlockPuzzleCaptchaPage({this.onSuccess, this.onFail}); + + @override + _BusBlockPuzzleCaptchaPageState createState() => _BusBlockPuzzleCaptchaPageState(); +} + +class _BusBlockPuzzleCaptchaPageState extends State + with TickerProviderStateMixin { +// String baseImageBase64 = +// "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"; + String baseImageBase64 = ""; + String slideImageBase64 = ""; + String captchaToken = ""; + String secretKey = ""; //加密key + + Size baseSize = Size.zero; //底部基类图片 + Size slideSize = Size.zero; //滑块图片 + + var sliderColor = Colors.white; //滑块的背景色 + var sliderIcon = Icons.arrow_forward; //滑块的图标 + var movedXBorderColor = Colors.white; //滑块拖动时,左边已滑的区域边框颜色 + double sliderStartX = 0; //滑块未拖前的X坐标 + double sliderXMoved = 0; + bool sliderMoveFinish = false; //滑块拖动结束 + bool checkResultAfterDrag = false; //拖动后的校验结果 + + //-------------动画------------ + int _checkMilliseconds = 0; //滑动时间 + bool _showTimeLine = false; //是否显示动画部件 + bool _checkSuccess = false; //校验是否成功 + AnimationController controller; + + //高度动画 + Animation offsetAnimation; + + //底部部件key + GlobalKey _containerKey = new GlobalKey(); + + //背景图key + GlobalKey _baseImageKey = new GlobalKey(); + + //滑块 + GlobalKey _slideImageKey = new GlobalKey(); + double _bottomSliderSize = 60.h; + + //------------动画------------ + + //校验通过 + void checkSuccess(String content) { + setState(() { + checkResultAfterDrag = true; + _checkSuccess = true; + _showTimeLine = true; + }); + _forwardAnimation(); + updateSliderColorIcon(); + + //刷新验证码 + Future.delayed(Duration(milliseconds: 1000)).then((v) { + _reverseAnimation().then((v) { + setState(() { + _showTimeLine = false; + }); + //回调 + if (widget.onSuccess != null) { + widget.onSuccess(content); + } + //关闭验证码 + print(content); + Navigator.pop(context); + }); + }); + } + + //校验失败 + void checkFail() { + setState(() { + _showTimeLine = true; + _checkSuccess = false; + checkResultAfterDrag = false; + }); + _forwardAnimation(); + updateSliderColorIcon(); + + //刷新验证码 + Future.delayed(Duration(milliseconds: 1000)).then((v) { + _reverseAnimation().then((v) { + setState(() { + _showTimeLine = false; + }); + loadCaptcha(); + //回调 + if (widget.onFail != null) { + widget.onFail(); + } + }); + }); + } + + //重设滑动颜色与图标 + void updateSliderColorIcon() { + var _sliderColor; //滑块的背景色 + var _sliderIcon; //滑块的图标 + var _movedXBorderColor; //滑块拖动时,左边已滑的区域边框颜色 + + //滑块的背景色 + if (sliderMoveFinish) { + //拖动结束 + _sliderColor = checkResultAfterDrag ? Colors.green : Colors.red; + _sliderIcon = checkResultAfterDrag ? Icons.check : Icons.close; + _movedXBorderColor = checkResultAfterDrag ? Colors.green : Colors.red; + } else { + //拖动未开始或正在拖动中 + _sliderColor = sliderXMoved > 0 ? Color(0xff447ab2) : Colors.white; + _sliderIcon = Icons.arrow_forward; + _movedXBorderColor = Color(0xff447ab2); + } + + sliderColor = _sliderColor; + sliderIcon = _sliderIcon; + movedXBorderColor = _movedXBorderColor; + setState(() {}); + } + + //加载验证码 + void loadCaptcha() async { + setState(() { + _showTimeLine = false; + sliderMoveFinish = false; + checkResultAfterDrag = false; + sliderColor = Colors.white; //滑块的背景色 + sliderIcon = Icons.arrow_forward; //滑块的图标 + movedXBorderColor = Colors.white; //滑块拖动时,左边已滑的区域边框颜色 + }); + BusinessApiService businessService = BusinessApiService(Dio(), context: context); + ClickWordCaptchaModel baseData = await businessService + .captchaGet({"captchaType": "blockPuzzle"}).catchError((onError) {}); + if (baseData == null) { + setState(() { + secretKey = ""; + }); + return; + } + + sliderXMoved = 0; + sliderStartX = 0; + captchaToken = ''; + checkResultAfterDrag = false; + + baseImageBase64 = baseData.imgStr; + secretKey = baseData.secretKey; + baseImageBase64 = baseImageBase64.replaceAll('\n', ''); + slideImageBase64 = baseData.jigsawImageBase64; + slideImageBase64 = slideImageBase64.replaceAll('\n', ''); + captchaToken = baseData.token; + + var baseR = await WidgetUtil.getImageWH( + image: Image.memory(Base64Decoder().convert(baseImageBase64))); + baseSize = baseR.size; + + var silderR = await WidgetUtil.getImageWH( + image: Image.memory(Base64Decoder().convert(slideImageBase64))); + slideSize = silderR.size; + + setState(() {}); + } + + //校验验证码 + void checkCaptcha(sliderXMoved, captchaToken, {BuildContext myContext}) { + setState(() { + sliderMoveFinish = true; + }); + //滑动结束,改变滑块的图标及颜色 +// updateSliderColorIcon(); + + //pointJson参数需要aes加密 + +// MediaQueryData mediaQuery = MediaQuery.of(myContext); + var pointMap = {"x": sliderXMoved, "y": 5}; + var pointStr = json.encode(pointMap); + var cryptedStr = pointStr; + + // secretKey 不为空 进行as加密 + if (!CaptchaUtil.isEmpty(secretKey)) { + cryptedStr = CaptchaUtil.aesEncode(key: secretKey, content: pointStr); + // var dcrypt = CaptchaUtil.aesDecode(key: secretKey, content: cryptedStr); + // json.decode(dcrypt); + } + + BusinessApiService businessService = BusinessApiService(Dio(), context: context); + businessService + .captchaCheck({ + "pointJson": cryptedStr, + "captchaType": "blockPuzzle", + "token": captchaToken + }) + .catchError((onError) {}) + .then((res) { + if (res) { + checkFail(); + return; + } + //如果不加密 将 token 和 坐标序列化 通过 --- 链接成字符串 + var captchaVerification = "$captchaToken---$pointStr"; + if (!CaptchaUtil.isEmpty(secretKey)) { + //如果加密 将 token 和 坐标序列化 通过 --- 链接成字符串 进行加密 加密密钥为 _clickWordCaptchaModel.secretKey + captchaVerification = CaptchaUtil.aesEncode( + key: secretKey, content: captchaVerification); + } + checkSuccess(captchaVerification); + }) + .catchError((error) { + loadCaptcha(); + print(error); + }); + } + + @override + void initState() { + super.initState(); + initAnimation(); + loadCaptcha(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + // 初始化动画 + void initAnimation() { + controller = + AnimationController(duration: Duration(milliseconds: 500), vsync: this); + + offsetAnimation = Tween(begin: 0.5, end: 0) + .animate(CurvedAnimation(parent: controller, curve: Curves.ease)) + ..addListener(() { + this.setState(() {}); + }); + } + + // 反向执行动画 + _reverseAnimation() async { + await controller.reverse(); + } + + // 正向执行动画 + _forwardAnimation() async { + await controller.forward(); + } + + @override + void didUpdateWidget(BusBlockPuzzleCaptchaPage oldWidget) { + // TODO: implement didUpdateWidget + super.didUpdateWidget(oldWidget); + } + + @override + Widget build(BuildContext context) { + return MaxScaleTextWidget( + child: buildContent(context), + ); + } + + Widget buildContent(BuildContext context) { + var mediaQuery = MediaQuery.of(context); + var dialogWidth = 0.9 * mediaQuery.size.width; + if (dialogWidth < 330) { + dialogWidth = mediaQuery.size.width; + } + + return Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: Container( + key: _containerKey, + width: dialogWidth, + height: MediaQuery.of(context).size.height >= 750 ? 310.h:325.h, + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _topContainer(), + _middleContainer(), + _bottomContainer(), + ], + ), + ), + ), + ); + } + + ///顶部,提示+关闭 + _topContainer() { + return Container( + height: 50.h, + padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1.w, color: Color(0xffe5e5e5))), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '请完成安全验证', + style: TextStyle(fontSize: 18), + ), + IconButton( + icon: Icon(Icons.highlight_off), + iconSize: 30, + color: Colors.black38, + onPressed: () { + //退出 + Navigator.pop(context); + }), + ], + ), + ); + } + + _middleContainer() { + ////显示验证码 + return Container( + margin: EdgeInsets.symmetric(vertical: 10.h), + child: Stack( + children: [ + ///底图 310*155 + baseImageBase64.length > 0 + ? Image.memory( + Base64Decoder().convert(baseImageBase64), + fit: BoxFit.fitWidth, + key: _baseImageKey, + gaplessPlayback: true, + ) + : Container( + width: 310.w, + height: 155.h, + alignment: Alignment.center, + child: CircularProgressIndicator(), + ), + + ///滑块图 + (baseImageBase64.length > 0 && slideImageBase64.length > 0) + ? Container( + margin: EdgeInsets.fromLTRB(sliderXMoved, 0, 0, 0), + child: Image.memory( + Base64Decoder().convert(slideImageBase64), + fit: BoxFit.fitHeight, + key: _slideImageKey, + gaplessPlayback: true, + ), + ) + : Container(), + + //刷新按钮 + Positioned( + top: 0, + right: 0, + child: IconButton( + icon: Icon(Icons.refresh), + iconSize: 30, + color: Colors.black54, + onPressed: () { + //刷新 + loadCaptcha(); + }), + ), + Positioned( + bottom: 0, + left: -10.w, + right: -10.w, + child: Offstage( + offstage: !_showTimeLine, + child: FractionalTranslation( + translation: Offset(0, offsetAnimation.value), + child: Container( + margin: EdgeInsets.only(left: 10.w, right: 10.w), + height: 40.h, + color: _checkSuccess + ? Color(0x7F66BB6A) + : Color.fromRGBO(200, 100, 100, 0.4), + alignment: Alignment.centerLeft, + child: Text( + _checkSuccess + ? "${(_checkMilliseconds / (60.0 * 12)).toStringAsFixed(2)}s验证成功" + : "验证失败", + style: TextStyle(color: Colors.white), + ), + ), + ), + )), + Positioned( + bottom: -20.h, + left: 0, + right: 0, + child: Offstage( + offstage: !_showTimeLine, + child: Container( + margin: EdgeInsets.only(left: 10.w, right: 10.w), + height: 20.h, + color: Colors.white, + ), + )) + ], + ), + ); + } + + ///底部,滑动区域 + _bottomContainer() { + return baseSize.width > 0 + ? Container( + height: 70.h, + width: baseSize.width, +// color: Colors.cyanAccent, + child: Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + height: _bottomSliderSize, + decoration: BoxDecoration( + border: Border.all( + width: 1.w, + color: Color(0xffe5e5e5), + ), + color: Color(0xfff8f9fb), + ), + ), + Container( + alignment: Alignment.center, + child: Text( + '向右拖动滑块填充拼图', + style: TextStyle(fontSize: 14.sp), + ), + ), + Container( + width: sliderXMoved, + height: _bottomSliderSize - 2.h, + decoration: BoxDecoration( + border: Border.all( + width: sliderXMoved > 0 ? 1 : 0, + color: movedXBorderColor, + ), + color: Color(0xfff3fef1), + ), + ), + GestureDetector( + onPanStart: (startDetails) { + ///开始 + _checkMilliseconds = + new DateTime.now().millisecondsSinceEpoch; + // print(startDetails.localPosition); + sliderStartX = startDetails.localPosition.dx; + }, + onPanUpdate: (updateDetails) { + ///更新 + // print(updateDetails.localPosition); + double _w1 = _baseImageKey.currentContext.size.width - + _slideImageKey.currentContext.size.width; + double offset = + updateDetails.localPosition.dx - sliderStartX; + if (offset < 0) { + offset = 0; + } + if (offset > _w1) { + offset = _w1; + } + // print("offset ------ $offset"); + setState(() { + sliderXMoved = offset; + }); + //滑动过程,改变滑块左边框颜色 + updateSliderColorIcon(); + }, + onPanEnd: (endDetails) { + //结束 + // print("endDetails"); + checkCaptcha(sliderXMoved, captchaToken); + int _nowTime = new DateTime.now().millisecondsSinceEpoch; + _checkMilliseconds = _nowTime - _checkMilliseconds; + }, + child: Container( + width: _bottomSliderSize, + height: _bottomSliderSize, + margin: EdgeInsets.only( + left: sliderXMoved > 0 ? sliderXMoved : 1), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: 1.w, + color: Color(0xffe5e5e5), + ), + right: BorderSide( + width: 1.w, + color: Color(0xffe5e5e5), + ), + bottom: BorderSide( + width: 1.w, + color: Color(0xffe5e5e5), + ), + ), + color: sliderColor, + ), + child: IconButton( + icon: Icon(sliderIcon), + iconSize: 30, + color: Colors.black54, + onPressed: () {}, + ), + ), + ) + ], + )) + : Container(); + } +} + +class MaxScaleTextWidget extends StatelessWidget { + final double max; + final Widget child; + + MaxScaleTextWidget({Key key, this.max = 1.0, this.child}) : super(key: key); + + @override + Widget build(BuildContext context) { + var data = MediaQuery.of(context); + var textScaleFactor = min(max, data.textScaleFactor); + return MediaQuery( + data: data.copyWith(textScaleFactor: textScaleFactor), child: child); + } +} diff --git a/lib/business_system/login/captcha/bus_click_word_captcha.dart b/lib/business_system/login/captcha/bus_click_word_captcha.dart new file mode 100644 index 00000000..4ec1cda9 --- /dev/null +++ b/lib/business_system/login/captcha/bus_click_word_captcha.dart @@ -0,0 +1,367 @@ +import 'dart:convert'; +import 'package:dio/dio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import '../../../retrofit/business_api.dart'; +import '../../../utils/captcha_util.dart'; +import '../../../utils/widget_util.dart'; + +typedef VoidSuccessCallback = dynamic Function(String v); + +class BusClickWordCaptcha extends StatefulWidget { + final VoidSuccessCallback onSuccess; //文字点击后验证成功回调 + final VoidCallback onFail; //文字点击完成后验证失败回调 + + const BusClickWordCaptcha({Key key, this.onSuccess, this.onFail}) + : super(key: key); + + @override + _BusClickWordCaptchaState createState() => _BusClickWordCaptchaState(); +} + +class _BusClickWordCaptchaState extends State { + BusClickWordCaptchaState _busClickWordCaptchaState = BusClickWordCaptchaState.none; + List _tapOffsetList = []; + BusClickWordCaptchaModel _busClickWordCaptchaModel = BusClickWordCaptchaModel(); + + Color titleColor = Colors.black; + Color borderColor = Color(0xffdddddd); + String bottomTitle = ""; + Size baseSize = Size(310.0, 155.0); + + //改变底部样式及字段 + _changeResultState() { + switch (_busClickWordCaptchaState) { + case BusClickWordCaptchaState.normal: + titleColor = Colors.black; + borderColor = Color(0xffdddddd); + break; + case BusClickWordCaptchaState.success: + _tapOffsetList = []; + titleColor = Colors.green; + borderColor = Colors.green; + bottomTitle = "验证成功"; + break; + case BusClickWordCaptchaState.fail: + _tapOffsetList = []; + titleColor = Colors.red; + borderColor = Colors.red; + bottomTitle = "验证失败"; + break; + default: + titleColor = Colors.black; + borderColor = Color(0xffdddddd); + bottomTitle = "数据加载中……"; + break; + } + setState(() {}); + } + + @override + void initState() { + super.initState(); + _loadCaptcha(); + } + + //加载验证码 + _loadCaptcha() async { + _tapOffsetList = []; + _busClickWordCaptchaState = BusClickWordCaptchaState.none; + _changeResultState(); + BusinessApiService businessService = BusinessApiService(Dio(), context: context); + BusClickWordCaptchaModel baseData = (await businessService.captchaGet({"captchaType": "clickWord"}).catchError((onError) {})) as BusClickWordCaptchaModel; + if (baseData == null) { + _busClickWordCaptchaModel.secretKey = ""; + bottomTitle = "加载失败,请刷新"; + _busClickWordCaptchaState = BusClickWordCaptchaState.normal; + _changeResultState(); + return; + } + else { + _busClickWordCaptchaModel = baseData; + var baseR = await WidgetUtil.getImageWH( + image: Image.memory( + Base64Decoder().convert(_busClickWordCaptchaModel.imgStr))); + baseSize = baseR.size; + + bottomTitle = "请依次点击【${_busClickWordCaptchaModel.wordStr}】"; + } + + _busClickWordCaptchaState = BusClickWordCaptchaState.normal; + _changeResultState(); + } + + //校验验证码 + _checkCaptcha() async { + List> mousePos = []; + _tapOffsetList.map((size) { + mousePos + .add({"x": size.dx.roundToDouble(), "y": size.dy.roundToDouble()}); + }).toList(); + var pointStr = json.encode(mousePos); + + var cryptedStr = pointStr; + + // secretKey 不为空 进行as加密 + if (!CaptchaUtil.isEmpty(_busClickWordCaptchaModel.secretKey)) { + cryptedStr = CaptchaUtil.aesEncode( + key: _busClickWordCaptchaModel.secretKey, content: pointStr); + // var dcrypt = CaptchaUtil.aesDecode( + // key: _busClickWordCaptchaModel.secretKey, content: cryptedStr); + } + +// Map _map = json.decode(dcrypt); + BusinessApiService businessService = BusinessApiService(Dio(), context: context); + bool baseData = await businessService.captchaCheck({ + "pointJson": cryptedStr, + "captchaType": "clickWord", + "token": _busClickWordCaptchaModel.token + }).catchError((onError) {}); + if (baseData) { + _checkFail(); + return; + } + //如果不加密 将 token 和 坐标序列化 通过 --- 链接成字符串 + var captchaVerification = "${_busClickWordCaptchaModel.token}---$pointStr"; + if (!CaptchaUtil.isEmpty(_busClickWordCaptchaModel.secretKey)) { + //如果加密 将 token 和 坐标序列化 通过 --- 链接成字符串 进行加密 加密密钥为 _busClickWordCaptchaModel.secretKey + captchaVerification = CaptchaUtil.aesEncode( + key: _busClickWordCaptchaModel.secretKey, + content: captchaVerification); + } + _checkSuccess(captchaVerification); + } + + //校验失败 + _checkFail() async { + _busClickWordCaptchaState = BusClickWordCaptchaState.fail; + _changeResultState(); + + await Future.delayed(Duration(milliseconds: 1000)); + _loadCaptcha(); + //回调 + if (widget.onFail != null) { + widget.onFail(); + } + } + + //校验成功 + _checkSuccess(String pointJson) async { + _busClickWordCaptchaState = BusClickWordCaptchaState.success; + _changeResultState(); + + await Future.delayed(Duration(milliseconds: 1000)); + + var cryptedStr = CaptchaUtil.aesEncode(key: 'BGxdEUOZkXka4HSj', content: pointJson); + + print(cryptedStr); + //回调 pointJson 是经过es加密之后的信息 + if (widget.onSuccess != null) { + widget.onSuccess(cryptedStr); + } + //关闭 + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + var data = MediaQuery.of(context); + var dialogWidth = 0.9 * data.size.width; + var isRatioCross = false; + if (dialogWidth < 320.0) { + dialogWidth = data.size.width; + isRatioCross = true; + } + return Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: Container( + width: dialogWidth, + height: 320.h, + color: Colors.white, + child: Column( + children: [ + _topConttainer(), + _captchaContainer(), + _bottomContainer() + ], + ), + ), + ), + ); + } + + //图片验证码 + _captchaContainer() { + List _widgetList = []; + if (!CaptchaUtil.isEmpty(_busClickWordCaptchaModel.imgStr)) { + _widgetList.add(Image( + width: baseSize.width, + height: baseSize.height, + gaplessPlayback: true, + image: MemoryImage( + Base64Decoder().convert(_busClickWordCaptchaModel.imgStr)))); + } + + double _widgetW = 20; + for (int i = 0; i < _tapOffsetList.length; i++) { + Offset offset = _tapOffsetList[i]; + _widgetList.add(Positioned( + left: offset.dx - _widgetW * 0.5, + top: offset.dy - _widgetW * 0.5, + child: Container( + alignment: Alignment.center, + width: _widgetW, + height: _widgetW, + decoration: BoxDecoration( + color: Color(0xCC43A047), + borderRadius: BorderRadius.all(Radius.circular(_widgetW))), + child: Text( + "${i + 1}", + style: TextStyle(color: Colors.white, fontSize: 15), + ), + ))); + } + _widgetList.add(//刷新按钮 + Positioned( + top: 0, + right: 0, + child: IconButton( + icon: Icon(Icons.refresh), + iconSize: 30, + color: Colors.deepOrangeAccent, + onPressed: () { + //刷新 + _loadCaptcha(); + }), + )); + + return GestureDetector( + onTapDown: (TapDownDetails details) { + debugPrint( + "onTapDown globalPosition全局坐标系位置: ${details.globalPosition} localPosition组件坐标系位置: ${details.localPosition} "); + if (!CaptchaUtil.isListEmpty(_busClickWordCaptchaModel.wordList) && + _tapOffsetList.length < _busClickWordCaptchaModel.wordList.length) { + _tapOffsetList.add( + Offset(details.localPosition.dx, details.localPosition.dy)); + } + setState(() {}); + if (!CaptchaUtil.isListEmpty(_busClickWordCaptchaModel.wordList) && + _tapOffsetList.length == _busClickWordCaptchaModel.wordList.length) { + _checkCaptcha(); + } + }, + child: Container( + width: baseSize.width, + height: baseSize.height, + child: Stack( + children: _widgetList, + ), + )); + } + + //底部提示部件 + _bottomContainer() { + return Container( + height: 50.h, + margin: EdgeInsets.only(top: 10), + alignment: Alignment.center, + width: baseSize.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(4)), + border: Border.all(color: borderColor)), + child: + Text(bottomTitle, style: TextStyle(fontSize: 18, color: titleColor)), + ); + } + + //顶部,提示+关闭 + _topConttainer() { + return Container( + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + margin: EdgeInsets.only(bottom: 20, top: 5), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: Color(0xffe5e5e5))), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '请完成安全验证', + style: TextStyle(fontSize: 18), + ), + IconButton( + icon: Icon(Icons.highlight_off), + iconSize: 35, + color: Colors.black54, + onPressed: () { + //退出 + Navigator.pop(context); + }), + ], + ), + ); + } +} + +//校验状态 +enum BusClickWordCaptchaState { + normal, //默认 可自定义描述 + success, //成功 + fail, //失败 + none, //无状态 用于加载使用 +} + +//请求数据模型 +class BusClickWordCaptchaModel { + String imgStr; //图表url 目前用base64 data + String jigsawImageBase64; //图表url 目前用base64 data + String token; // 获取的token 用于校验 + List wordList; //显示需要点选的字 + String wordStr; //显示需要点选的字转换为字符串 + String secretKey; //加密key + + BusClickWordCaptchaModel( + {this.imgStr = "", + this.jigsawImageBase64 = "", + this.token = "", + this.secretKey = "", + this.wordList = const [], + this.wordStr = ""}); + + //解析数据转换模型 + static BusClickWordCaptchaModel fromMap(Map map) { + BusClickWordCaptchaModel captchaModel = BusClickWordCaptchaModel(); + captchaModel.imgStr = map["originalImageBase64"] ?? ""; + captchaModel.jigsawImageBase64 = map["jigsawImageBase64"] ?? ""; + captchaModel.token = map["token"] ?? ""; + captchaModel.secretKey = map["secretKey"] ?? ""; + captchaModel.wordList = map["wordList"] ?? []; + + if (!CaptchaUtil.isListEmpty(captchaModel.wordList)) { + captchaModel.wordStr = captchaModel.wordList.join(","); + } + + return captchaModel; + } + + //将模型转换 + Map toJson() { + var map = new Map(); + map['imgStr'] = imgStr; + map['jigsawImageBase64'] = jigsawImageBase64; + map['token'] = token; + map['secretKey'] = token; + map['wordList'] = wordList; + map['wordStr'] = wordStr; + return map; + } + + @override + String toString() { + // TODO: implement toString + return JsonEncoder.withIndent(' ').convert(toJson()); + } +} diff --git a/lib/business_system/login/register_retrieve_password.dart b/lib/business_system/login/register_retrieve_password.dart new file mode 100644 index 00000000..3454beef --- /dev/null +++ b/lib/business_system/login/register_retrieve_password.dart @@ -0,0 +1,760 @@ +import 'dart:async'; + +import 'package:dio/dio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:sharesdk_plugin/sharesdk_interface.dart'; + +import '../../generated/l10n.dart'; +import '../../retrofit/business_api.dart'; +import '../../retrofit/data/base_data.dart'; +import '../../utils/flutter_utils.dart'; +import '../../utils/font_weight.dart'; +import '../../view_widget/border_text.dart'; +import '../../view_widget/my_appbar.dart'; +import '../../view_widget/round_button.dart'; +import '../../view_widget/settlement_tips_dialog.dart'; +import 'captcha/bus_block_puzzle_captcha.dart'; + +class RegisterRetrievePassword extends StatefulWidget { + final Map arguments; + + RegisterRetrievePassword({this.arguments}); + + @override + State createState() { + return _RegisterRetrievePassword(); + } +} + +class _RegisterRetrievePassword extends State { + TextEditingController phoneController = TextEditingController(); + TextEditingController codeController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + TextEditingController changePasswordController = TextEditingController(); + TextEditingController businessNameController = TextEditingController(); + final TapGestureRecognizer tapGestureRecognizer = TapGestureRecognizer(); + var checkStatus = false; + String titleName; + BusinessApiService businessService; + Color statusCodeTextColor = Color(0xFF353535); + var verifyStatus = 0; + var mobileStatus = 0; + var btnText = "获取验证码"; + var sendCodeStatus = 0; + Timer _timer; + int phoneState = 1; + String mobile; + String newMobile; + + @override + void initState() { + super.initState(); + titleName = widget?.arguments["titleName"] ?? ""; + } + + @override + void dispose() { + super.dispose(); + if (_timer != null && _timer.isActive) _timer.cancel(); + } + + ///发送验证码 + sendVerifyCode(v) async { + BusinessApiService businessService = + BusinessApiService(Dio(), context: context); + BaseData baseData = await businessService.busSendVerify({ + "areaCode": "+86", + "mobile": phoneController.text, + "verification": v + }).catchError((onError) { + SmartDialog.showToast(AppUtils.dioErrorTypeToString(onError.type), + alignment: Alignment.center); + }); + if (baseData != null && baseData.isSuccess) { + sendCodeStatus = 1; + countdown(); + SmartDialog.showToast(baseData.data, alignment: Alignment.center); + } else { + btnText = S.of(context).send_code; + sendCodeStatus = 0; + SmartDialog.showToast("${baseData.msg}", alignment: Alignment.center); + refresh(); + } + } + + ///刷新页面 + void refresh() { + if (!mounted) return; + setState(() {}); + } + + ///发送验证码成功倒计时 + countdown() { + if (_timer != null && _timer.isActive) return; + int countdown = 60; + _timer = Timer.periodic(Duration(seconds: 1), (timer) { + countdown--; + if (countdown == 0) { + btnText = "重新发送"; + sendCodeStatus = 0; + _timer.cancel(); + } else { + btnText = "${countdown}s"; + } + if (!mounted) return; + setState(() {}); + }); + } + + ///注册接口 + register() async { + try { + if (codeController.text == "") { + SmartDialog.showToast("请输入验证码", alignment: Alignment.center); + return; + } + if (phoneController.text == "") { + SmartDialog.showToast(S.of(context).qingshurushoujihao, + alignment: Alignment.center); + return; + } + if (passwordController.text == "") { + SmartDialog.showToast("请输入密码", alignment: Alignment.center); + return; + } + if (businessNameController.text == "") { + SmartDialog.showToast("请输入商户名称", alignment: Alignment.center); + return; + } + if (!checkStatus) { + SmartDialog.showToast(S.of(context).gouxuanxieyi, + alignment: Alignment.center); + return; + } + + var param = { + "areaCode": "+86", + "mobile": phoneController.text, + "capcha": codeController.text, + "tenantName": businessNameController.text, + "password": passwordController.text, + }; + EasyLoading.show( + status: S.of(context).zhengzaijiazai, + maskType: EasyLoadingMaskType.black); + businessService = BusinessApiService(Dio(), context: context); + BaseData baseData = + await businessService.tenantAppLogin(param).catchError((error) { + print(error.message); + }); + if (baseData != null && baseData.isSuccess) { + SmartDialog.show( + clickBgDismissTemp: false, + widget: SettlementTips( + () {}, + text: baseData.data, + color: Color(0xFF30415B), + )); + Navigator.of(context).pop(); + } else { + if (baseData.msg != null) + SmartDialog.show( + clickBgDismissTemp: false, + widget: SettlementTips( + () {}, + text: baseData.msg, + color: Color(0xFF30415B), + )); + } + } finally { + EasyLoading.dismiss(); + } + } + + ///找回密码 + userChangePsd() async { + try { + if (phoneController.text == "") { + SmartDialog.showToast(S.of(context).qingshurushoujihao, + alignment: Alignment.center); + return; + } + if (codeController.text == "") { + SmartDialog.showToast("请输入验证码", alignment: Alignment.center); + return; + } + if (passwordController.text == "") { + SmartDialog.showToast("请输入密码", alignment: Alignment.center); + return; + } + if (changePasswordController.text == "") { + SmartDialog.showToast("请输入确认密码", alignment: Alignment.center); + return; + } + if (passwordController.text != changePasswordController.text) { + SmartDialog.showToast("两次密码不一致,请重新输入", alignment: Alignment.center); + return; + } + + var param = { + "areaCode": "+86", + "mobile": phoneController.text, + "capcha": codeController.text, + "newPassword": changePasswordController.text, + }; + EasyLoading.show( + status: S.of(context).zhengzaijiazai, + maskType: EasyLoadingMaskType.black); + businessService = BusinessApiService(Dio(), context: context); + BaseData baseData = + await businessService.tenantUserChangePsd(param).catchError((error) { + print(error.message); + }); + if (baseData != null && baseData.isSuccess) { + SmartDialog.show( + clickBgDismissTemp: false, + widget: SettlementTips( + () {}, + text: baseData.data, + color: Color(0xFF30415B), + )); + Navigator.of(context).pop(); + } else { + if (baseData.msg != null) + SmartDialog.show( + clickBgDismissTemp: false, + widget: SettlementTips( + () {}, + text: baseData.msg, + color: Color(0xFF30415B), + )); + } + } finally { + EasyLoading.dismiss(); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + resizeToAvoidBottomInset: false, + appBar: MyAppBar( + title: titleName, + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + brightness: Brightness.dark, + ), + body: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Column( + children: [ + registerAccount(), + GestureDetector( + onTap: () { + FocusScope.of(context).requestFocus(FocusNode()); + if (titleName == "注册账号") { + register(); + } else { + userChangePsd(); + } + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 15.h), + margin: + EdgeInsets.symmetric(horizontal: 16.w, vertical: 30.h), + alignment: Alignment.center, + width: double.infinity, + decoration: BoxDecoration( + color: Color(0xFF30415B), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + titleName == "注册账号" ? "注册" : "确定", + style: TextStyle( + fontSize: 16.sp, + color: Colors.white, + fontWeight: MyFontWeight.bold), + ), + ), + ), + if (titleName == "注册账号") + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Checkbox( + value: checkStatus, + onChanged: (a) { + setState(() { + checkStatus = !checkStatus; + }); + }, + checkColor: Color(0xFFFFFFFF), + fillColor: MaterialStateProperty.all(Color(0xFF30415B)), + ), + Expanded( + child: Text.rich( + TextSpan(children: [ + TextSpan( + text: S.of(context).privacy_policy1, + style: TextStyle( + fontSize: 11.sp, + color: Color(0xFF010101), + ), + ), + TextSpan( + text: "《一心回乡用户协议》", + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.of(context) + .pushNamed('/router/user_service_page'); + }, + style: TextStyle( + fontSize: 11.sp, + color: Color(0xFF010101), + ), + ), + TextSpan( + text: "、", + style: TextStyle( + fontSize: 11.sp, + color: Colors.black, + ), + ), + TextSpan( + text: S.of(context).privacy_policy3, + recognizer: tapGestureRecognizer, + style: TextStyle( + fontSize: 11.sp, + color: Color(0xFF010101), + ), + ), + TextSpan( + text: S.of(context).privacy_policy4, + style: TextStyle( + fontSize: 11.sp, + height: 1.2, + color: Color(0xFF010101), + ), + ), + ]), + )), + SizedBox( + width: 30, + ) + ], + ), + ], + )), + ); + } + + Widget registerAccount() { + return Container( + padding: + EdgeInsets.only(top: 21.h, bottom: 16.h, left: 15.w, right: 18.w), + margin: EdgeInsets.only(left: 16.w, right: 16.w, top: 16.h), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(12), + offset: Offset(0, 3), + blurRadius: 14, + spreadRadius: 0, + ) + ], + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + ///手机号 + Row( + children: [ + Text( + "手机号码", + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + ), + Expanded( + child: TextField( + controller: phoneController, + decoration: InputDecoration( + hintText: "请输入手机号码", + hintStyle: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + border: InputBorder.none, + contentPadding: EdgeInsets.only(left: 23.w), + ), + inputFormatters: [LengthLimitingTextInputFormatter(11)], + keyboardType: TextInputType.phone, + style: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + ), + ], + ), + Container( + height: 1.h, + width: double.infinity, + color: Color(0xFFEBECEF), + margin: EdgeInsets.only(bottom: 16.h), + ), + + ///验证码 + Row( + children: [ + Text( + "验证码", + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + ), + Expanded( + flex: 2, + child: TextField( + controller: codeController, + decoration: InputDecoration( + hintText: "请输入验证码", + hintStyle: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + border: InputBorder.none, + contentPadding: EdgeInsets.only(left: 23.w), + ), + keyboardType: TextInputType.phone, + style: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + ), + Expanded( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + mobile = phoneController.text; + if (mobile == "") { + SmartDialog.showToast(S.of(context).qingshurushoujihao, + alignment: Alignment.center); + return; + } + loadingBlockPuzzle(context); + }, + child: Text( + btnText, + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF30415B), + fontWeight: MyFontWeight.regular), + ), + )), + ], + ), + Container( + height: 1.h, + width: double.infinity, + color: Color(0xFFEBECEF), + margin: EdgeInsets.only(bottom: 16.h), + ), + + ///密码 + Row( + children: [ + Text( + "密码", + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + ), + Expanded( + child: TextField( + controller: passwordController, + decoration: InputDecoration( + hintText: "请输入密码", + hintStyle: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + border: InputBorder.none, + contentPadding: EdgeInsets.only(left: 23.w), + ), + keyboardType: TextInputType.phone, + style: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + ), + ], + ), + Container( + height: 1.h, + width: double.infinity, + color: Color(0xFFEBECEF), + margin: EdgeInsets.only(bottom: 16.h), + ), + + ///商户名称/确认密码 + titleName == "注册账号" + ? Row( + children: [ + Text( + "商户名称", + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + ), + Expanded( + child: TextField( + controller: businessNameController, + decoration: InputDecoration( + hintText: "请输入商户名称", + hintStyle: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + border: InputBorder.none, + contentPadding: EdgeInsets.only(left: 23.w), + ), + keyboardType: TextInputType.phone, + style: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + ), + ], + ) + : Row( + children: [ + Text( + "确认密码", + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + ), + Expanded( + child: TextField( + controller: changePasswordController, + decoration: InputDecoration( + hintText: "请再次输入密码", + hintStyle: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + border: InputBorder.none, + contentPadding: EdgeInsets.only(left: 23.w), + ), + keyboardType: TextInputType.phone, + style: TextStyle( + color: Color(0xFF808080), + fontSize: 14.sp, + fontWeight: MyFontWeight.regular), + ), + ), + ], + ) + ], + )); + } + + showAlertDialog() { + //显示对话框 + showDialog( + context: context, + builder: (BuildContext context) { + return WillPopScope( + onWillPop: () async => false, + child: SimpleDialog( + titlePadding: EdgeInsets.all(10), + backgroundColor: Colors.transparent, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + children: [ + Stack( + alignment: Alignment.bottomCenter, + children: [ + Container( + alignment: Alignment.center, + width: double.infinity, + height: 325.h, + padding: EdgeInsets.only(left: 16.w, right: 16.w), + decoration: new BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 24.h, bottom: 10.h), + child: Text( + S.of(context).xieyitanchuang, + style: TextStyle( + color: Color(0xff4D4D4D), + fontSize: 18.sp, + fontWeight: FontWeight.bold, + ), + ), + ), + Text.rich( + TextSpan(children: [ + TextSpan( + text: S.of(context).yinsizhengce1, + style: TextStyle( + fontWeight: MyFontWeight.medium, + fontSize: 14.sp, + height: 1.3.h, + color: Color(0xff727272), + ), + ), + TextSpan( + text: S.of(context).yinsixieyi, + style: TextStyle( + fontWeight: MyFontWeight.medium, + fontSize: 14.sp, + color: Color(0xff32A060)), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.of(context) + .popAndPushNamed('/router/treaty_page'); + }, + ), + ]), + ), + SizedBox( + height: 10.h, + ), + Text( + S.of(context).yinsizhengce2, + style: TextStyle( + color: Color(0xff727272), + fontSize: 14.sp, + height: 1.3.h, + fontWeight: MyFontWeight.medium, + ), + ), + SizedBox( + height: 16.h, + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + Navigator.of(context).pop(); + // exit(0); + }, + child: Container( + height: 40.h, + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(bottom: 20.h), + child: BorderText( + padding: EdgeInsets.only( + top: 10.h, + bottom: 10.h, + left: 36.w, + right: 36.w, + ), + text: S.of(context).jujue, + fontSize: 12.sp, + textColor: Color(0xFF32A060), + borderColor: Color(0xFF32A060), + borderWidth: 1.w, + radius: 23, + ), + ), + ), + SizedBox( + width: 21.w, + ), + Container( + height: 40.h, + margin: EdgeInsets.only(bottom: 20.h), + alignment: Alignment.bottomCenter, + child: RoundButton( + text: S.of(context).tongyibingjixu, + textColor: Colors.white, + fontSize: 12.sp, + callback: () { + SharedPreferences.getInstance().then((value) { + value.setBool("isShowPrivacyPolicy", true); + }); + SharesdkPlugin.uploadPrivacyPermissionStatus( + 1, + (success) => { + Navigator.of(context).pop(), + }, + ); + }, + padding: EdgeInsets.only( + top: 10.h, + bottom: 10.h, + left: 21.5.w, + right: 21.5.w, + ), + backgroup: Color(0xff32A060), + radius: 23, + ), + ), + SizedBox( + height: 20.h, + ), + ], + ), + ], + ) + ], + ), + ); + }, + ); + } + + //滑动拼图 + loadingBlockPuzzle(BuildContext context, {barrierDismissible = true}) { + showDialog( + context: context, + barrierDismissible: barrierDismissible, + builder: (BuildContext context) { + return BusBlockPuzzleCaptchaPage( + onSuccess: (v) { + sendVerifyCode(v); + }, + onFail: () { + print("onFail"); + }, + ); + }, + ); + } +} diff --git a/lib/business_system/mine/service_subscription/function_version_detail.dart b/lib/business_system/mine/service_subscription/function_version_detail.dart new file mode 100644 index 00000000..1a0dfb69 --- /dev/null +++ b/lib/business_system/mine/service_subscription/function_version_detail.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:huixiang/view_widget/my_appbar.dart'; + +class FunctionVersionDetail extends StatefulWidget { + final Map arguments; + + FunctionVersionDetail({this.arguments}); + + @override + State createState() { + return _FunctionVersionDetail(); + } +} + +class _FunctionVersionDetail extends State { + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: MyAppBar( + title: "功能版本介绍", + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + brightness: Brightness.dark, + ), + body:Container( + width: double.infinity, + height: double.infinity, + child:Image.asset( + "assets/image/activity_q.webp", + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + ), + ), + ); + } +} diff --git a/lib/business_system/mine/service_subscription/service_purchase_record.dart b/lib/business_system/mine/service_subscription/service_purchase_record.dart new file mode 100644 index 00000000..3cf30a2b --- /dev/null +++ b/lib/business_system/mine/service_subscription/service_purchase_record.dart @@ -0,0 +1,459 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:huixiang/view_widget/classic_header.dart'; +import 'package:huixiang/view_widget/my_footer.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:shimmer/shimmer.dart'; + +import '../../../generated/l10n.dart'; +import '../../../retrofit/business_api.dart'; +import '../../../retrofit/data/base_data.dart'; +import '../../../retrofit/data/service_bug_list.dart'; +import '../../../utils/business_instance.dart'; +import '../../../utils/flutter_utils.dart'; +import '../../../utils/font_weight.dart'; +import '../../../view_widget/my_appbar.dart'; +import '../../../view_widget/no_data_view.dart'; + +class ServicePurchaseRecord extends StatefulWidget { + final Map arguments; + + ServicePurchaseRecord({this.arguments}); + + @override + State createState() { + return _ServicePurchaseRecord(); + } +} + +class _ServicePurchaseRecord extends State { + final RefreshController refreshController = RefreshController(); + BusinessApiService businessService; + int _current = 1; + String networkError = ""; + int networkStatus = 0; + List records = []; + + ///离开页面记着销毁和清除 + @override + void dispose() { + super.dispose(); + refreshController.dispose(); + } + + @override + void initState() { + super.initState(); + _onRefresh(); + } + + _onRefresh({bool isShowLoad = true}) async { + if (isShowLoad) + EasyLoading.show( + status: S.current.zhengzaijiazai, + maskType: EasyLoadingMaskType.black); + await queryPackageBuyList(); + EasyLoading.dismiss(); + if (!mounted) return; + if (refreshController.isRefresh) refreshController.refreshCompleted(); + setState(() {}); + } + + ///服务购买记录 + queryPackageBuyList() async { + try { + if (businessService == null) { + businessService = BusinessApiService(Dio(), + context: context, + token: BusinessInstance.instance.businessToken, + tenant: BusinessInstance.instance.businessTenant, + storeId: widget.arguments["storeId"]); + } + BaseData baseData = await businessService.packageBuyList({ + "current": _current, + "map": {}, + "model": {"tenantCode": BusinessInstance.instance.businessTenant}, + "order": "descending", + "size": 10, + "sort": "createTime" + }).catchError((error) { + networkError = AppUtils.dioErrorTypeToString(error.type); + networkStatus = -1; + setState(() {}); + refreshController.refreshFailed(); + refreshController.loadFailed(); + }); + if (!mounted) return; + if (baseData != null && baseData.isSuccess) { + records.addAll(baseData?.data?.records ?? []); + if ((baseData?.data?.records ?? []).isEmpty || + records.length.toString() == baseData.data.total) + refreshController.loadNoData(); + else + refreshController.loadComplete(); + networkStatus = 1; + } + } finally { + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: MyAppBar( + title: "购买记录", + titleColor: Colors.black, + background: Colors.white, + leadingColor: Colors.black, + ), + body: SmartRefresher( + controller: refreshController, + enablePullDown: true, + enablePullUp: records.length == 0 ? false : true, + header: MyHeader(color: Color(0xFF30415B)), + physics: BouncingScrollPhysics(), + footer: CustomFooter( + builder: (context, mode) { + return MyFooter(mode); + }, + ), + onRefresh: () { + _current = 1; + records.clear(); + _onRefresh(isShowLoad: false); + }, + onLoading: () { + _current++; + _onRefresh(isShowLoad: false); + }, + child: networkStatus == -1 + ? noNetwork() + : ((networkStatus == 0) + ? Container( + margin: EdgeInsets.only(top: 12.h), + child: ListView.builder( + padding: EdgeInsets.zero, + itemCount: 10, + scrollDirection: Axis.vertical, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, position) { + return purchaseRecordItemSm(); + }, + )) + : ((records == null || records.length == 0) + ? NoDataView( + src: "assets/image/bs_no data_logo.webp", + isShowBtn: false, + text: "暂无购买记录", + fontSize: 16.sp, + iconHeight: 120.h, + margin: EdgeInsets.all(50.h), + ) + : Container( + margin: EdgeInsets.only(top: 12.h), + child: ListView.builder( + itemCount: records?.length ?? 0, + physics: BouncingScrollPhysics(), + shrinkWrap: true, + itemBuilder: (context, position) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () {}, + child: purchaseRecordItem(records[position]), + ); + }, + ), + )))), + ); + } + + Widget purchaseRecordItem(Records records) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + margin: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 12.h), + padding: EdgeInsets.only( + left: 12.h, + top: 12.h, + bottom: 12.h, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + records?.packageName ?? "", + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF0D0D0D), + fontWeight: MyFontWeight.bold), + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0xFFF4F6F7), + margin: EdgeInsets.symmetric(vertical: 13.h), + ), + + ///服务内容暂未定义,暂时隐藏 + // Padding( + // padding: EdgeInsets.only(bottom: 12.h), + // child: Text( + // "套餐内容: 会员管理", + // style: TextStyle( + // fontSize: 12.sp, + // color: Color(0xFF1A1A1A), + // fontWeight: MyFontWeight.regular), + // ), + // ), + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Text( + "套餐年限: ${records?.packageNum ?? "0"}年", + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + )), + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Text( + "套餐金额: ${records?.packagePrice ?? "0"}元", + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + )), + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Text( + "购买时间: ${records?.createTime ?? ""}", + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + )), + Text( + "支付方式: ${records?.payChannel == 1 ? "微信支付" :"支付宝支付"}", + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF1A1A1A), + fontWeight: MyFontWeight.regular), + ) + ], + ), + ); + } + + Widget purchaseRecordItemSm() { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + margin: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 12.h), + padding: EdgeInsets.only( + left: 12.h, + top: 16.h, + bottom: 16.h, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 70.w, + height: 20.h, + ), + ), + Container( + width: double.infinity, + height: 1.h, + color: Color(0xFFF4F6F7), + margin: EdgeInsets.symmetric(vertical: 13.h), + ), + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Row( + children: [ + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 52.w, + height: 18.h, + ), + ), + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + margin: EdgeInsets.only(left: 15.w), + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 48.w, + height: 18.h, + ), + ), + ], + )), + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Row( + children: [ + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 52.w, + height: 18.h, + ), + ), + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + margin: EdgeInsets.only(left: 15.w), + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 30.w, + height: 18.h, + ), + ), + ], + )), + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Row( + children: [ + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 52.w, + height: 18.h, + ), + ), + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + margin: EdgeInsets.only(left: 15.w), + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 123.w, + height: 18.h, + ), + ), + ], + )), + Row( + children: [ + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 52.w, + height: 18.h, + ), + ), + Shimmer.fromColors( + baseColor: Color(0XFFD8D8D8), + highlightColor: Color(0XFFD8D8D8), + child: Container( + margin: EdgeInsets.only(left: 15.w), + decoration: BoxDecoration( + color: Color(0XFFD8D8D8), + borderRadius: BorderRadius.circular(2), + ), + width: 48.w, + height: 18.h, + ), + ), + ], + ) + ], + )); + } + + Widget noNetwork() { + return Container( + margin: EdgeInsets.only(top: 120.h), + 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), + )), + ) + ], + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 2073baa6..4e634d07 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -93,6 +93,7 @@ import 'business_system/date_select/week_report_page.dart'; import 'business_system/goods/add_goods/add_goods_page.dart'; import 'business_system/goods/add_goods/edit_specs_detail.dart'; import 'business_system/goods/add_goods/set_goods_specs.dart'; +import 'business_system/goods/add_goods/set_goods_specs_value.dart'; import 'business_system/goods/add_goods/set_meal.dart'; import 'business_system/goods/goods_search_page.dart'; import 'business_system/goods/on_sale/add_assort.dart'; @@ -113,11 +114,14 @@ import 'business_system/home/vip/member_details_page.dart'; import 'business_system/home/vip/pay_success_page.dart'; import 'business_system/home/vip/vip_recharge_page.dart'; import 'business_system/login/business_login_page.dart'; +import 'business_system/login/register_retrieve_password.dart'; import 'business_system/mine/account_information.dart'; import 'business_system/mine/clerk_manage/add_new_clerk_page.dart'; import 'business_system/mine/clerk_manage/clerk_manage_page.dart'; import 'business_system/mine/merchant_info.dart'; import 'business_system/mine/security_setting.dart'; +import 'business_system/mine/service_subscription/function_version_detail.dart'; +import 'business_system/mine/service_subscription/service_purchase_record.dart'; import 'business_system/mine/service_subscription/service_subscription_page.dart'; import 'business_system/mine/shop_image_info.dart'; import 'business_system/mine/shop_reservation_code.dart'; @@ -566,4 +570,12 @@ Map routers = { EditSpecsDetail(arguments:arguments), '/router/set_meal': (context, {arguments}) => SetMeal(arguments:arguments), + '/router/function_version_detail': (context, {arguments}) => + FunctionVersionDetail(arguments:arguments), + '/router/register_retrieve_password': (context, {arguments}) => + RegisterRetrievePassword(arguments:arguments), + '/router/service_purchase_record': (context, {arguments}) => + ServicePurchaseRecord(arguments:arguments), + '/router/set_goods_specs_value': (context, {arguments}) => + SetGoodsSpecsValue(arguments:arguments), }; diff --git a/lib/retrofit/data/edit_specs_detail_list.dart b/lib/retrofit/data/edit_specs_detail_list.dart new file mode 100644 index 00000000..b061b1cb --- /dev/null +++ b/lib/retrofit/data/edit_specs_detail_list.dart @@ -0,0 +1,32 @@ +import 'package:flutter/cupertino.dart'; + +class EditSpecsDetailList { + String _specsDetailName; + TextEditingController _goodPriceController; + TextEditingController _originalPriceController; + TextEditingController _packagingFeeController; + TextEditingController _specsWeightController; + TextEditingController _skuStockController; + + TextEditingController get goodPriceController => _goodPriceController; + TextEditingController get originalPriceController => _originalPriceController; + TextEditingController get packagingFeeController => _packagingFeeController; + TextEditingController get specsWeightController => _specsWeightController; + TextEditingController get skuStockController => _skuStockController; + + + String get specsDetailName => _specsDetailName; + + set specsDetailName(String value) { + _specsDetailName = value; + } + + EditSpecsDetailList(String specsDetailName){ + _specsDetailName = specsDetailName; + _goodPriceController = TextEditingController(); + _originalPriceController = TextEditingController(); + _packagingFeeController = TextEditingController(); + _specsWeightController = TextEditingController(); + _skuStockController = TextEditingController(); + } +} \ No newline at end of file diff --git a/lib/retrofit/data/service_bug_list.dart b/lib/retrofit/data/service_bug_list.dart new file mode 100644 index 00000000..5b59a119 --- /dev/null +++ b/lib/retrofit/data/service_bug_list.dart @@ -0,0 +1,313 @@ +/// records : [{"id":"1745006589485514752","createTime":"2024-01-10 16:56:06","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:48","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1743090505270427648","oldPackageId":"1742842291845857280","packagePrice":"0.01","packageNum":1,"packageDiscount":100,"expirationTime":"2025-01-10 16:56:06","upgradeTime":null,"status":0,"payChannel":1,"isDelete":0,"packageName":"品牌商户"},{"id":"1745002175626477568","createTime":"2024-01-10 16:38:34","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:47","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1742842291845857280","oldPackageId":null,"packagePrice":"200.00","packageNum":10,"packageDiscount":100,"expirationTime":"2049-09-11 15:39:12","upgradeTime":null,"status":0,"payChannel":1,"isDelete":0,"packageName":"普通商户"},{"id":"1744984806560628736","createTime":"2024-01-10 15:29:33","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:46","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1743090505270427648","oldPackageId":null,"packagePrice":"0.01","packageNum":2,"packageDiscount":100,"expirationTime":"2030-01-10 14:23:37","upgradeTime":null,"status":1,"payChannel":1,"isDelete":0,"packageName":"品牌商户"},{"id":"1744983525037178880","createTime":"2024-01-10 15:24:27","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:46","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1743090505270427648","oldPackageId":null,"packagePrice":"0.01","packageNum":3,"packageDiscount":100,"expirationTime":"2028-01-10 14:23:37","upgradeTime":null,"status":1,"payChannel":1,"isDelete":0,"packageName":"品牌商户"},{"id":"1744968216842600448","createTime":"2024-01-10 14:23:37","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:45","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1743090505270427648","oldPackageId":"1742842291845857280","packagePrice":"0.01","packageNum":1,"packageDiscount":100,"expirationTime":"2025-01-10 14:23:37","upgradeTime":null,"status":1,"payChannel":1,"isDelete":0,"packageName":"品牌商户"},{"id":"1744965441966571520","createTime":"2024-01-10 14:12:36","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:44","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1742842291845857280","oldPackageId":null,"packagePrice":"0.01","packageNum":10,"packageDiscount":100,"expirationTime":"2030-01-10 18:00:00","upgradeTime":"2024-01-10 16:56:05","status":3,"payChannel":1,"isDelete":0,"packageName":"普通商户"},{"id":"1744965184633438208","createTime":"2024-01-10 14:11:35","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:44","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1742842291845857280","oldPackageId":null,"packagePrice":"0.01","packageNum":5,"packageDiscount":100,"expirationTime":"2027-01-10 18:00:00","upgradeTime":"2024-01-10 16:38:57","status":3,"payChannel":1,"isDelete":0,"packageName":"普通商户"},{"id":"1744965083273887744","createTime":"2024-01-10 14:11:10","createUser":"1739884285034233856","updateTime":"2024-01-11 07:51:43","updateUser":"1739884285034233856","tenantId":"1739884282001752064","tenantCode":"1197","packageId":"1742842291845857280","oldPackageId":null,"packagePrice":"0.01","packageNum":1,"packageDiscount":100,"expirationTime":"2025-01-10 18:00:00","upgradeTime":"2024-05-10 18:00:00","status":3,"payChannel":1,"isDelete":0,"packageName":"普通商户"}] +/// total : "8" +/// size : "10" +/// current : "1" +/// orders : [{"column":"create_time","asc":false}] +/// hitCount : false +/// searchCount : true +/// pages : "1" + +class ServiceBugList { + ServiceBugList({ + List records, + String total, + String size, + String current, + List orders, + bool hitCount, + bool searchCount, + String pages,}){ + _records = records; + _total = total; + _size = size; + _current = current; + _orders = orders; + _hitCount = hitCount; + _searchCount = searchCount; + _pages = pages; +} + + ServiceBugList.fromJson(dynamic json) { + if (json['records'] != null) { + _records = []; + json['records'].forEach((v) { + _records.add(Records.fromJson(v)); + }); + } + _total = json['total']; + _size = json['size']; + _current = json['current']; + if (json['orders'] != null) { + _orders = []; + json['orders'].forEach((v) { + _orders.add(Orders.fromJson(v)); + }); + } + _hitCount = json['hitCount']; + _searchCount = json['searchCount']; + _pages = json['pages']; + } + List _records; + String _total; + String _size; + String _current; + List _orders; + bool _hitCount; + bool _searchCount; + String _pages; +ServiceBugList copyWith({ List records, + String total, + String size, + String current, + List orders, + bool hitCount, + bool searchCount, + String pages, +}) => ServiceBugList( records: records ?? _records, + total: total ?? _total, + size: size ?? _size, + current: current ?? _current, + orders: orders ?? _orders, + hitCount: hitCount ?? _hitCount, + searchCount: searchCount ?? _searchCount, + pages: pages ?? _pages, +); + List get records => _records; + String get total => _total; + String get size => _size; + String get current => _current; + List get orders => _orders; + bool get hitCount => _hitCount; + bool get searchCount => _searchCount; + String get pages => _pages; + + Map toJson() { + final map = {}; + if (_records != null) { + map['records'] = _records.map((v) => v.toJson()).toList(); + } + map['total'] = _total; + map['size'] = _size; + map['current'] = _current; + if (_orders != null) { + map['orders'] = _orders.map((v) => v.toJson()).toList(); + } + map['hitCount'] = _hitCount; + map['searchCount'] = _searchCount; + map['pages'] = _pages; + return map; + } + +} + +/// column : "create_time" +/// asc : false + +class Orders { + Orders({ + String column, + bool asc,}){ + _column = column; + _asc = asc; +} + + Orders.fromJson(dynamic json) { + _column = json['column']; + _asc = json['asc']; + } + String _column; + bool _asc; +Orders copyWith({ String column, + bool asc, +}) => Orders( column: column ?? _column, + asc: asc ?? _asc, +); + String get column => _column; + bool get asc => _asc; + + Map toJson() { + final map = {}; + map['column'] = _column; + map['asc'] = _asc; + return map; + } + +} + +/// id : "1745006589485514752" +/// createTime : "2024-01-10 16:56:06" +/// createUser : "1739884285034233856" +/// updateTime : "2024-01-11 07:51:48" +/// updateUser : "1739884285034233856" +/// tenantId : "1739884282001752064" +/// tenantCode : "1197" +/// packageId : "1743090505270427648" +/// oldPackageId : "1742842291845857280" +/// packagePrice : "0.01" +/// packageNum : 1 +/// packageDiscount : 100 +/// expirationTime : "2025-01-10 16:56:06" +/// upgradeTime : null +/// status : 0 +/// payChannel : 1 +/// isDelete : 0 +/// packageName : "品牌商户" + +class Records { + Records({ + String id, + String createTime, + String createUser, + String updateTime, + String updateUser, + String tenantId, + String tenantCode, + String packageId, + String oldPackageId, + String packagePrice, + num packageNum, + num packageDiscount, + String expirationTime, + dynamic upgradeTime, + num status, + num payChannel, + num isDelete, + String packageName,}){ + _id = id; + _createTime = createTime; + _createUser = createUser; + _updateTime = updateTime; + _updateUser = updateUser; + _tenantId = tenantId; + _tenantCode = tenantCode; + _packageId = packageId; + _oldPackageId = oldPackageId; + _packagePrice = packagePrice; + _packageNum = packageNum; + _packageDiscount = packageDiscount; + _expirationTime = expirationTime; + _upgradeTime = upgradeTime; + _status = status; + _payChannel = payChannel; + _isDelete = isDelete; + _packageName = packageName; +} + + Records.fromJson(dynamic json) { + _id = json['id']; + _createTime = json['createTime']; + _createUser = json['createUser']; + _updateTime = json['updateTime']; + _updateUser = json['updateUser']; + _tenantId = json['tenantId']; + _tenantCode = json['tenantCode']; + _packageId = json['packageId']; + _oldPackageId = json['oldPackageId']; + _packagePrice = json['packagePrice']; + _packageNum = json['packageNum']; + _packageDiscount = json['packageDiscount']; + _expirationTime = json['expirationTime']; + _upgradeTime = json['upgradeTime']; + _status = json['status']; + _payChannel = json['payChannel']; + _isDelete = json['isDelete']; + _packageName = json['packageName']; + } + String _id; + String _createTime; + String _createUser; + String _updateTime; + String _updateUser; + String _tenantId; + String _tenantCode; + String _packageId; + String _oldPackageId; + String _packagePrice; + num _packageNum; + num _packageDiscount; + String _expirationTime; + dynamic _upgradeTime; + num _status; + num _payChannel; + num _isDelete; + String _packageName; +Records copyWith({ String id, + String createTime, + String createUser, + String updateTime, + String updateUser, + String tenantId, + String tenantCode, + String packageId, + String oldPackageId, + String packagePrice, + num packageNum, + num packageDiscount, + String expirationTime, + dynamic upgradeTime, + num status, + num payChannel, + num isDelete, + String packageName, +}) => Records( id: id ?? _id, + createTime: createTime ?? _createTime, + createUser: createUser ?? _createUser, + updateTime: updateTime ?? _updateTime, + updateUser: updateUser ?? _updateUser, + tenantId: tenantId ?? _tenantId, + tenantCode: tenantCode ?? _tenantCode, + packageId: packageId ?? _packageId, + oldPackageId: oldPackageId ?? _oldPackageId, + packagePrice: packagePrice ?? _packagePrice, + packageNum: packageNum ?? _packageNum, + packageDiscount: packageDiscount ?? _packageDiscount, + expirationTime: expirationTime ?? _expirationTime, + upgradeTime: upgradeTime ?? _upgradeTime, + status: status ?? _status, + payChannel: payChannel ?? _payChannel, + isDelete: isDelete ?? _isDelete, + packageName: packageName ?? _packageName, +); + String get id => _id; + String get createTime => _createTime; + String get createUser => _createUser; + String get updateTime => _updateTime; + String get updateUser => _updateUser; + String get tenantId => _tenantId; + String get tenantCode => _tenantCode; + String get packageId => _packageId; + String get oldPackageId => _oldPackageId; + String get packagePrice => _packagePrice; + num get packageNum => _packageNum; + num get packageDiscount => _packageDiscount; + String get expirationTime => _expirationTime; + dynamic get upgradeTime => _upgradeTime; + num get status => _status; + num get payChannel => _payChannel; + num get isDelete => _isDelete; + String get packageName => _packageName; + + Map toJson() { + final map = {}; + map['id'] = _id; + map['createTime'] = _createTime; + map['createUser'] = _createUser; + map['updateTime'] = _updateTime; + map['updateUser'] = _updateUser; + map['tenantId'] = _tenantId; + map['tenantCode'] = _tenantCode; + map['packageId'] = _packageId; + map['oldPackageId'] = _oldPackageId; + map['packagePrice'] = _packagePrice; + map['packageNum'] = _packageNum; + map['packageDiscount'] = _packageDiscount; + map['expirationTime'] = _expirationTime; + map['upgradeTime'] = _upgradeTime; + map['status'] = _status; + map['payChannel'] = _payChannel; + map['isDelete'] = _isDelete; + map['packageName'] = _packageName; + return map; + } + +} \ No newline at end of file diff --git a/lib/retrofit/data/set_specs_list.dart b/lib/retrofit/data/set_specs_list.dart new file mode 100644 index 00000000..5f28f98a --- /dev/null +++ b/lib/retrofit/data/set_specs_list.dart @@ -0,0 +1,19 @@ +import 'package:flutter/cupertino.dart'; + +class SetSpecsList { + TextEditingController _specsNameController; + List _specsValues = []; + + TextEditingController get specsNameController => _specsNameController; + + + List get specsValues => _specsValues; + + set specsValues(List value) { + _specsValues = value; + } + + SetSpecsList(){ + _specsNameController = TextEditingController(); + } +} \ No newline at end of file diff --git a/lib/retrofit/data/set_specs_meal_list.dart b/lib/retrofit/data/set_specs_meal_list.dart new file mode 100644 index 00000000..d025bbe3 --- /dev/null +++ b/lib/retrofit/data/set_specs_meal_list.dart @@ -0,0 +1,34 @@ +import 'package:flutter/cupertino.dart'; + +class SetSpecsMealList { + TextEditingController _groupsNameController; + List> _goodsMeal = []; + num _groupsTotal = 1; + num _optionalNum = 1; + + TextEditingController get groupsNameController => _groupsNameController; + + + List> get goodsMeal => _goodsMeal; + + set goodsMeal(List> value) { + _goodsMeal = value; + } + + + num get groupsTotal => _groupsTotal; + + set groupsTotal(num value) { + _groupsTotal = value; + } + + SetSpecsMealList(){ + _groupsNameController = TextEditingController(); + } + + num get optionalNum => _optionalNum; + + set optionalNum(num value) { + _optionalNum = value; + } +} \ No newline at end of file diff --git a/lib/retrofit/data/set_specs_value_list.dart b/lib/retrofit/data/set_specs_value_list.dart new file mode 100644 index 00000000..362ccefe --- /dev/null +++ b/lib/retrofit/data/set_specs_value_list.dart @@ -0,0 +1,10 @@ +import 'package:flutter/cupertino.dart'; + +class SetSpecsValueList { + TextEditingController _specsValueNameController; + + TextEditingController get specsValueNameController => _specsValueNameController; + SetSpecsValueList(){ + _specsValueNameController = TextEditingController(); + } +} \ No newline at end of file