From 2d890f81cdb8d5a0a7c3a1e5c5d41ed7264a2697 Mon Sep 17 00:00:00 2001 From: GYJ <1157756119@qq.com> Date: Tue, 26 Nov 2024 17:58:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=B0=E6=A1=8C=E5=88=97=E8=A1=A8=E9=A2=84?= =?UTF-8?q?=E5=AE=9A=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/home/reserve_left_content_view.dart | 683 +++++++++++++++++++++++- lib/home/reserve_view.dart | 25 +- lib/home/reserve_view_model.dart | 64 ++- 3 files changed, 752 insertions(+), 20 deletions(-) diff --git a/lib/home/reserve_left_content_view.dart b/lib/home/reserve_left_content_view.dart index 8c5a316..c82f61a 100644 --- a/lib/home/reserve_left_content_view.dart +++ b/lib/home/reserve_left_content_view.dart @@ -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 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 { ), ); } -} \ No newline at end of file + + /// _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( + value: "table", + groupValue: provider.bookingStandardType, + onChanged: (String? value) { + provider.updateBookingStandard(value ?? "table"); + }, + ), + const Text('元/桌', style: TextStyle(fontSize: 12, color: Color(0xff666666)),), + Radio( + 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),), + ), + ); + } +} diff --git a/lib/home/reserve_view.dart b/lib/home/reserve_view.dart index d859ce9..3221618 100644 --- a/lib/home/reserve_view.dart +++ b/lib/home/reserve_view.dart @@ -8,10 +8,29 @@ import '../common/base/provider.dart'; class ReserveView extends BaseUI with TickerProviderStateMixin { TabController? tabController; + late AnimationController animationController; + late Animation animationSizeFactor; + + @override + void initState() { + super.initState(); + + animationController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 300), + ); + animationSizeFactor = Tween(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, diff --git a/lib/home/reserve_view_model.dart b/lib/home/reserve_view_model.dart index f306cf1..79c9fa5 100644 --- a/lib/home/reserve_view_model.dart +++ b/lib/home/reserve_view_model.dart @@ -40,7 +40,34 @@ class ReserveViewModel extends BaseUIModel { Map> tableMap = {}; List? 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}"; }