feat:饭卡激活
This commit is contained in:
1 parent
72443f7abf
commit
9a98ac8e1c
20 files changed
+665
-154
No files matched your search
@@ -2,7 +2,7 @@ import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
|
||||
abstract class ProductApi {
|
||||
/// 菜品分类
|
||||
static Future<List<ServiceClassify>?> cookbookClassify(
|
||||
static Future<List<ServiceClassify>?> canteenClassify(
|
||||
dynamic pa,
|
||||
) async {
|
||||
final res = await HttpManage().dio.get(
|
||||
|
||||
@@ -24,7 +24,7 @@ abstract class WalletApi {
|
||||
|
||||
/// 开卡成功
|
||||
static Future<bool> openCardSuccess(dynamic pa) async {
|
||||
final res = await HttpManage().dio.get<ServiceBase>(
|
||||
final res = await HttpManage().dio.get(
|
||||
"/wallet/wallet-active/ad/open-card-success",
|
||||
queryParameters: pa,
|
||||
);
|
||||
@@ -34,7 +34,7 @@ abstract class WalletApi {
|
||||
|
||||
/// 重新激活
|
||||
static Future<bool> refreshAvatar(dynamic pa) async {
|
||||
final res = await HttpManage().dio.get<ServiceBase>(
|
||||
final res = await HttpManage().dio.get(
|
||||
"/wallet/wallet-active/ad/refresh-avatar",
|
||||
queryParameters: pa,
|
||||
);
|
||||
|
||||
@@ -56,22 +56,28 @@ enum OrderPayType implements BaseEnum {
|
||||
/// 订单状态
|
||||
enum OrderStatus implements BaseEnum {
|
||||
// 查询使用
|
||||
TOTAL("-1", "全部"),
|
||||
TOTAL("-1", "全部", true),
|
||||
|
||||
CREATE("1", "未付款"),
|
||||
OFFLINE_CREATE("2", "离线创建订单(未支付)"),
|
||||
PAY("5", "已付款"),
|
||||
OFFLINE_PAY("6", "本地支付"),
|
||||
REFUND("10", "退款"),
|
||||
CANCEL("20", "已核销"),
|
||||
CREATE("1", "未付款", true),
|
||||
OFFLINE_CREATE("2", "离线创建订单(未支付)", false),
|
||||
PAY("5", "已付款", true),
|
||||
OFFLINE_PAY("6", "本地支付", true),
|
||||
REFUND("10", "退款", true),
|
||||
CANCEL("20", "已核销", false),
|
||||
;
|
||||
|
||||
@override
|
||||
final String code;
|
||||
@override
|
||||
final String title;
|
||||
@override
|
||||
final bool visible;
|
||||
|
||||
const OrderStatus(this.code, this.title);
|
||||
const OrderStatus(this.code, this.title, this.visible);
|
||||
|
||||
static List<OrderStatus> visibleList() {
|
||||
return OrderStatus.values.where((e) => e.visible).toList();
|
||||
}
|
||||
}
|
||||
|
||||
// 打印状态
|
||||
|
||||
@@ -122,12 +122,6 @@ class SyncFaceTool {
|
||||
add.path = filePath;
|
||||
await faceDao.edit(add);
|
||||
}
|
||||
// 重新生成人脸模型
|
||||
await AppFaceTool.removeFace(sampleId: add.sampleId);
|
||||
await AppFaceTool.faceRegister(
|
||||
userId: add.userId.toString(),
|
||||
forceRegister: true,
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -162,12 +156,6 @@ class SyncFaceTool {
|
||||
edit.path = filePath;
|
||||
}
|
||||
await faceDao.edit(edit);
|
||||
// 重新生成人脸模型
|
||||
await AppFaceTool.removeFace(sampleId: edit.sampleId);
|
||||
await AppFaceTool.faceRegister(
|
||||
userId: edit.userId.toString(),
|
||||
forceRegister: true,
|
||||
);
|
||||
}
|
||||
if (data.length >= size) return true;
|
||||
} catch (e, stack) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
@@ -10,13 +9,8 @@ abstract class SyncProductTool {
|
||||
static Future<void> updateDatabase() async {
|
||||
final isNetwork = AppNetworkTool.isAutoNetwork();
|
||||
if (!isNetwork) return;
|
||||
EasyLoading.show(
|
||||
status: '初始化资源...',
|
||||
maskType: EasyLoadingMaskType.black,
|
||||
);
|
||||
await syncClassify();
|
||||
await syncProduct();
|
||||
EasyLoading.dismiss();
|
||||
}
|
||||
|
||||
/// 同步商品分类
|
||||
@@ -26,7 +20,7 @@ abstract class SyncProductTool {
|
||||
try {
|
||||
List<ServiceClassify>? apiList;
|
||||
if (sysType == SysType.CANTEEN) {
|
||||
apiList = await ProductApi.cookbookClassify(null);
|
||||
apiList = await ProductApi.canteenClassify(null);
|
||||
} else if (sysType == SysType.SUPERMARKET) {
|
||||
apiList = await ProductApi.supermarketClassify(null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
|
||||
Widget appBack(
|
||||
BuildContext context, {
|
||||
required VoidCallback onTap,
|
||||
double height = 90,
|
||||
}) {
|
||||
final theme = FTheme.of(context);
|
||||
return FIcon(
|
||||
FAssets.icons.chevronLeft,
|
||||
size: theme.typography.xl4.fontSize,
|
||||
).alignLeft().width(height).onTap(() => onTap());
|
||||
}
|
||||
@@ -8,7 +8,7 @@ Future<bool> appMessageDialog(BuildContext context, String msg) async {
|
||||
final res = await showAdaptiveDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => FDialog(
|
||||
direction: Axis.horizontal,
|
||||
direction: Axis.vertical,
|
||||
title: <Widget>[
|
||||
FIcon(
|
||||
FAssets.icons.circleAlert,
|
||||
@@ -17,25 +17,30 @@ Future<bool> appMessageDialog(BuildContext context, String msg) async {
|
||||
).paddingOnly(top: 5.h),
|
||||
Text("警告", style: theme.typography.xl).paddingOnly(left: 10.w),
|
||||
].toRow(crossAxisAlignment: CrossAxisAlignment.center),
|
||||
body: Text(msg, style: theme.typography.base)
|
||||
.width(context.width * 0.5)
|
||||
body: Text(msg, style: theme.typography.xl)
|
||||
.width(context.width * 0.6)
|
||||
.padding(vertical: 50.w)
|
||||
.marginSymmetric(
|
||||
vertical: 10.h,
|
||||
),
|
||||
actions: [
|
||||
FButton(
|
||||
<Widget>[
|
||||
FButton(
|
||||
label: Text(
|
||||
'确定',
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => Navigator.of(context).pop(true),
|
||||
).flexible(flex: 1),
|
||||
SizedBox(width: 10.w),
|
||||
FButton(
|
||||
style: FButtonStyle.outline,
|
||||
label: Text('取消', style: theme.typography.base),
|
||||
onPress: () => Navigator.of(context).pop(false)),
|
||||
FButton(
|
||||
label: Text(
|
||||
'确定',
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => Navigator.of(context).pop(true),
|
||||
),
|
||||
onPress: () => Navigator.of(context).pop(false),
|
||||
).flexible(flex: 1),
|
||||
].toRow(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
|
||||
Widget readCardEmpty(
|
||||
BuildContext context, {
|
||||
required bool loading,
|
||||
}) {
|
||||
final theme = FTheme.of(context);
|
||||
if (loading) {
|
||||
return <Widget>[
|
||||
CircularProgressIndicator(
|
||||
color: theme.colorScheme.primary,
|
||||
).width(100.w).height(100.w).center(),
|
||||
SizedBox(height: 10.h),
|
||||
Text(
|
||||
"扫描中",
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
].toColumn(mainAxisAlignment: MainAxisAlignment.center);
|
||||
}
|
||||
return <Widget>[
|
||||
FIcon(
|
||||
FAssets.icons.idCard,
|
||||
size: theme.typography.xl4.fontSize,
|
||||
),
|
||||
SizedBox(height: 10.h),
|
||||
Text(
|
||||
"请让用户放置饭卡",
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
].toColumn(mainAxisAlignment: MainAxisAlignment.center);
|
||||
}
|
||||
|
||||
Future<void> cardDialog({
|
||||
required String title,
|
||||
required Rx<bool> loading,
|
||||
required VoidCallback doSubmit,
|
||||
required Rx<ServiceOpenCard?> detail,
|
||||
}) async {
|
||||
showDialog(
|
||||
context: Get.context!,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
final width = context.width;
|
||||
final height = context.height;
|
||||
final theme = FTheme.of(context);
|
||||
final textStyle = theme.typography.xl;
|
||||
final titleTheme = theme.tileGroupStyle.tileStyle.copyWith(
|
||||
border: Border.all(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
);
|
||||
return FDialog(
|
||||
direction: Axis.vertical,
|
||||
title: Text(title, style: theme.typography.lg),
|
||||
body: <Widget>[
|
||||
Obx(
|
||||
() => Visibility(
|
||||
visible: detail.value == null,
|
||||
replacement: <Widget>[
|
||||
FTile(
|
||||
style: titleTheme,
|
||||
prefixIcon: FIcon(FAssets.icons.user),
|
||||
title: Text('姓名', style: textStyle),
|
||||
details: Text(
|
||||
"${detail.value?.username}",
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
FTile(
|
||||
style: titleTheme,
|
||||
prefixIcon: FIcon(FAssets.icons.badgeDollarSign),
|
||||
title: Text('卡号', style: textStyle),
|
||||
details: Text(
|
||||
"${detail.value?.cardNumber}",
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
].toColumn(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
),
|
||||
child: readCardEmpty(
|
||||
context,
|
||||
loading: loading.value,
|
||||
),
|
||||
),
|
||||
).width(width * 0.5).height(height * 0.5),
|
||||
].toColumn(),
|
||||
actions: [
|
||||
FButton(
|
||||
label: Text(
|
||||
"确定",
|
||||
style: theme.typography.xl.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => doSubmit(),
|
||||
).flexible(flex: 1),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ library;
|
||||
|
||||
export './toast/toast_widget.dart';
|
||||
|
||||
export './app/app_back.dart';
|
||||
export './app/app_check_pay_type_dialog.dart';
|
||||
export './app/app_date_picker.dart';
|
||||
export './app/app_divider_title.dart';
|
||||
@@ -14,6 +15,8 @@ export './app/app_price.dart';
|
||||
export './app/app_radio_hour_type_dialog.dart';
|
||||
export './app/app_title.dart';
|
||||
|
||||
export './card/card_common.dart';
|
||||
|
||||
export './order/mixin/order_mixin.dart';
|
||||
export './order/select_pay_type_dialog.dart';
|
||||
export './order/steelyard_container.dart';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
|
||||
@@ -17,13 +17,11 @@ class CanteenProductPage extends GetView<CanteenProductController> {
|
||||
final context = Get.context!;
|
||||
final theme = FTheme.of(context);
|
||||
return <Widget>[
|
||||
FIcon(
|
||||
FAssets.icons.chevronLeft,
|
||||
size: theme.typography.xl4.fontSize,
|
||||
)
|
||||
.alignLeft()
|
||||
.width(headerHeight)
|
||||
.onTap(() => Get.offAndToNamed(RouteNames.panel)),
|
||||
appBack(
|
||||
context,
|
||||
height: headerHeight,
|
||||
onTap: () => Get.offAndToNamed(RouteNames.panel),
|
||||
),
|
||||
Obx(
|
||||
() => orderRowClassify(
|
||||
context,
|
||||
|
||||
@@ -19,8 +19,7 @@ class CardActiveController extends GetxController {
|
||||
|
||||
RxList<ServiceOpenCard> tableList = <ServiceOpenCard>[].obs;
|
||||
|
||||
// 读卡器
|
||||
RxString readCardNumber = "未读取".obs;
|
||||
Rx<ServiceOpenCard?> detail = Rx(null);
|
||||
|
||||
RxBool readLoading = false.obs;
|
||||
|
||||
@@ -54,20 +53,28 @@ class CardActiveController extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> getTableList() async {
|
||||
final appSetting = await AppSettingTool.getSysSetting();
|
||||
final deptId = appSetting.merchantDeptId;
|
||||
final pa = {
|
||||
"current": currentPage.value,
|
||||
"size": pageSize.value,
|
||||
"deptId": "",
|
||||
"walletTypeId": "",
|
||||
};
|
||||
final data = await WalletApi.openCardList(pa);
|
||||
if (data == null) return;
|
||||
totalPage.value = data.total;
|
||||
final records = data.records;
|
||||
if (records != null) {
|
||||
tableList.value = records;
|
||||
EasyLoading.show(
|
||||
status: '查询中...',
|
||||
maskType: EasyLoadingMaskType.black,
|
||||
);
|
||||
try {
|
||||
final appSetting = await AppSettingTool.getSysSetting();
|
||||
final deptId = appSetting.merchantDeptId;
|
||||
final pa = {
|
||||
"current": currentPage.value,
|
||||
"size": pageSize.value,
|
||||
"deptId": "",
|
||||
"walletTypeId": "",
|
||||
};
|
||||
final data = await WalletApi.openCardList(pa);
|
||||
if (data == null) return;
|
||||
totalPage.value = data.total;
|
||||
final records = data.records;
|
||||
if (records != null) {
|
||||
tableList.value = records;
|
||||
}
|
||||
} finally {
|
||||
EasyLoading.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,28 +95,26 @@ class CardActiveController extends GetxController {
|
||||
return;
|
||||
}
|
||||
writeLoading.value = true;
|
||||
// writeCardDialog(
|
||||
// context: Get.context!,
|
||||
// cardNumber: v.cardNumber!,
|
||||
// doCancel: () {
|
||||
// Get.back();
|
||||
// serialCardManage.readerClose();
|
||||
// serialCardManage.close();
|
||||
// _closeWriteStatus();
|
||||
// },
|
||||
// );
|
||||
detail.value = null;
|
||||
final context = Get.context!;
|
||||
cardDialog(
|
||||
title: "写卡",
|
||||
loading: readLoading,
|
||||
detail: detail,
|
||||
doSubmit: () {
|
||||
Navigator.of(context).pop();
|
||||
_closeStatus();
|
||||
},
|
||||
);
|
||||
serialCardManage.callback = (type, status, res) async {
|
||||
switch (status) {
|
||||
case SerialCardResStatus.success:
|
||||
Toast.success(msg: "写入成功");
|
||||
serialCardManage.readerClose();
|
||||
serialCardManage.close();
|
||||
if (ObjectUtil.isNotEmpty(v.id)) {
|
||||
await _getOpenCardSuccess(v.id!);
|
||||
currentPage.value = 1;
|
||||
getTableList();
|
||||
}
|
||||
Navigator.of(Get.context!).pop();
|
||||
detail.value = v;
|
||||
_closeStatus();
|
||||
break;
|
||||
case SerialCardResStatus.warning:
|
||||
break;
|
||||
@@ -122,13 +127,15 @@ class CardActiveController extends GetxController {
|
||||
TtsManage.speak("请在合适区域放置饭卡");
|
||||
serialCardManage.sendWrite(v.cardNumber!);
|
||||
} catch (e, stack) {
|
||||
_closeStatus();
|
||||
logger.d("写卡失败error:|$e|stack:|$stack|");
|
||||
Toast.error(msg: "写入失败,请重试");
|
||||
}
|
||||
}
|
||||
|
||||
// 读卡
|
||||
void doSelectHorType() async {
|
||||
void doReadCard() async {
|
||||
final context = Get.context!;
|
||||
try {
|
||||
await serialCardManage.connect();
|
||||
if (!serialCardManage.isConnect) {
|
||||
@@ -136,23 +143,26 @@ class CardActiveController extends GetxController {
|
||||
return;
|
||||
}
|
||||
readLoading.value = true;
|
||||
// readCardDialog(
|
||||
// context: Get.context!,
|
||||
// doCancel: () {
|
||||
// serialCardManage.readerClose();
|
||||
// serialCardManage.close();
|
||||
// _closeReadStatus();
|
||||
// Get.back();
|
||||
// },
|
||||
// );
|
||||
serialCardManage.callback = (type, status, res) {
|
||||
detail.value = null;
|
||||
cardDialog(
|
||||
title: "读卡",
|
||||
loading: readLoading,
|
||||
detail: detail,
|
||||
doSubmit: () {
|
||||
Navigator.of(context).pop();
|
||||
_closeStatus();
|
||||
},
|
||||
);
|
||||
serialCardManage.callback = (type, status, res) async {
|
||||
switch (status) {
|
||||
case SerialCardResStatus.success:
|
||||
Toast.success(msg: "读取成功");
|
||||
readLoading.value = false;
|
||||
readCardNumber.value = res;
|
||||
serialCardManage.readerClose();
|
||||
serialCardManage.close();
|
||||
final pa = {"cardNumber": res};
|
||||
final data = await WalletApi.openCardList(pa);
|
||||
if (data != null && data.records != null) {
|
||||
detail.value = data.records![0];
|
||||
}
|
||||
_closeStatus();
|
||||
break;
|
||||
case SerialCardResStatus.warning:
|
||||
break;
|
||||
@@ -165,7 +175,7 @@ class CardActiveController extends GetxController {
|
||||
TtsManage.speak("请在合适区域放置饭卡");
|
||||
serialCardManage.sendRead();
|
||||
} catch (e, stack) {
|
||||
_closeReadStatus();
|
||||
_closeStatus();
|
||||
logger.d("读卡失败error:|$e|stack:|$stack|");
|
||||
Toast.error(msg: "读取失败,请重试");
|
||||
}
|
||||
@@ -173,7 +183,10 @@ class CardActiveController extends GetxController {
|
||||
|
||||
Future<void> _getOpenCardSuccess(String id) async {
|
||||
try {
|
||||
EasyLoading.show(status: '激活饭卡中...');
|
||||
EasyLoading.show(
|
||||
status: '激活饭卡中...',
|
||||
maskType: EasyLoadingMaskType.black,
|
||||
);
|
||||
final pa = {"id": id};
|
||||
final data = await WalletApi.openCardSuccess(pa);
|
||||
if (data == false) throw Error();
|
||||
@@ -199,14 +212,17 @@ class CardActiveController extends GetxController {
|
||||
final pa = {"id": v.id};
|
||||
final data = await WalletApi.refreshAvatar(pa);
|
||||
if (data == false) return;
|
||||
TtsManage.speak("重新激活成功");
|
||||
Toast.success(msg: "重新激活成功");
|
||||
getTableList();
|
||||
} catch (e, stack) {
|
||||
logger.d("重新激活失败error:|$e|stack:|$stack|");
|
||||
}
|
||||
}
|
||||
|
||||
void _closeReadStatus() {
|
||||
void _closeStatus() {
|
||||
serialCardManage.readerClose();
|
||||
serialCardManage.close();
|
||||
readLoading.value = false;
|
||||
readCardNumber.value = "未读取";
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,50 @@ import 'index.dart';
|
||||
class CardActivePage extends GetView<CardActiveController> {
|
||||
const CardActivePage({super.key});
|
||||
|
||||
// 主视图
|
||||
Widget _buildView(BuildContext context) {
|
||||
// 条件
|
||||
Widget _buildHeader(double height) {
|
||||
final context = Get.context!;
|
||||
final theme = FTheme.of(context);
|
||||
return <Widget>[
|
||||
appBack(
|
||||
context,
|
||||
height: height,
|
||||
onTap: () => Get.offAndToNamed(RouteNames.panel),
|
||||
),
|
||||
Spacer(),
|
||||
FButton(
|
||||
prefix: FIcon(
|
||||
FAssets.icons.idCard,
|
||||
size: theme.typography.base.fontSize,
|
||||
),
|
||||
label: Text(
|
||||
'读卡',
|
||||
style: theme.typography.base,
|
||||
),
|
||||
style: FButtonStyle.secondary,
|
||||
onPress: () => controller.doReadCard(),
|
||||
),
|
||||
SizedBox(width: 20.w),
|
||||
FButton(
|
||||
prefix: FIcon(
|
||||
FAssets.icons.search,
|
||||
size: theme.typography.base.fontSize,
|
||||
),
|
||||
label: Text(
|
||||
'搜索',
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => controller.doPage(),
|
||||
),
|
||||
].toRow();
|
||||
}
|
||||
|
||||
// 主视图
|
||||
Widget _buildView() {
|
||||
final context = Get.context!;
|
||||
return <Widget>[
|
||||
_condition(context),
|
||||
_buildTable(context).expanded(),
|
||||
Obx(() => appPage(
|
||||
context,
|
||||
@@ -26,11 +66,6 @@ class CardActivePage extends GetView<CardActiveController> {
|
||||
].toColumn();
|
||||
}
|
||||
|
||||
// 条件
|
||||
Widget _condition(BuildContext context) {
|
||||
return const Center();
|
||||
}
|
||||
|
||||
// 主视图
|
||||
Widget _buildTable(BuildContext context) {
|
||||
final theme = FTheme.of(context);
|
||||
@@ -133,12 +168,28 @@ class CardActivePage extends GetView<CardActiveController> {
|
||||
).center(),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
WalletType.values
|
||||
.fromCode(v.walletTypeUniqueCode)
|
||||
?.title ??
|
||||
"未知",
|
||||
textAlign: TextAlign.center,
|
||||
Visibility(
|
||||
visible: v.isActiveHardware == false,
|
||||
replacement: FButton(
|
||||
style: FButtonStyle.destructive,
|
||||
prefix: FIcon(FAssets.icons.refreshCcw),
|
||||
label: Text(
|
||||
'重新激活',
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => controller.doRefreshAvatar(v),
|
||||
),
|
||||
child: FButton(
|
||||
style: FButtonStyle.secondary,
|
||||
prefix: FIcon(FAssets.icons.folderOpenDot),
|
||||
label: Text(
|
||||
'激活',
|
||||
style: theme.typography.base,
|
||||
),
|
||||
onPress: () => controller.doWriteCard(v),
|
||||
),
|
||||
).center(),
|
||||
),
|
||||
],
|
||||
@@ -151,26 +202,16 @@ class CardActivePage extends GetView<CardActiveController> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = FTheme.of(context);
|
||||
final height = context.height;
|
||||
final height = 90;
|
||||
return GetBuilder<CardActiveController>(
|
||||
init: CardActiveController(),
|
||||
id: "card_active",
|
||||
builder: (_) {
|
||||
return FScaffold(
|
||||
header: FHeader.nested(
|
||||
title: Text("开卡管理"),
|
||||
prefixActions: [
|
||||
FHeaderAction.back(onPress: Get.back),
|
||||
],
|
||||
style: theme.headerStyle.nestedStyle.copyWith(
|
||||
titleTextStyle: theme.typography.lg,
|
||||
actionStyle: theme.headerStyle.nestedStyle.actionStyle.copyWith(
|
||||
size: theme.typography.xl2.fontSize,
|
||||
),
|
||||
),
|
||||
).height(height * 0.1),
|
||||
content: _buildView(context),
|
||||
header: _buildHeader(height.h)
|
||||
.height(height.h)
|
||||
.padding(vertical: 30.h, horizontal: 10.w),
|
||||
content: _buildView(),
|
||||
resizeToAvoidBottomInset: false,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -137,7 +137,7 @@ class OrderHistoryController extends GetxController {
|
||||
|
||||
Future<void> getTotalList() async {
|
||||
final total = await _getTotal();
|
||||
List<OrderHistoryTableItem> tabs = OrderStatus.values
|
||||
List<OrderHistoryTableItem> tabs = OrderStatus.visibleList()
|
||||
.map((v) => OrderHistoryTableItem(status: v))
|
||||
.toList();
|
||||
for (int i = 0; i < tabs.length; i++) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class SettingPage extends GetView<SettingController> {
|
||||
),
|
||||
),
|
||||
Obx(() => _buildDetail(context, controller.cuurentMenuType.value))
|
||||
.marginOnly(left: 20.w)
|
||||
.marginSymmetric(horizontal: 10.w)
|
||||
.expanded(),
|
||||
].toRow().height(double.infinity);
|
||||
}
|
||||
|
||||
@@ -33,13 +33,6 @@ Widget settingBackup(BuildContext context) {
|
||||
title: appPrefixTitle(context, "log备份"),
|
||||
onPress: () => controller.backupsLog(),
|
||||
),
|
||||
appDividerTitle(context, "恢复"),
|
||||
FTile(
|
||||
prefixIcon: appPrefixIcon(context, FAssets.icons.user),
|
||||
suffixIcon: appSuffixIcon(context, FAssets.icons.folderSync),
|
||||
title: appPrefixTitle(context, "sql恢复"),
|
||||
onPress: () => controller.recoverSql(),
|
||||
),
|
||||
].toColumnSpace(space: 20.h);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,6 +104,8 @@ class FaceManageController extends GetxController {
|
||||
} finally {
|
||||
currentPage.value = 1;
|
||||
getFaceList();
|
||||
// 重新生成人脸模型
|
||||
await AppFaceTool.removeFace(sampleId: "-1");
|
||||
await AppFaceTool.faceRegister(forceRegister: true);
|
||||
Toast.success(msg: "同步成功");
|
||||
EasyLoading.dismiss();
|
||||
|
||||
@@ -47,11 +47,27 @@ class ProductManageController extends GetxController {
|
||||
Future<void> initData() async {
|
||||
await getProductList();
|
||||
if (ObjectUtil.isEmptyList(productList)) {
|
||||
await SyncProductTool.updateDatabase();
|
||||
getProductList();
|
||||
}
|
||||
}
|
||||
|
||||
// 更新商品和分类
|
||||
Future<void> updateProductAndClassify() async {
|
||||
EasyLoading.show(
|
||||
status: '更新中...',
|
||||
maskType: EasyLoadingMaskType.black,
|
||||
);
|
||||
try {
|
||||
await SyncProductTool.updateDatabase();
|
||||
await getProductList();
|
||||
} finally {
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
EasyLoading.dismiss();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 获取商品列表
|
||||
Future<void> getProductList({bool isLoading = false}) async {
|
||||
if (isLoading) {
|
||||
EasyLoading.show(
|
||||
@@ -60,7 +76,6 @@ class ProductManageController extends GetxController {
|
||||
);
|
||||
}
|
||||
try {
|
||||
await SyncProductTool.updateDatabase();
|
||||
final app = Get.find<AppControl>();
|
||||
final sysSetting = await AppSettingTool.getSysSetting();
|
||||
final productDao = app.dataBase.getProductDao;
|
||||
@@ -134,6 +149,10 @@ Widget buildSearch(BuildContext context) {
|
||||
).width(300.w),
|
||||
].toRow().expanded(),
|
||||
FButton(
|
||||
prefix: FIcon(
|
||||
FAssets.icons.search,
|
||||
size: theme.typography.base.fontSize,
|
||||
),
|
||||
label: Text(
|
||||
'搜索',
|
||||
style: theme.typography.base.copyWith(
|
||||
@@ -142,6 +161,16 @@ Widget buildSearch(BuildContext context) {
|
||||
),
|
||||
onPress: () => productC.doPage(),
|
||||
),
|
||||
SizedBox(width: 20.w),
|
||||
FButton(
|
||||
label: Text(
|
||||
'更新商品和分类',
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => productC.updateProductAndClassify(),
|
||||
),
|
||||
].toRow();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_subscreen_plugin/flutter_subscreen_plugin.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
@@ -5,6 +8,16 @@ import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
class SupermarketOrderController extends GetxController with OrderMixin {
|
||||
SupermarketOrderController();
|
||||
|
||||
static const _tag = "食堂购买页面";
|
||||
|
||||
final appC = Get.find<AppControl>();
|
||||
|
||||
late SysSetting appSetting;
|
||||
|
||||
RxInt currentPage = RxInt(1);
|
||||
RxInt totalPage = RxInt(0);
|
||||
RxInt pageSize = RxInt(24);
|
||||
|
||||
_initData() {
|
||||
update(["supermarket_order"]);
|
||||
}
|
||||
@@ -12,8 +25,9 @@ class SupermarketOrderController extends GetxController with OrderMixin {
|
||||
void onTap() {}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
await _initState();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -25,5 +39,141 @@ class SupermarketOrderController extends GetxController with OrderMixin {
|
||||
@override
|
||||
void onClose() {
|
||||
super.onClose();
|
||||
SubScreenPlugin.sendMsgToViceScreen(SubScreenAction.jumpSubBack.name);
|
||||
// 读卡器
|
||||
appC.serialCardManage.readerClose();
|
||||
appC.serialCardManage.close();
|
||||
}
|
||||
|
||||
Future<void> _initState() async {
|
||||
EasyLoading.show(
|
||||
status: '初始化资源...',
|
||||
maskType: EasyLoadingMaskType.black,
|
||||
);
|
||||
appSetting = await AppSettingTool.getSysSetting();
|
||||
// 打开副屏
|
||||
SubScreenPlugin.sendMsgToViceScreen(SubScreenAction.jumpSubPage.name);
|
||||
// 组件初始化
|
||||
sysType = SysType.SUPERMARKET;
|
||||
_listenPayTypeSelectCallback();
|
||||
// 获取分类和商品
|
||||
await getClassify();
|
||||
await getProduct();
|
||||
// 清空购物车
|
||||
await _clearShopCard();
|
||||
EasyLoading.dismiss();
|
||||
}
|
||||
|
||||
// |下单|点击购买
|
||||
Future<void> doPay() async {
|
||||
final validShopCar = _validateShopCar();
|
||||
if (!validShopCar) return;
|
||||
// 创建本地订单
|
||||
await createSqlOrder();
|
||||
selectPayTypeDialog();
|
||||
}
|
||||
|
||||
// |下单|点击取消下单
|
||||
Future<void> doCancelPay({bool cancelShop = true}) async {
|
||||
if (cancelShop) await _clearShopCard();
|
||||
sendSubScreen();
|
||||
}
|
||||
|
||||
// 分页
|
||||
Future<void> doPage({int? page}) async {
|
||||
if (page != null) currentPage.value = page;
|
||||
}
|
||||
|
||||
void _listenPayTypeSelectCallback() {
|
||||
final payTypeSelect = Get.find<SelectPayTypeDialogController>();
|
||||
// |支付方式|点击|开始识别|
|
||||
payTypeSelect.onRecognition = () async {};
|
||||
// 识别出用户的回调
|
||||
payTypeSelect.onDiscernUser = (payUser) {
|
||||
if (payUser == null) return;
|
||||
this.payUser.value = payUser;
|
||||
sendSubScreen();
|
||||
};
|
||||
// |支付方式|点击|确定|
|
||||
payTypeSelect.onSubmit = (
|
||||
user,
|
||||
orderType,
|
||||
orderPayType,
|
||||
orderPayDisplayType,
|
||||
qrCode,
|
||||
) async {
|
||||
final log =
|
||||
"|$_tag|回调,识别到用户:|${user.toJson()}|orderType:|$orderType|;orderPayType:|$orderPayType|;orderPayDisplayType|$orderPayDisplayType|;";
|
||||
logger.i(log);
|
||||
this.orderType = orderType;
|
||||
this.orderPayType.value = orderPayType;
|
||||
this.orderPayDisplayType.value = orderPayDisplayType;
|
||||
this.globalQrCode = qrCode;
|
||||
payUser.value = user;
|
||||
final validPayUser = _validatePayUser();
|
||||
if (!validPayUser) return;
|
||||
final validShopCar = _validateShopCar();
|
||||
if (!validShopCar) return;
|
||||
EasyLoading.show(
|
||||
status: '支付中...',
|
||||
maskType: EasyLoadingMaskType.black,
|
||||
);
|
||||
// 最后计算一次额外的价格
|
||||
await _computedAmountMealPrice();
|
||||
await updateSqlOrder();
|
||||
await createApiOrder();
|
||||
_clearShopCard();
|
||||
putOffSendSubScreen();
|
||||
};
|
||||
// |支付方式|点击|取消|
|
||||
payTypeSelect.onCancel = () {};
|
||||
}
|
||||
|
||||
// 计算额外的价格
|
||||
Future<void> _computedAmountMealPrice() async {
|
||||
final price = await getAmountMealPrice(
|
||||
price: totalPrice.value,
|
||||
);
|
||||
if (ObjectUtil.isNotEmpty(price)) {
|
||||
amountMealPrice.value = int.parse(price!.toString());
|
||||
sendSubScreen();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _clearShopCard() async {
|
||||
shopCardList.clear();
|
||||
payUser.value = null;
|
||||
totalPrice.value = 0;
|
||||
amountMealPrice.value = 0;
|
||||
}
|
||||
|
||||
bool _validatePayUser() {
|
||||
bool flag = true;
|
||||
if (ObjectUtil.isEmpty(payUser.value?.walletBalance)) {
|
||||
TtsManage.speak("用户钱包不存在");
|
||||
Toast.error(msg: "校验购物车失败,用户钱包不存在");
|
||||
return false;
|
||||
}
|
||||
if (payUser.value!.walletBalance! < totalPrice.value) {
|
||||
TtsManage.speak("用户余额不足");
|
||||
Toast.error(msg: "校验购物车失败,用户余额不足");
|
||||
return false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool _validateShopCar() {
|
||||
bool flag = false;
|
||||
for (final v in shopCardList) {
|
||||
if (v.productNumber > 0) {
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
Toast.error(msg: "校验购物车失败,未选择商品");
|
||||
return false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
@@ -10,18 +11,20 @@ import 'index.dart';
|
||||
class SupermarketOrderPage extends GetView<SupermarketOrderController> {
|
||||
const SupermarketOrderPage({super.key});
|
||||
|
||||
// **************************************************************************
|
||||
// 头部 start
|
||||
// **************************************************************************
|
||||
|
||||
// 头部
|
||||
Widget _buildHeader(double headerHeight) {
|
||||
final context = Get.context!;
|
||||
final theme = FTheme.of(context);
|
||||
return <Widget>[
|
||||
FIcon(
|
||||
FAssets.icons.chevronLeft,
|
||||
size: theme.typography.xl4.fontSize,
|
||||
)
|
||||
.alignLeft()
|
||||
.width(headerHeight)
|
||||
.onTap(() => Get.offAndToNamed(RouteNames.panel)),
|
||||
appBack(
|
||||
context,
|
||||
height: headerHeight,
|
||||
onTap: () => Get.offAndToNamed(RouteNames.panel),
|
||||
),
|
||||
Obx(
|
||||
() => orderRowClassify(
|
||||
context,
|
||||
@@ -33,11 +36,168 @@ class SupermarketOrderPage extends GetView<SupermarketOrderController> {
|
||||
].toRow();
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// 头部 end
|
||||
// **************************************************************************
|
||||
|
||||
// **************************************************************************
|
||||
// 商品 start
|
||||
// **************************************************************************
|
||||
|
||||
Widget _buildProductItem(
|
||||
BuildContext context, {
|
||||
required List<ProductEntity> productList,
|
||||
required double productSpacing,
|
||||
required Size productSize,
|
||||
String? title = "",
|
||||
}) {
|
||||
return <Widget>[].toColumn();
|
||||
}
|
||||
|
||||
Widget _buildProduct() {
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext _, BoxConstraints constraints) {
|
||||
const spacing = 10;
|
||||
const runSpacing = 10;
|
||||
double maxHeight = constraints.maxHeight;
|
||||
double maxWidth = constraints.maxWidth;
|
||||
double itemWidth = (maxWidth - spacing * 5) / 6;
|
||||
double itemHeight = (maxHeight - (runSpacing + 30) * 3) / 3;
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: controller.productClassifyList.length,
|
||||
itemBuilder: (context, index) {
|
||||
if (ObjectUtil.isEmpty(controller.productClassifyList) ||
|
||||
ObjectUtil.isEmpty(controller.productList)) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final current = controller.productClassifyList[index];
|
||||
final currentStr = controller.classifyList
|
||||
.firstWhereOrNull((v) => v.serviceUniqueCode == current);
|
||||
final currentList = controller.productList
|
||||
.where((i) => i.classifyServiceUniqueCode == current)
|
||||
.toList();
|
||||
if (ObjectUtil.isEmpty(currentList)) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return _buildProductItem(
|
||||
context,
|
||||
productList: currentList,
|
||||
productSpacing: spacing.toDouble(),
|
||||
productSize: Size(itemWidth, itemHeight),
|
||||
title: currentStr?.name,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProductArea() {
|
||||
final context = Get.context!;
|
||||
return <Widget>[
|
||||
_buildProduct().expanded(),
|
||||
Obx(
|
||||
() => appPage(
|
||||
context,
|
||||
pageNo: controller.currentPage.value,
|
||||
pageSize: controller.pageSize.value,
|
||||
total: controller.totalPage.value,
|
||||
onPageChanged: (pageNo) => controller.doPage(page: pageNo),
|
||||
),
|
||||
),
|
||||
].toColumn();
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// 商品 end
|
||||
// **************************************************************************
|
||||
|
||||
// **************************************************************************
|
||||
// 用户 end
|
||||
// **************************************************************************
|
||||
|
||||
Widget _buildUser() {
|
||||
final theme = FTheme.of(Get.context!);
|
||||
return <Widget>[
|
||||
<Widget>[
|
||||
Obx(() {
|
||||
final payUser = controller.payUser.value;
|
||||
return appUserInfo(
|
||||
Get.context!,
|
||||
username: payUser?.username,
|
||||
balance: payUser?.walletBalance,
|
||||
avatar: payUser?.userAvatar,
|
||||
);
|
||||
}).width(400.w).center(),
|
||||
SizedBox(height: 10.h),
|
||||
FDivider(
|
||||
style: theme.dividerStyles.verticalStyle.copyWith(
|
||||
color: theme.colorScheme.primary,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"已选商品",
|
||||
style: theme.typography.xl2,
|
||||
).alignLeft(),
|
||||
].toColumn(),
|
||||
Spacer(),
|
||||
<Widget>[
|
||||
Obx(
|
||||
() => orderAllPrice(
|
||||
Get.context!,
|
||||
totalPrice: controller.totalPrice.value,
|
||||
amountMealPrice: controller.amountMealPrice.value,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20.h),
|
||||
<Widget>[
|
||||
FButton(
|
||||
label: Text(
|
||||
"支付",
|
||||
style: theme.typography.xl.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => controller.doPay(),
|
||||
).flexible(flex: 1),
|
||||
SizedBox(width: 20.w),
|
||||
FButton(
|
||||
style: FButtonStyle.destructive,
|
||||
label: Text(
|
||||
"取消",
|
||||
style: theme.typography.xl.copyWith(
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
onPress: () => controller.doCancelPay(),
|
||||
).flexible(flex: 1),
|
||||
].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween),
|
||||
].toColumn(),
|
||||
].toColumn().padding(vertical: 10.h, horizontal: 10.w);
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// 用户 end
|
||||
// **************************************************************************
|
||||
|
||||
// 主视图
|
||||
Widget _buildView(BuildContext context) {
|
||||
return const Center(
|
||||
child: Text("SupermarketOrderPage"),
|
||||
);
|
||||
final context = Get.context!;
|
||||
final width = context.width;
|
||||
final theme = FTheme.of(context);
|
||||
return <Widget>[
|
||||
_buildProductArea().expanded(),
|
||||
SizedBox(width: 15.w),
|
||||
_buildUser().width(width * 0.25).decorated(
|
||||
border: Border.all(
|
||||
color: theme.colorScheme.primary,
|
||||
width: 1,
|
||||
),
|
||||
borderRadius: theme.style.borderRadius,
|
||||
),
|
||||
].toRow().marginOnly(bottom: 20.h);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
Reference in new issue
Block a user