Browse Source
新增商家端滑动图片验证文件; 新增编辑规格明细页面,且数据交互已完成; 新增编辑规格明细实体类; 新增服务套餐功能本介绍;(ui设计为仅显示一张图片,接口未新增该字段;待开发,接入数据字段即可;) 新增服务套餐购买记录实体类; 新增服务套餐购买记录页面;(该页面已完成初步ui设计,接口数据已对接,服务内容暂未定义,暂时隐藏) 新增设置商品规格页面;(已完成数据的交互流程) 新增设置商品规格值页面;已完成数据的交互流程) 新增设置套餐选择页面;(已完成新增商品跳转,选择商品数据显示的交互流程) 新增设置规格列表实体类; 新增设置规格套餐列表实体类; 新增设置规格值列表实体类;wr_2023_new_business
wurong
1 year ago
22 changed files with 5439 additions and 0 deletions
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 968 B |
After Width: | Height: | Size: 888 B |
File diff suppressed because it is too large
Load Diff
@ -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<String, dynamic> arguments; |
||||||
|
|
||||||
|
EditSpecsDetail({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _EditSpecsDetail(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _EditSpecsDetail extends State<EditSpecsDetail> { |
||||||
|
List<EditSpecsDetailList> 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<String> skus = widget?.arguments["skus"] ?? []; |
||||||
|
List<Map<String, String>> 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<Map<String, String>> 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), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -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<String, dynamic> arguments; |
||||||
|
|
||||||
|
SetGoodsSpecs({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _SetGoodsSpecs(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _SetGoodsSpecs extends State<SetGoodsSpecs> { |
||||||
|
List<SetSpecsList> specs = []; |
||||||
|
List<Map<String, String>> 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<String> mergeArr(List<List<String>> 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<String> 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, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
)), |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -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<String, dynamic> arguments; |
||||||
|
|
||||||
|
SetGoodsSpecsValue({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _SetGoodsSpecsValue(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _SetGoodsSpecsValue extends State<SetGoodsSpecsValue> { |
||||||
|
List<SetSpecsValueList> 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<String> 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<String> 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), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -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<String, dynamic> arguments; |
||||||
|
|
||||||
|
SetMeal({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _SetMeal(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _SetMeal extends State<SetMeal> { |
||||||
|
List<SetSpecsMealList> 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, |
||||||
|
), |
||||||
|
), |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
File diff suppressed because one or more lines are too long
@ -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<BusClickWordCaptcha> { |
||||||
|
BusClickWordCaptchaState _busClickWordCaptchaState = BusClickWordCaptchaState.none; |
||||||
|
List<Offset> _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<Map<String, dynamic>> 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: <Widget>[ |
||||||
|
_topConttainer(), |
||||||
|
_captchaContainer(), |
||||||
|
_bottomContainer() |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
//图片验证码 |
||||||
|
_captchaContainer() { |
||||||
|
List<Widget> _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: <Widget>[ |
||||||
|
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<String, dynamic> 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<String, dynamic> toJson() { |
||||||
|
var map = new Map<String, dynamic>(); |
||||||
|
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()); |
||||||
|
} |
||||||
|
} |
@ -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<String, dynamic> arguments; |
||||||
|
|
||||||
|
RegisterRetrievePassword({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _RegisterRetrievePassword(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _RegisterRetrievePassword extends State<RegisterRetrievePassword> { |
||||||
|
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: <Widget>[ |
||||||
|
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<Null>( |
||||||
|
context: context, |
||||||
|
barrierDismissible: barrierDismissible, |
||||||
|
builder: (BuildContext context) { |
||||||
|
return BusBlockPuzzleCaptchaPage( |
||||||
|
onSuccess: (v) { |
||||||
|
sendVerifyCode(v); |
||||||
|
}, |
||||||
|
onFail: () { |
||||||
|
print("onFail"); |
||||||
|
}, |
||||||
|
); |
||||||
|
}, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
||||||
|
|
||||||
|
class FunctionVersionDetail extends StatefulWidget { |
||||||
|
final Map<String, dynamic> arguments; |
||||||
|
|
||||||
|
FunctionVersionDetail({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _FunctionVersionDetail(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _FunctionVersionDetail extends State<FunctionVersionDetail> { |
||||||
|
|
||||||
|
@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, |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -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<String, dynamic> arguments; |
||||||
|
|
||||||
|
ServicePurchaseRecord({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _ServicePurchaseRecord(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _ServicePurchaseRecord extends State<ServicePurchaseRecord> { |
||||||
|
final RefreshController refreshController = RefreshController(); |
||||||
|
BusinessApiService businessService; |
||||||
|
int _current = 1; |
||||||
|
String networkError = ""; |
||||||
|
int networkStatus = 0; |
||||||
|
List<Records> 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<ServiceBugList> 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), |
||||||
|
)), |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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> records, |
||||||
|
String total, |
||||||
|
String size, |
||||||
|
String current, |
||||||
|
List<Orders> 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> _records; |
||||||
|
String _total; |
||||||
|
String _size; |
||||||
|
String _current; |
||||||
|
List<Orders> _orders; |
||||||
|
bool _hitCount; |
||||||
|
bool _searchCount; |
||||||
|
String _pages; |
||||||
|
ServiceBugList copyWith({ List<Records> records, |
||||||
|
String total, |
||||||
|
String size, |
||||||
|
String current, |
||||||
|
List<Orders> 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<Records> get records => _records; |
||||||
|
String get total => _total; |
||||||
|
String get size => _size; |
||||||
|
String get current => _current; |
||||||
|
List<Orders> get orders => _orders; |
||||||
|
bool get hitCount => _hitCount; |
||||||
|
bool get searchCount => _searchCount; |
||||||
|
String get pages => _pages; |
||||||
|
|
||||||
|
Map<String, dynamic> toJson() { |
||||||
|
final map = <String, dynamic>{}; |
||||||
|
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<String, dynamic> toJson() { |
||||||
|
final map = <String, dynamic>{}; |
||||||
|
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<String, dynamic> toJson() { |
||||||
|
final map = <String, dynamic>{}; |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
|
||||||
|
class SetSpecsList { |
||||||
|
TextEditingController _specsNameController; |
||||||
|
List<String> _specsValues = []; |
||||||
|
|
||||||
|
TextEditingController get specsNameController => _specsNameController; |
||||||
|
|
||||||
|
|
||||||
|
List<String> get specsValues => _specsValues; |
||||||
|
|
||||||
|
set specsValues(List<String> value) { |
||||||
|
_specsValues = value; |
||||||
|
} |
||||||
|
|
||||||
|
SetSpecsList(){ |
||||||
|
_specsNameController = TextEditingController(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
|
||||||
|
class SetSpecsMealList { |
||||||
|
TextEditingController _groupsNameController; |
||||||
|
List<Map<String, String>> _goodsMeal = []; |
||||||
|
num _groupsTotal = 1; |
||||||
|
num _optionalNum = 1; |
||||||
|
|
||||||
|
TextEditingController get groupsNameController => _groupsNameController; |
||||||
|
|
||||||
|
|
||||||
|
List<Map<String, String>> get goodsMeal => _goodsMeal; |
||||||
|
|
||||||
|
set goodsMeal(List<Map<String, String>> 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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
|
||||||
|
class SetSpecsValueList { |
||||||
|
TextEditingController _specsValueNameController; |
||||||
|
|
||||||
|
TextEditingController get specsValueNameController => _specsValueNameController; |
||||||
|
SetSpecsValueList(){ |
||||||
|
_specsValueNameController = TextEditingController(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue