台桌列表预定页面

This commit is contained in:
GYJ
2024-11-26 17:58:17 +08:00
parent 2644163712
commit 2d890f81cd
3 changed files with 752 additions and 20 deletions

View File

@@ -1,36 +1,103 @@
import 'package:cashier_reserve/common/base/ui.dart';
import 'package:cashier_reserve/common/channel/call_log_model.dart';
import 'package:cashier_reserve/common/print/print.dart';
import 'package:cashier_reserve/home/reserve_view_model.dart';
import 'package:flutter/cupertino.dart';
class ReserveLeftContentView extends StatelessWidget {
final double contentWidth = 430;
final double inputItemHeight = 36;
final ReserveViewModel provider;
const ReserveLeftContentView({super.key, required this.provider});
final Animation<double> animationSizeFactor;
final AnimationController animationController;
const ReserveLeftContentView(
{super.key,
required this.provider,
required this.animationSizeFactor,
required this.animationController});
@override
Widget build(BuildContext context) {
return SizedBox(
width: contentWidth,
// height: MediaQuery.of(context).size.height,
child: Stack(
children: [
_buildCallLog(context),
_buildBookingWidget(context),
],
),
);
}
Widget _buildBookingWidget(BuildContext context) {
return SizeTransition(
sizeFactor: animationSizeFactor,
axis: Axis.vertical,
axisAlignment: -1, // 设置为 -1使动画从下往上开始
child: Container(
color: const Color(0xfff5f5f5),
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 5,
),
Container(
margin: const EdgeInsets.only(left: 15),
child: const Text(
'创建订单',
style: TextStyle(fontSize: 15, color: Color(0xff333333)),
),
),
const SizedBox(
height: 5,
),
_buildNumAndTable(context),
const SizedBox(
height: 10,
),
_buildBookingInfo(context),
const SizedBox(
height: 10,
),
_buildBookingActions(context),
],
),
),
));
}
Widget _buildCallLog(BuildContext context) {
return Column(
children: [
Expanded(
child: SizedBox(
width: 430,
child: ListView.builder(
itemCount: provider.callLogs?.length ?? 0,
itemBuilder: (context, index) {
return _buildCallRecordItem(context, provider.callLogs?[index]);
},
),
)),
width: contentWidth,
child: ListView.builder(
itemCount: provider.callLogs?.length ?? 0,
itemBuilder: (context, index) {
return _buildCallRecordItem(context, provider.callLogs?[index]);
},
),
)),
Container(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 15),
child: InkWell(
onTap: () {},
onTap: () {
animationController.forward();
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: const Color(0xff318AFE),
),
width: 300,
height: 36,
height: inputItemHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
@@ -77,7 +144,7 @@ class ReserveLeftContentView extends StatelessWidget {
Text(
model?.time ?? "",
style:
const TextStyle(color: Color(0xff999999), fontSize: 12),
const TextStyle(color: Color(0xff999999), fontSize: 12),
),
],
),
@@ -88,7 +155,7 @@ class ReserveLeftContentView extends StatelessWidget {
Text(
model?.name ?? "未知电话",
style:
const TextStyle(color: Color(0xff333333), fontSize: 14),
const TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(height: 5),
Row(
@@ -104,7 +171,7 @@ class ReserveLeftContentView extends StatelessWidget {
const Text(
"已消费0单",
style:
TextStyle(color: Color(0xff333333), fontSize: 14),
TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(
width: 15,
@@ -112,7 +179,7 @@ class ReserveLeftContentView extends StatelessWidget {
const Text(
"已撤0单",
style:
TextStyle(color: Color(0xff333333), fontSize: 14),
TextStyle(color: Color(0xff333333), fontSize: 14),
),
],
),
@@ -125,7 +192,7 @@ class ReserveLeftContentView extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border:
Border.all(color: const Color(0xff318AFE), width: 1),
Border.all(color: const Color(0xff318AFE), width: 1),
),
padding: const EdgeInsets.fromLTRB(20, 7, 20, 7),
child: const Text(
@@ -147,4 +214,586 @@ class ReserveLeftContentView extends StatelessWidget {
),
);
}
/// _buildNumAndTable 就餐人数和桌台
Widget _buildNumAndTable(BuildContext context) {
return Container(
color: Colors.white,
padding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
child: Column(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
height: inputItemHeight,
child: Row(
children: [
const Text(
"就餐人数",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextField(
controller: provider.bookingNumController,
decoration: InputDecoration(
hintText: "请输入就餐人数",
hintStyle: const TextStyle(
fontSize: 14,
color: Color(0xff999999),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(5),
),
),
keyboardType: TextInputType.number,
textAlign: TextAlign.right,
),
),
const SizedBox(
width: 10,
),
const Text(
"",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
],
),
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"请选择桌台",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
Text(provider.selectedTable?.name ?? "",
style:
const TextStyle(color: Color(0xff333333), fontSize: 14)),
],
),
const SizedBox(
height: 5,
),
],
),
);
}
/// _buildBookingInfo 预订信息
Widget _buildBookingInfo(BuildContext context) {
return Container(
color: Colors.white,
padding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
child: Column(
children: [
_buildBookingPhone(context),
const SizedBox(
height: 5,
),
_buildBookingName(context),
const SizedBox(
height: 5,
),
_buildBookingTimeAndType(context),
const SizedBox(
height: 5,
),
_buildBookingAttribute(context),
const SizedBox(
height: 5,
),
_buildBookingTableNum(context),
const SizedBox(
height: 5,
),
_buildBookingStandard(context),
const SizedBox(
height: 5,
),
_buildBookingRemark(context),
],
),
);
}
/// _buildBookingActions 预订操作
Widget _buildBookingActions(BuildContext context) {
return Container(
color: Colors.white,
padding: const EdgeInsets.fromLTRB(15, 5, 15, 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildBookingActionBtn(context, "预约", () {}),
_buildBookingActionBtn(context, "预约并短信", () {}),
_buildBookingActionBtn(context, "发路线", () {}),
_buildBookingActionBtn(context, "取消", () {
animationController.reverse();
}),
],
),
);
}
/// _buildBookingPhone 预订电话
Widget _buildBookingPhone(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
height: inputItemHeight,
child: Row(
children: [
const Text(
"电话",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextField(
controller: provider.bookingPhoneController,
decoration: InputDecoration(
hintText: "请输入电话",
hintStyle: const TextStyle(
fontSize: 14,
color: Color(0xff999999),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(5),
),
),
keyboardType: TextInputType.number,
textAlign: TextAlign.left,
),
),
const SizedBox(
width: 10,
),
],
),
);
}
/// _buildBookingName 预订人
Widget _buildBookingName(BuildContext context) {
return SizedBox(
width: contentWidth - 30,
child: Row(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
height: inputItemHeight,
width: contentWidth - 160,
child: Row(
children: [
const Text(
"姓名",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextField(
controller: provider.bookingNameController,
decoration: InputDecoration(
hintText: "请输入姓名",
hintStyle: const TextStyle(
fontSize: 14,
color: Color(0xff999999),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(5),
),
),
textAlign: TextAlign.left,
),
),
const SizedBox(
width: 10,
),
],
),
),
const SizedBox(
width: 10,
),
// 先生、女士
SizedBox(
width: 120,
child: CupertinoSegmentedControl(
//子标签
children: {
1: Container(
width: 60,
height: inputItemHeight,
alignment: Alignment.center,
child: const Text(
"先生",
style: TextStyle(
fontSize: 14,
// color: Color(0xff333333),
decoration: TextDecoration.none),
),
),
2: Container(
width: 60,
height: inputItemHeight,
alignment: Alignment.center,
child: const Text(
"女士",
style: TextStyle(
fontSize: 14,
// color: Color(0xff333333),
decoration: TextDecoration.none),
),
),
},
//当前选中的索引
groupValue: provider.bookingGender,
//点击回调
onValueChanged: (int index) {
provider.updateBookingGender(index);
},
selectedColor: Colors.blue,
borderColor: Colors.blue,
unselectedColor: Colors.white,
),
),
],
),
);
}
/// _buildBookingTimeAndType 预订时间和类型
Widget _buildBookingTimeAndType(BuildContext context) {
final itemWidth = (contentWidth - 40) / 2;
return Row(
children: [
Container(
width: itemWidth,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
height: inputItemHeight,
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text("时间",
style: TextStyle(color: Color(0xff666666), fontSize: 14)),
InkWell(
onTap: () async {
TimeOfDay? t = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
yjPrint(t);
provider.updateBookingTime(t?.hour ?? 0, t?.minute ?? 0);
},
child: (provider.bookingSelectedTime == "")
? const Text(
"请选择时间",
style:
TextStyle(color: Color(0xff999999), fontSize: 14),
)
: Text(
provider.bookingSelectedTime,
style: const TextStyle(
color: Color(0xff333333), fontSize: 14),
),
)
],
),
),
const SizedBox(
width: 10,
),
Container(
width: itemWidth,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
height: inputItemHeight,
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
child: Row(
children: [
const Text("类型",
style: TextStyle(color: Color(0xff666666), fontSize: 14)),
const SizedBox(
width: 10,
),
Expanded(
child: TextField(
controller: provider.bookingTypeController,
decoration: InputDecoration(
hintText: "请输入类型",
hintStyle: const TextStyle(
fontSize: 14,
color: Color(0xff999999),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(5),
),
),
textAlign: TextAlign.right,
),
),
const SizedBox(
width: 10,
),
],
),
),
],
);
}
/// _buildBookingAttribute 预订属性
Widget _buildBookingAttribute(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
height: inputItemHeight,
width: contentWidth - 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildBookingAttrItem(context, "重点关注", provider.bookingFocus,
(value) {
provider.updateBookingAttr("focus", value);
}),
_buildBookingAttrItem(context, "接收营销短信", provider.bookingSms,
(value) {
provider.updateBookingAttr("sms", value);
}),
],
),
);
}
Widget _buildBookingAttrItem(BuildContext context, String name, bool isOpen,
Function(bool) onChanged) {
return Row(
children: [
Text(name,
style: const TextStyle(color: Color(0xff999999), fontSize: 14)),
const SizedBox(width: 5),
Transform.scale(
scale: 0.8, // 调整这个值来改变大小大于1放大小于1缩小
child: CupertinoSwitch(
value: isOpen, onChanged: onChanged, activeColor: Colors.blue),
),
],
);
}
/// _buildBookingTableNum 预订桌台数量
Widget _buildBookingTableNum(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
height: inputItemHeight,
// width: contentWidth - 30,
child: Row(
children: [
const Text(
"摆台桌数(桌)",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextField(
controller: provider.bookingTableNumController,
decoration: InputDecoration(
hintText: "请输入台桌数",
hintStyle: const TextStyle(
fontSize: 14,
color: Color(0xff999999),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(5),
),
),
textAlign: TextAlign.left,
),
),
const SizedBox(
width: 10,
),
],
),
);
}
Widget _buildBookingStandard(BuildContext context) {
final itemWidth = (contentWidth - 40) / 2;
return Row(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
width: itemWidth,
height: inputItemHeight,
child: Row(
children: [
const Text(
"餐标",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextField(
controller: provider.bookingStandardController,
decoration: InputDecoration(
hintText: "请输入标准",
hintStyle: const TextStyle(
fontSize: 14,
color: Color(0xff999999),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(5),
),
),
textAlign: TextAlign.left,
),
),
const SizedBox(
width: 10,
),
],
),
),
const SizedBox(width: 10,),
SizedBox(
height: inputItemHeight,
width: itemWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Radio<String>(
value: "table",
groupValue: provider.bookingStandardType,
onChanged: (String? value) {
provider.updateBookingStandard(value ?? "table");
},
),
const Text('元/桌', style: TextStyle(fontSize: 12, color: Color(0xff666666)),),
Radio<String>(
value: "person",
groupValue: provider.bookingStandardType,
onChanged: (String? value) {
provider.updateBookingStandard(value ?? "person");
},
),
const Text('元/人', style: TextStyle(fontSize: 12, color: Color(0xff666666)),),
],
),
)
],
);
}
/// _buildBookingRemark 备注
Widget _buildBookingRemark(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: const Color(0xffededed), width: 1),
),
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
height: inputItemHeight,
child: Row(
children: [
const Text(
"备注",
style: TextStyle(color: Color(0xff333333), fontSize: 14),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextField(
controller: provider.bookingRemarkController,
decoration: InputDecoration(
hintText: "请输入备注",
hintStyle: const TextStyle(
fontSize: 14,
color: Color(0xff999999),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(5),
),
),
textAlign: TextAlign.left,
),
),
const SizedBox(
width: 10,
),
],
),
);
}
Widget _buildBookingActionBtn(BuildContext context, String title, Function() onTap) {
return InkWell(
onTap: onTap,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.blue,
),
padding: const EdgeInsets.fromLTRB(20, 5, 20, 5),
child: Text(title, style: const TextStyle(color: Colors.white, fontSize: 14),),
),
);
}
}

View File

@@ -8,10 +8,29 @@ import '../common/base/provider.dart';
class ReserveView extends BaseUI with TickerProviderStateMixin {
TabController? tabController;
late AnimationController animationController;
late Animation<double> animationSizeFactor;
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
animationSizeFactor = Tween<double>(begin: 0, end: 1).animate(
CurveTween(curve: Curves.easeInOut)
.chain(CurveTween(curve: Curves.decelerate))
.animate(animationController),
);
}
@override
void dispose() {
tabController?.dispose();
animationController.dispose();
animationSizeFactor.removeListener(() {});
super.dispose();
}
@@ -127,7 +146,11 @@ class ReserveView extends BaseUI with TickerProviderStateMixin {
}
return Row(
children: [
ReserveLeftContentView(provider: provider),
ReserveLeftContentView(
provider: provider,
animationSizeFactor: animationSizeFactor,
animationController: animationController,
),
Expanded(
child: ReserveRightContentView(
provider: provider,

View File

@@ -41,6 +41,33 @@ class ReserveViewModel extends BaseUIModel {
List<CallLogModel?>? callLogs = [];
/// bookingGender 预订人性别 1: 男 2: 女
int bookingGender = 1;
/// bookingNumController 就餐人数
TextEditingController bookingNumController = TextEditingController();
/// bookingPhoneController 联系电话
TextEditingController bookingPhoneController = TextEditingController();
/// bookingNameController 预订人姓名
TextEditingController bookingNameController = TextEditingController();
/// bookingTypeController 预订类型
TextEditingController bookingTypeController = TextEditingController();
/// bookingTableNumController 预订台桌数量
TextEditingController bookingTableNumController = TextEditingController();
/// bookingStandardController 预定餐标
TextEditingController bookingStandardController = TextEditingController();
/// bookingRemarkController 备注
TextEditingController bookingRemarkController = TextEditingController();
/// bookingSelectedTime 预订时间
String bookingSelectedTime = "";
/// bookingFocus 重点关注
bool bookingFocus = false;
/// bookingSms 短信通知
bool bookingSms = false;
/// bookingStandardType 餐标类型
String bookingStandardType = "table";
TableModel? selectedTable;
ReserveViewModel() {
selectedDate = "${now.year}-${now.month}-${now.day}";
@@ -62,10 +89,16 @@ class ReserveViewModel extends BaseUIModel {
@override
void dispose() {
pageController.dispose();
bookingNumController.dispose();
bookingPhoneController.dispose();
bookingNameController.dispose();
bookingTypeController.dispose();
bookingTableNumController.dispose();
bookingStandardController.dispose();
bookingRemarkController.dispose();
super.dispose();
}
void loadCallLog() {
ChannelManager.getCallLog("getCallLog");
}
@@ -114,6 +147,33 @@ class ReserveViewModel extends BaseUIModel {
loadAreaTableList(0);
}
updateBookingTime(int hour, int minute) {
bookingSelectedTime = "${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}";
notifyListeners();
}
updateBookingGender(int gender) {
if (bookingGender == gender) {
return;
}
bookingGender = gender;
notifyListeners();
}
updateBookingAttr(String key, bool val) {
if (key == "focus") {
bookingFocus = val;
} else if (key == "sms") {
bookingSms = val;
}
notifyListeners();
}
updateBookingStandard(String standard) {
bookingStandardType = standard;
notifyListeners();
}
String getCurrentDate() {
return "${now.year}/${now.month}/${now.day}";
}