feat:挂单

This commit is contained in:
dzc committed 2026-02-06 17:12:02 +08:00
1 parent 988247f3cd
commit 2b956342f4
12 files changed
+545 -36

No files matched your search

+2 -1
View File
@@ -27,7 +27,8 @@ export './order/steelyard_container.dart';
export './order/order_caneen_common.dart';
export './order/order_common.dart';
export './order/order_supermarket_common.dart';
export 'order/order_more_dialog.dart';
export './order/select_hold_bill_dialog.dart';
export './order/order_more_dialog.dart';
export './setting/setting_password_dialog.dart';
@@ -374,7 +374,7 @@ mixin OrderMixin {
await orderDao.edit(sqlOrderDetail);
if (orderPayType.value != OrderPayType.WALLET_QR_CODE_SCAN) {
if (sqlOrderDetail.payPrice != 0) {
final price = AppriceTool.fenToYuan(sqlOrderDetail.payPrice);
final price = AppPriceTool.fenToYuan(sqlOrderDetail.payPrice);
TtsManage.speak("购买成功总金额$price元");
}
Toast.success(msg: "购买成功");
@@ -24,7 +24,7 @@ Future<OrderMoreTypeEnum?> selectOrderMoreDialog() async {
final width = Get.context!.width;
final height = Get.context!.height;
final dialogWidth = width * 0.3;
final dialogHeight = height * 0.5;
final dialogHeight = height * 0.25;
return showDialog<OrderMoreTypeEnum?>(
context: context,
barrierDismissible: true,
@@ -55,7 +55,10 @@ Future<OrderMoreTypeEnum?> selectOrderMoreDialog() async {
).marginOnly(bottom: 20.h),
)
.toList(),
].toColumn().width(double.infinity).height(dialogHeight),
]
.toColumn(mainAxisAlignment: MainAxisAlignment.center)
.width(double.infinity)
.height(dialogHeight),
actions: [],
);
});
@@ -0,0 +1,366 @@
import 'dart:convert';
import 'package:common_utils/common_utils.dart';
import 'package:data_table_2/data_table_2.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:forui/forui.dart';
import 'package:get/get.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
class SelectHoldBillController extends GetxController {
static const String _tag = "挂单管理 Controller";
final appC = Get.find<AppControl>();
// 选择的时间
RxList<DateTime> selectDateTime = <DateTime>[
DateTime.now(),
DateTime.now().add(const Duration(days: 1)),
].obs;
RxInt currentPage = RxInt(1);
RxInt totalPage = RxInt(0);
RxInt pageSize = RxInt(5);
RxList<OrderHoldBillEntity> holdBillList = RxList();
Rxn<int> selectedId = Rxn<int>(null);
@override
void onInit() async {
super.onInit();
await getHoldBillList();
}
@override
void onClose() {}
Future<void> doDateRangeDate(List<DateTime>? dateTime) async {
if (ObjectUtil.isEmptyList(dateTime)) {
return;
}
selectDateTime.value = dateTime!;
currentPage.value = 1;
await doPage();
}
/// 搜索
Future<void> doPage({int? page}) async {
if (page != null) currentPage.value = page;
await getHoldBillList(isLoading: true);
}
/// 获取挂单列表
Future<void> getHoldBillList({bool isLoading = false}) async {
if (isLoading) {
EasyLoading.show(
status: '查询中...',
maskType: EasyLoadingMaskType.black,
);
}
final orderHoldBillDao = appC.dataBase.getOrderHoldBillDao;
try {
final startTime = DateUtil.formatDate(
DateTime(selectDateTime[0].year, selectDateTime[0].month,
selectDateTime[0].day, 0, 0, 0),
);
final endTime = DateUtil.formatDate(
DateTime(selectDateTime[1].year, selectDateTime[1].month,
selectDateTime[1].day, 23, 59, 59),
);
final total = await orderHoldBillDao.count(
startTime,
endTime,
);
totalPage.value = total ?? 0;
final list = await orderHoldBillDao.list(
startTime,
endTime,
pageSize.value,
(currentPage.value - 1) * pageSize.value,
);
if (ObjectUtil.isEmptyList(list)) {
holdBillList.value = [];
return;
}
holdBillList.value = list;
} catch (error, stack) {
LogUtil.e("|$_tag|,获取挂单列表意外的错误error:|$error|,stack:|$stack|");
} finally {
if (isLoading) {
Future.delayed(const Duration(seconds: 1), () {
EasyLoading.dismiss();
});
}
// 只保留7天内的挂单数据
orderHoldBillDao.deleteOlderThan7Days();
}
}
}
Future<OrderHoldBillEntity?> selectHoldBillDialog() async {
final context = Get.context!;
final theme = FTheme.of(context);
final holdBillC = Get.put<SelectHoldBillController>(
SelectHoldBillController(),
);
await holdBillC.getHoldBillList(isLoading: true);
final width = Get.context!.width;
final height = Get.context!.height;
final dialogWidth = width * 0.9;
final dialogHeight = height * 0.7;
return showDialog<OrderHoldBillEntity?>(
context: context,
barrierDismissible: true,
builder: (BuildContext _) {
return FDialog(
title: Text(
"挂单列表",
style: theme.typography.lg,
).marginOnly(bottom: 20.h),
style: theme.dialogStyle.copyWith(
insetPadding: EdgeInsets.zero,
maxWidth: dialogWidth,
minWidth: dialogWidth,
horizontalStyle: theme.dialogStyle.horizontalStyle.copyWith(
padding: EdgeInsets.all(20.w),
),
),
body: <Widget>[
_buildHoldBillSearch(context),
_buildHoldBillList(context).expanded(),
Obx(
() => appPage(
context,
pageNo: holdBillC.currentPage.value,
pageSize: holdBillC.pageSize.value,
total: holdBillC.totalPage.value,
onPageChanged: (pageNo) => holdBillC.doPage(page: pageNo),
),
)
].toColumn().width(double.infinity).height(dialogHeight),
actions: [
<Widget>[
FButton(
label: Text(
'确定',
style: theme.typography.base.copyWith(
color: theme.colorScheme.secondary,
),
),
onPress: () {
final holdBillC = Get.find<SelectHoldBillController>();
final selected = holdBillC.holdBillList.firstWhereOrNull(
(v) => v.id == holdBillC.selectedId.value,
);
if (selected == null) {
EasyLoading.showInfo("请先选择一条挂单");
return;
}
Get.back(result: selected);
},
).flexible(flex: 1),
SizedBox(width: 10.w),
FButton(
style: FButtonStyle.outline,
label: Text('取消', style: theme.typography.base),
onPress: () => Get.back(result: null),
).flexible(flex: 1),
].toRow()
],
);
},
);
}
Widget _buildHoldBillSearch(BuildContext context) {
final holdBillC = Get.find<SelectHoldBillController>();
return <Widget>[
const Spacer(),
Obx(
() => appDatePicker(
context,
datetimeRange: holdBillC.selectDateTime,
onChnage: (dateList) => holdBillC.doDateRangeDate(dateList),
).width(400.w).marginOnly(right: 15.w),
),
].toRow();
}
Widget _buildHoldBillList(BuildContext context) {
final theme = FTheme.of(context);
final holdBillC = Get.find<SelectHoldBillController>();
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final width = constraints.maxWidth;
// 计算列可用总宽度 = 父容器宽度 - 左右边距 - 每列之间的间距
const int colCount = 4;
final double spacing = 12.w; // columnSpacing
final double marginH = 12.w; // horizontalMargin
final double totalColAvailableWidth =
width - 2 * marginH - spacing * (colCount - 1);
final hdWidth = totalColAvailableWidth / colCount;
final height = constraints.maxHeight;
final hdHeight = (height - 60.h) / 5;
return Obx(
() => DataTable2(
columnSpacing: 12.w,
horizontalMargin: 12.w,
minWidth: 600.w,
showBottomBorder: true,
headingTextStyle: theme.typography.lg,
dataTextStyle: theme.typography.base,
dataRowHeight: hdHeight,
columns: [
DataColumn2(
label: Text("购物车", textAlign: TextAlign.center),
headingRowAlignment: MainAxisAlignment.center,
fixedWidth: hdWidth * 1.7,
),
DataColumn2(
label: Text("价格", textAlign: TextAlign.center),
headingRowAlignment: MainAxisAlignment.center,
fixedWidth: hdWidth * 0.8,
),
DataColumn2(
label: Text("挂单时间", textAlign: TextAlign.center),
headingRowAlignment: MainAxisAlignment.center,
fixedWidth: hdWidth,
),
],
rows: holdBillC.holdBillList.map((e) {
final carList = (jsonDecode(e.carListJson ?? '[]') as List)
.map((v) => ShopCardEntity.fromJson(v as Map<String, dynamic>))
.toList();
return DataRow(
selected: holdBillC.selectedId.value == e.id,
onSelectChanged: (selected) {
if (selected == true) {
holdBillC.selectedId.value = e.id;
}
},
color: WidgetStateProperty.resolveWith<Color?>((states) {
if (states.contains(WidgetState.selected)) {
return theme.colorScheme.secondary.withAlpha(24);
}
if (states.contains(WidgetState.hovered)) {
return theme.colorScheme.secondary.withAlpha(12);
}
return null;
}),
cells: [
DataCell(
GridView.builder(
shrinkWrap: true,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
childAspectRatio: 30,
),
itemCount: carList.length,
itemBuilder: (context, i) {
final currentCar = carList[i];
return <Widget>[
Text(
"${currentCar.productName}(单价¥${AppPriceTool.fenToYuan(currentCar.productPrice)}) x ${currentCar.productNumber}",
textAlign: TextAlign.left,
style: theme.typography.sm,
),
Text("共", style: theme.typography.sm),
appPrice(
context,
currentCar.totalPrice,
textStyle: theme.typography.sm,
),
].toRow().marginOnly(left: 50.w);
},
),
),
DataCell(
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
childAspectRatio: 10,
),
itemCount: 3,
itemBuilder: (context, i) {
// 购物车总价
if (i == 0) {
return <Widget>[
Text(
"购物车总价:",
textAlign: TextAlign.left,
style: theme.typography.sm,
).flexible(flex: 1),
appPrice(
context,
e.price,
textStyle: theme.typography.sm,
).flexible(flex: 1),
].toRow();
}
// 额外价格
if (i == 1) {
return <Widget>[
Text(
"额外价格:",
textAlign: TextAlign.left,
style: theme.typography.sm,
).flexible(flex: 1),
appPrice(
context,
e.extraPrice,
textStyle: theme.typography.sm,
).flexible(flex: 1),
].toRow();
}
// 支付价格
if (i == 2) {
return <Widget>[
Text(
"支付价格:",
textAlign: TextAlign.left,
style: theme.typography.sm,
).flexible(flex: 1),
appPrice(
context,
e.payPrice,
textStyle: theme.typography.sm,
).flexible(flex: 1),
].toRow();
}
return SizedBox.shrink();
},
),
),
DataCell(
Text(
DateUtil.formatDate(
e.createTime,
format: DateFormats.full,
),
textAlign: TextAlign.center,
style: theme.typography.base,
).center(),
),
],
);
}).toList(),
),
);
},
);
}