You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

818 lines
28 KiB

import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../retrofit/business_api.dart';
import '../../../utils/font_weight.dart';
import '../../generated/l10n.dart';
import '../../retrofit/data/base_data.dart';
import '../../retrofit/data/business_goods.dart';
import '../../retrofit/data/store_time_info_list.dart';
import '../../utils/business_instance.dart';
import '../../utils/flutter_utils.dart';
import '../../view_widget/my_appbar.dart';
class ReservationPage extends StatefulWidget {
final Map<String, dynamic> arguments;
ReservationPage({this.arguments});
@override
State<StatefulWidget> createState() {
return _ReservationPage();
}
}
class _ReservationPage extends State<ReservationPage> {
final RefreshController _refreshController = RefreshController();
BusinessApiService businessService;
String networkError = "";
int networkStatus = 0;
final TextEditingController editingController = TextEditingController();
final TextEditingController daysAfterController = TextEditingController();
final TextEditingController daysWithinController = TextEditingController();
FocusNode _focusNode = FocusNode();
bool isKeyBoardShow = false;
bool _subscribeSwitch = false;
bool _paySubscribeSwitch = false;
StoreTimeInfoList storeTimeInfoList;
List<String> timeSlots = [];
SubscribeParam subscribeParam;
String selectTimeDate = "";
///离开页面记着销毁和清除
@override
void dispose() {
super.dispose();
_refreshController.dispose();
_focusNode.unfocus();
}
@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;
}
});
});
subscribeParam = widget.arguments["subscribeParam"];
queryReservationDetails(widget.arguments["shopId"]);
}
///预约时间详情
queryReservationDetails(shopId) async {
try {
if (subscribeParam != null)
EasyLoading.show(
status: S.current.zhengzaijiazai,
maskType: EasyLoadingMaskType.black);
if (businessService == null) {
businessService = BusinessApiService(Dio(),
context: context,
token: BusinessInstance.instance.businessToken,
tenant: BusinessInstance.instance.businessTenant,
storeId: widget.arguments["storeId"]);
}
BaseData<StoreTimeInfoList> baseData =
await businessService.storeOpenTime(shopId).catchError((error) {
networkStatus = -1;
networkError = AppUtils.dioErrorTypeToString(error.type);
});
if (baseData != null && baseData.isSuccess) {
storeTimeInfoList = baseData.data;
if (subscribeParam != null) {
timeSlots = subscribeParam.subscribeTimes;
_subscribeSwitch = subscribeParam.isEnableSubscribe;
_paySubscribeSwitch = subscribeParam.isEnableSubscribePay;
universalTypeSelect = subscribeParam.dayOrDate;
setState(() {});
}
networkStatus = 1;
}
} finally {
EasyLoading.dismiss();
}
}
///设置间隔的时间段list
List<String> getTimeSlots(String st, String et, int n) {
List<String> tempTimes = [];
try {
DateTime start = DateTime.parse(st);
DateTime end = DateTime.parse(et);
Duration interval = Duration(minutes: n);
while (start.isBefore(end)) {
DateTime current = start.add(interval);
if (current.isBefore(end)) {
String startTime = start.toString().substring(11, 16);
String endTime = current.toString().substring(11, 16);
tempTimes.add('$startTime-$endTime');
} else {
String startTime = start.toString().substring(11, 16);
String endTime = end.toString().substring(11, 16);
tempTimes.add('$startTime-$endTime');
}
start = current;
}
} catch (ex) {
EasyLoading.dismiss();
}
return tempTimes;
}
///预约信息保存
updateSubscribeInfo() async {
try {
EasyLoading.show(
status: S.current.zhengzaijiazai,
maskType: EasyLoadingMaskType.black);
if (businessService == null) {
businessService = BusinessApiService(Dio(),
context: context,
token: BusinessInstance.instance.businessToken,
tenant: BusinessInstance.instance.businessTenant,
storeId: widget.arguments["storeId"]);
}
BaseData baseData = await businessService.updateSubscribe({
"productId": widget.arguments["productId"],
"subscribe": {
"isEnableSubscribe": _subscribeSwitch,
"isEnableSubscribePay": _paySubscribeSwitch,
"timePeriod": editingController.text != ""
? editingController.text
: subscribeParam?.timePeriod ?? "",
"subscribeTimes": timeSlots,
"dayOrDate": (storeTimeInfoList?.posType ?? "") == "FAST_SERVICE"
? 0
: universalTypeSelect,
"startAfterDays": daysAfterController?.text ?? "",
"daysValidate": daysWithinController?.text ?? "",
"subscribeStartTime": selectTimeDate == ""
? ""
: selectTimeDate
.replaceAll("", "-")
.replaceAll("", "-")
.replaceAll("", "")
.substring(0, 19),
"subscribeEndTime": selectTimeDate == ""
? ""
: selectTimeDate
.replaceAll("", "-")
.replaceAll("", "-")
.replaceAll("", "")
.substring(23, 41),
"stores": []
}
}).catchError((error) {});
if (baseData != null && baseData.isSuccess) {
Navigator.of(context).pop(1);
SmartDialog.showToast("预约信息编辑成功", alignment: Alignment.center);
setState(() {});
} else {
SmartDialog.showToast(baseData.msg, alignment: Alignment.center);
}
} finally {
EasyLoading.dismiss();
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap:(){
FocusScope.of(context).requestFocus(FocusNode());},
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: MyAppBar(
title: "预约",
titleColor: Colors.black,
leadingColor: Colors.black,
background: Colors.white,
),
body: networkStatus == -1
? noNetwork()
: Container(
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (networkStatus == 1)
Row(
children: [
Text(
"预约开关",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF0D0D0D),
fontWeight: MyFontWeight.bold),
),
SizedBox(
width: 24.w,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
_subscribeSwitch = !_subscribeSwitch;
});
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: _subscribeSwitch
? Image.asset(
"assets/image/reservation_switch.webp",
width: 44.w,
height: 24.h,
fit: BoxFit.fill,
)
: Image.asset(
"assets/image/reservation_unswitch.webp",
width: 44.w,
height: 24.h,
fit: BoxFit.fill,
),
),
),
],
),
if (networkStatus == 1)
Expanded(
child:
(storeTimeInfoList?.posType ?? "") == "FAST_SERVICE"
? timeIntervalType()
: universalType()),
if (networkStatus == 1)
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
updateSubscribeInfo();
},
child: Container(
width: double.infinity,
alignment: Alignment.center,
margin: EdgeInsets.only(bottom: 55.h, top: 15.h),
padding: EdgeInsets.symmetric(vertical: 16.h),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(27),
color: Color(0xFF30415B)),
child: Text(
S.of(context).baocun,
style: TextStyle(
fontWeight: MyFontWeight.semi_bold,
fontSize: 16.sp,
color: Colors.white,
),
),
),
)
],
),
),
),
);
}
///时间间隔预约类型
Widget timeIntervalType() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: 1.h,
color: Color(0x14000000),
margin: EdgeInsets.symmetric(vertical: 24.h),
),
Row(
children: [
Text(
"付费预约开关",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF0D0D0D),
fontWeight: MyFontWeight.bold),
),
SizedBox(
width: 24.w,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
_paySubscribeSwitch = !_paySubscribeSwitch;
});
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: _paySubscribeSwitch
? Image.asset(
"assets/image/reservation_switch.webp",
width: 44.w,
height: 24.h,
fit: BoxFit.fill,
)
: Image.asset(
"assets/image/reservation_unswitch.webp",
width: 44.w,
height: 24.h,
fit: BoxFit.fill,
),
),
),
],
),
Container(
width: double.infinity,
height: 1.h,
color: Color(0x14000000),
margin: EdgeInsets.only(top: 24.h, bottom: 10.h),
),
Row(
children: [
Expanded(
child: Text(
"预约间隔时(分钟)",
style: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: TextField(
controller: editingController,
keyboardType: TextInputType.phone,
onChanged: (value) {
timeSlots = getTimeSlots(
"2023-11-14 ${storeTimeInfoList?.openStartTime ?? ""}",
"2023-11-14 ${storeTimeInfoList?.openEndTime ?? ""}",
int.tryParse(editingController.text) ?? 30);
},
decoration: InputDecoration(
hintText: subscribeParam != null
? (subscribeParam?.timePeriod ?? 0).toString()
: "分钟",
hintTextDirection: TextDirection.rtl,
hintStyle: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: MyFontWeight.semi_bold,
),
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 16.w),
),
textAlign: TextAlign.right,
style: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: MyFontWeight.semi_bold),
),
),
],
),
Padding(
padding: EdgeInsets.only(bottom: 16.h, top: 38.h),
child: Text(
"选择预约时间段",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF0D0D0D),
fontWeight: MyFontWeight.bold),
)),
Expanded(
child: GridView.builder(
itemCount: timeSlots.length,
shrinkWrap: true,
physics: BouncingScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//一行的Widget数量
crossAxisCount: 3,
//水平子Widget之间间距
crossAxisSpacing:10.w,
//垂直子Widget之间间距
mainAxisSpacing: 20.h,
//子Widget宽高比例
childAspectRatio: 3,
),
itemBuilder: (context, index) {
return reservationTimeList(index);
},
)),
],
);
}
///通用预约类型
Widget universalType() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: 34.h, bottom: 16.h),
child: Text(
"增加有效期",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF0D0D0D),
fontWeight: MyFontWeight.bold),
)),
Row(
children: [
Expanded(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
universalTypeSelect = 1;
});
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
checkView(1),
Text(
"任意时间",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFF1A1A1A),
fontWeight: MyFontWeight.regular),
)
],
))),
Expanded(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
universalTypeSelect = 3;
});
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
checkView(3),
Text(
"日期范围",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFF1A1A1A),
fontWeight: MyFontWeight.regular),
)
],
))),
Expanded(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
universalTypeSelect = 2;
});
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
checkView(2),
Text(
"可预定的期限",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFF1A1A1A),
fontWeight: MyFontWeight.regular),
)
],
))),
],
),
if ((universalTypeSelect != 0 && universalTypeSelect != 1))
Expanded(
child:
universalTypeSelect == 2 ? expectedDeadline() : dateRange()),
],
);
}
///可预订的期限UI
Widget expectedDeadline() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: 34.h, bottom: 16.h),
child: Text(
"预约多少天以后",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF0D0D0D),
fontWeight: MyFontWeight.bold),
)),
Container(
width: 164.w,
margin: EdgeInsets.only(bottom: 8.h),
padding: EdgeInsets.symmetric(vertical: 5.h),
decoration: BoxDecoration(
color: Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(4),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: TextField(
controller: daysAfterController,
keyboardType: TextInputType.phone,
onEditingComplete: () {
FocusScope.of(context).requestFocus(FocusNode());
},
decoration: InputDecoration(
border: InputBorder.none,
isCollapsed: true,
hintText: subscribeParam != null
? (subscribeParam?.startAfterDays ?? "").toString()
: "",
hintStyle: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: MyFontWeight.regular,
),
contentPadding: EdgeInsets.only(left: 16.w),
),
style: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: MyFontWeight.regular),
),
),
Padding(
padding: EdgeInsets.only(right: 13.w),
child: Text(
"",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF7B8CA7),
fontWeight: MyFontWeight.medium),
),
)
],
),
),
Text(
"*设定预定后整数天后才有效",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFFFA5151),
fontWeight: MyFontWeight.regular),
),
Padding(
padding: EdgeInsets.only(top: 25.h, bottom: 16.h),
child: Text(
"预约多少天以内",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF0D0D0D),
fontWeight: MyFontWeight.bold),
)),
Container(
width: 164.w,
margin: EdgeInsets.only(bottom: 8.h),
padding: EdgeInsets.symmetric(vertical: 5.h),
decoration: BoxDecoration(
color: Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(4),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: TextField(
controller: daysWithinController,
keyboardType: TextInputType.phone,
onEditingComplete: () {
FocusScope.of(context).requestFocus(FocusNode());
},
decoration: InputDecoration(
isCollapsed: true,
border: InputBorder.none,
hintText: subscribeParam != null
? (subscribeParam?.daysValidate ?? "").toString()
: "",
hintStyle: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: MyFontWeight.regular,
),
contentPadding: EdgeInsets.only(left: 16.w),
),
style: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: MyFontWeight.regular),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 13.w),
child: Text(
"",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF7B8CA7),
fontWeight: MyFontWeight.medium),
),
)
],
),
),
Text(
"*设定预定后整数天内有效",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFFFA5151),
fontWeight: MyFontWeight.regular),
)
],
);
}
///日期范围UI
Widget dateRange() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: 34.h, bottom: 16.h),
child: Text(
"日期范围",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF0D0D0D),
fontWeight: MyFontWeight.bold),
)),
timeSelect(),
],
);
}
///时间选择
Widget timeSelect() {
return Container(
color: Colors.white,
child: GestureDetector(
onTap: () {
Navigator.of(context).pushNamed('/router/custom_page',
arguments: {"beyondDateRange": "1"}).then((value) {
setState(() {
selectTimeDate = value;
});
});
},
child: Container(
decoration: BoxDecoration(
color: Color(0xFFF7F8FA),
borderRadius: BorderRadius.circular(2),
),
padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 12.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
(selectTimeDate == "" || selectTimeDate == null)
? (((subscribeParam?.subscribeEndTime ?? "") != "" &&
(subscribeParam?.subscribeStartTime ?? "") != "")
? "${subscribeParam?.subscribeStartTime ?? ""}${subscribeParam?.subscribeEndTime ?? ""}"
: "选择开始时间 至 结束时间")
: "${selectTimeDate.replaceAll("", "-").replaceAll("", "-").replaceAll("", "").substring(0, 19)} "
"${selectTimeDate.replaceAll("", "-").replaceAll("", "-").replaceAll("", "").substring(20, 41)}",
style: TextStyle(
fontSize: 14.sp,
color: Color(0xFF30415B),
fontWeight: MyFontWeight.regular),
),
],
),
),
),
);
}
var universalTypeSelect = 0;
Widget checkView(var index) {
return Container(
padding: EdgeInsets.only(
right: 6.w,
),
alignment: Alignment.center,
child: Image.asset(
universalTypeSelect != index
? "assets/image/bus_time_unSelect.webp"
: "assets/image/bus_time_select.webp",
width: 20.w,
height: 20.h,
),
);
}
Widget reservationTimeList(int index) {
return Container(
decoration: new BoxDecoration(
color: Color(0xFFEFF5FF),
borderRadius: BorderRadius.circular(2),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
timeSlots[index],
style: TextStyle(
fontWeight: MyFontWeight.medium,
fontSize: 14.sp,
color: Color(0xFF30415B),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
timeSlots.removeAt(index);
setState(() {});
},
child: Container(
padding: EdgeInsets.all(2),
child: Image.asset(
"assets/image/bus_close_circle.webp",
width: 16.h,
height: 16.h,
fit: BoxFit.fill,
),
),
),
],
),
);
}
Widget noNetwork() {
return Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.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: () {
queryReservationDetails(widget.arguments["shopId"]);
},
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),
)),
)
],
),
);
}
}