From 88e73ad950eac363e5da8da73dc27ff4fdff5633 Mon Sep 17 00:00:00 2001 From: dzc <2388224167@qq.com> Date: Tue, 11 Mar 2025 18:04:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E4=BA=A4=E6=98=93=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E3=80=81=E6=97=A5=E6=9C=9F=E7=BB=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/app.dart | 3 + lib/common/models/api/product_api_models.dart | 4 + .../models/api/product_api_models.g.dart | 4 + .../models/database/database_enum_models.dart | 2 +- .../models/database/database_models.dart | 23 ++- .../models/database/database_models.g.dart | 73 ++++---- .../services/database/dao/order_dao.dart | 4 +- .../services/database/dao/product_dao.dart | 14 +- lib/common/services/database/database.g.dart | 26 +-- .../database/entity/product_entity.dart | 6 +- .../database/entity/product_entity.g.dart | 4 + lib/common/utils/app/app_file_tool.dart | 56 ++++++- lib/common/utils/app/control/app_control.dart | 2 - .../utils/app/control/app_theme_control.dart | 6 +- lib/common/utils/sync/sync_product_tool.dart | 5 + lib/common/widgets/app/app_date_picker.dart | 158 +++++++++++++++++- .../widgets/app/app_message_dialog.dart | 13 +- lib/common/widgets/app/app_page.dart | 2 +- .../widgets/order/mixin/order_mixin.dart | 3 - .../widgets/order/select_pay_type_dialog.dart | 122 +++++++++----- lib/pages/canteen_product/controller.dart | 31 ++-- lib/pages/canteen_product/view.dart | 10 +- lib/pages/order_history/controller.dart | 83 +++++---- lib/pages/order_history/view.dart | 18 +- lib/pages/panel/controller.dart | 2 +- lib/pages/setting/controller.dart | 87 ++++++++-- lib/pages/setting/view.dart | 56 +++++-- lib/pages/setting/widgets/setting_backup.dart | 8 + lib/pages/setting/widgets/setting_pay.dart | 15 +- .../setting/widgets/setting_product.dart | 93 +++++------ pubspec.lock | 16 ++ pubspec.yaml | 2 + 32 files changed, 672 insertions(+), 279 deletions(-) diff --git a/lib/app.dart b/lib/app.dart index 9d33c86..30db278 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -39,6 +39,9 @@ class MainApp extends StatelessWidget { getPages: RoutePages.list, enableLog: true, debugShowCheckedModeBanner: false, + locale: const Locale('zh', 'CN'), + localizationsDelegates: FLocalizations.localizationsDelegates, + supportedLocales: FLocalizations.supportedLocales, builder: EasyLoading.init( builder: (context, child) => FTheme( data: themeData, diff --git a/lib/common/models/api/product_api_models.dart b/lib/common/models/api/product_api_models.dart index 97ba575..518b8e7 100644 --- a/lib/common/models/api/product_api_models.dart +++ b/lib/common/models/api/product_api_models.dart @@ -72,6 +72,9 @@ class ServiceProduct { /// 用餐类型,早餐、中餐、晚餐 String? categoryType; + /// 菜品上架日期 + DateTime? saleDate; + ServiceProduct({ this.id, this.spuId, @@ -81,6 +84,7 @@ class ServiceProduct { this.hourType, this.sort, this.categoryType, + this.saleDate, }); factory ServiceProduct.fromJson(Map json) => diff --git a/lib/common/models/api/product_api_models.g.dart b/lib/common/models/api/product_api_models.g.dart index 6e04015..fcfd933 100644 --- a/lib/common/models/api/product_api_models.g.dart +++ b/lib/common/models/api/product_api_models.g.dart @@ -38,6 +38,9 @@ ServiceProduct _$ServiceProductFromJson(Map json) => hourType: JsonTool.anyToString(json['hourType']), sort: (json['sort'] as num?)?.toInt(), categoryType: json['categoryType'] as String?, + saleDate: json['saleDate'] == null + ? null + : DateTime.parse(json['saleDate'] as String), )..price = (json['price'] as num?)?.toInt(); Map _$ServiceProductToJson(ServiceProduct instance) => @@ -51,4 +54,5 @@ Map _$ServiceProductToJson(ServiceProduct instance) => 'price': instance.price, 'sort': instance.sort, 'categoryType': instance.categoryType, + 'saleDate': instance.saleDate?.toIso8601String(), }; diff --git a/lib/common/models/database/database_enum_models.dart b/lib/common/models/database/database_enum_models.dart index aca912a..8700a67 100644 --- a/lib/common/models/database/database_enum_models.dart +++ b/lib/common/models/database/database_enum_models.dart @@ -54,7 +54,7 @@ enum OrderPayType implements BaseEnum { /// 订单状态 enum OrderStatus implements BaseEnum { // 查询使用 - total("-1", "未付款"), + total("-1", "全部"), nonePay("1", "未付款"), pay("5", "已付款"), diff --git a/lib/common/models/database/database_models.dart b/lib/common/models/database/database_models.dart index 648603e..3a4e9aa 100644 --- a/lib/common/models/database/database_models.dart +++ b/lib/common/models/database/database_models.dart @@ -88,6 +88,18 @@ class SysSetting extends Equatable { /// 长链接重连 DateTime? mqSyncTime; + /// 商品时间段类型 + ProductHourType? hourType; + + // 全局字体大小 + SettingGlobalFontSize? globalFontSize; + + // 使用支付方式 + List? usePayDisplayType; + + // 默认支付方式 + OrderPayDisplayType? defaultPayDisplayType; + SysSetting({ required this.sysType, this.androidId, @@ -133,6 +145,10 @@ class SysSetting extends Equatable { supermarketProductSyncTime?.millisecondsSinceEpoch, offlineOrderSyncTime?.millisecondsSinceEpoch, mqSyncTime?.millisecondsSinceEpoch, + hourType, + globalFontSize, + usePayDisplayType, + defaultPayDisplayType, ]; } @@ -164,12 +180,6 @@ class UserSetting extends Equatable { /// end 服务端信息 end - /// 商品时间段类型 - ProductHourType? hourType; - - // 全局字体大小 - SettingGlobalFontSize? globalFontSize; - UserSetting({ this.username, this.password, @@ -189,7 +199,6 @@ class UserSetting extends Equatable { accessToken, refreshToken, expiresTime, - hourType, ]; } diff --git a/lib/common/models/database/database_models.g.dart b/lib/common/models/database/database_models.g.dart index 08d5cb4..972daec 100644 --- a/lib/common/models/database/database_models.g.dart +++ b/lib/common/models/database/database_models.g.dart @@ -49,7 +49,16 @@ SysSetting _$SysSettingFromJson(Map json) => SysSetting( : DateTime.parse(json['offlineOrderSyncTime'] as String) ..mqSyncTime = json['mqSyncTime'] == null ? null - : DateTime.parse(json['mqSyncTime'] as String); + : DateTime.parse(json['mqSyncTime'] as String) + ..hourType = + $enumDecodeNullable(_$ProductHourTypeEnumMap, json['hourType']) + ..globalFontSize = $enumDecodeNullable( + _$SettingGlobalFontSizeEnumMap, json['globalFontSize']) + ..usePayDisplayType = (json['usePayDisplayType'] as List?) + ?.map((e) => $enumDecode(_$OrderPayDisplayTypeEnumMap, e)) + .toList() + ..defaultPayDisplayType = $enumDecodeNullable( + _$OrderPayDisplayTypeEnumMap, json['defaultPayDisplayType']); Map _$SysSettingToJson(SysSetting instance) => { @@ -84,6 +93,13 @@ Map _$SysSettingToJson(SysSetting instance) => instance.supermarketProductSyncTime?.toIso8601String(), 'offlineOrderSyncTime': instance.offlineOrderSyncTime?.toIso8601String(), 'mqSyncTime': instance.mqSyncTime?.toIso8601String(), + 'hourType': _$ProductHourTypeEnumMap[instance.hourType], + 'globalFontSize': _$SettingGlobalFontSizeEnumMap[instance.globalFontSize], + 'usePayDisplayType': instance.usePayDisplayType + ?.map((e) => _$OrderPayDisplayTypeEnumMap[e]!) + .toList(), + 'defaultPayDisplayType': + _$OrderPayDisplayTypeEnumMap[instance.defaultPayDisplayType], }; const _$SysTypeEnumMap = { @@ -91,33 +107,6 @@ const _$SysTypeEnumMap = { SysType.canteen: 'canteen', }; -UserSetting _$UserSettingFromJson(Map json) => UserSetting( - username: json['username'] as String?, - password: json['password'] as String?, - ) - ..sysType = $enumDecodeNullable(_$SysTypeEnumMap, json['sysType']) - ..userId = (json['userId'] as num?)?.toInt() - ..accessToken = json['accessToken'] as String? - ..refreshToken = json['refreshToken'] as String? - ..expiresTime = (json['expiresTime'] as num?)?.toInt() - ..hourType = - $enumDecodeNullable(_$ProductHourTypeEnumMap, json['hourType']) - ..globalFontSize = $enumDecodeNullable( - _$SettingGlobalFontSizeEnumMap, json['globalFontSize']); - -Map _$UserSettingToJson(UserSetting instance) => - { - 'username': instance.username, - 'password': instance.password, - 'sysType': _$SysTypeEnumMap[instance.sysType], - 'userId': instance.userId, - 'accessToken': instance.accessToken, - 'refreshToken': instance.refreshToken, - 'expiresTime': instance.expiresTime, - 'hourType': _$ProductHourTypeEnumMap[instance.hourType], - 'globalFontSize': _$SettingGlobalFontSizeEnumMap[instance.globalFontSize], - }; - const _$ProductHourTypeEnumMap = { ProductHourType.all: 'all', ProductHourType.morning: 'morning', @@ -132,6 +121,34 @@ const _$SettingGlobalFontSizeEnumMap = { SettingGlobalFontSize.xl4: 'xl4', }; +const _$OrderPayDisplayTypeEnumMap = { + OrderPayDisplayType.qrCode: 'qrCode', + OrderPayDisplayType.walletCard: 'walletCard', + OrderPayDisplayType.face: 'face', + OrderPayDisplayType.cash: 'cash', +}; + +UserSetting _$UserSettingFromJson(Map json) => UserSetting( + username: json['username'] as String?, + password: json['password'] as String?, + ) + ..sysType = $enumDecodeNullable(_$SysTypeEnumMap, json['sysType']) + ..userId = (json['userId'] as num?)?.toInt() + ..accessToken = json['accessToken'] as String? + ..refreshToken = json['refreshToken'] as String? + ..expiresTime = (json['expiresTime'] as num?)?.toInt(); + +Map _$UserSettingToJson(UserSetting instance) => + { + 'username': instance.username, + 'password': instance.password, + 'sysType': _$SysTypeEnumMap[instance.sysType], + 'userId': instance.userId, + 'accessToken': instance.accessToken, + 'refreshToken': instance.refreshToken, + 'expiresTime': instance.expiresTime, + }; + CanteenExtraPriceSetting _$CanteenExtraPriceSettingFromJson( Map json) => CanteenExtraPriceSetting( diff --git a/lib/common/services/database/dao/order_dao.dart b/lib/common/services/database/dao/order_dao.dart index 98962f5..e53ccc6 100644 --- a/lib/common/services/database/dao/order_dao.dart +++ b/lib/common/services/database/dao/order_dao.dart @@ -33,7 +33,7 @@ abstract class OrderDao { (:status == "-1" OR status = :status) AND (:sysType = '-1' OR sysType = :sysType) AND (:hourType = '-1' OR hourType = :hourType) AND - createTime >= :startCreateOrderTime AND createTime <= :endCreateOrderTime + strftime('%Y-%m-%d', createTime) >= strftime('%Y-%m-%d', :startCreateOrderTime) AND strftime('%Y-%m-%d', createTime) <= strftime('%Y-%m-%d', :endCreateOrderTime) ORDER BY createTime DESC LIMIT :pageSize OFFSET :offset ''') @@ -53,7 +53,7 @@ abstract class OrderDao { (:status == "-1" OR status = :status) AND (:sysType = '-1' OR sysType = :sysType) AND (:hourType = '-1' OR hourType = :hourType) AND - createTime >= :startCreateOrderTime AND createTime <= :endCreateOrderTime + strftime('%Y-%m-%d', createTime) >= strftime('%Y-%m-%d', :startCreateOrderTime) AND strftime('%Y-%m-%d', createTime) <= strftime('%Y-%m-%d', :endCreateOrderTime) ''') Future count( String status, diff --git a/lib/common/services/database/dao/product_dao.dart b/lib/common/services/database/dao/product_dao.dart index bb59977..de8c517 100644 --- a/lib/common/services/database/dao/product_dao.dart +++ b/lib/common/services/database/dao/product_dao.dart @@ -19,6 +19,7 @@ abstract class ProductDao { final placeholders = List.generate(codes.length, (index) => '?').join(', '); final sql = ''' UPDATE product SET delFlag = 1 WHERE serviceUniqueCode IN ($placeholders) + AND (sysType = 'canteen' OR strftime('%Y-%m-%d', saleDate) = strftime('%Y-%m-%d', 'now', 'localtime')) '''; return await database.rawUpdate(sql, [...codes]); } @@ -38,7 +39,9 @@ abstract class ProductDao { @Query(""" UPDATE product SET isDefault = :isDefault WHERE - delFlag = 0 AND serviceUniqueCode = :uniqueCode AND hourType = :hourType + delFlag = 0 + AND serviceUniqueCode = :uniqueCode AND hourType = :hourType + AND (sysType = 'canteen' OR strftime('%Y-%m-%d', saleDate) = strftime('%Y-%m-%d', 'now', 'localtime')) """) Future edit(bool isDefault, String uniqueCode, String hourType); @@ -51,6 +54,7 @@ abstract class ProductDao { delFlag = 0 AND (:sysType = '-1' OR sysType = :sysType) AND (:hourType = '-1' OR INSTR(',' || hourType || ',', ',' || :hourType || ',') > 0) + AND (:sysType = 'canteen' OR strftime('%Y-%m-%d', saleDate) = strftime('%Y-%m-%d', 'now', 'localtime')) """) Future getCount( String sysType, @@ -88,11 +92,12 @@ abstract class ProductDao { product.delFlag = 0 AND (:classifyServiceUniqueCode = '-1' OR product.classifyServiceUniqueCode = :classifyServiceUniqueCode) AND (:hourType = '-1' OR INSTR(',' || product.hourType || ',', ',' || :hourType || ',') > 0) AND - (:sysType = '-1' OR product.sysType = :sysType) + (:sysType = '-1' OR product.sysType = :sysType) AND + (:sysType = 'canteen' OR strftime('%Y-%m-%d', product.saleDate) = strftime('%Y-%m-%d', 'now', 'localtime')) ORDER BY classify.sort, classify.id, product.price LIMIT :pageSize OFFSET :offset ''') - Future> getCurrentDayAllPage( + Future> getAllPage( String classifyServiceUniqueCode, String hourType, String sysType, @@ -103,10 +108,11 @@ abstract class ProductDao { @Query(''' SELECT * FROM product WHERE - product.delFlag = 0 + delFlag = 0 AND isDefault = 1 AND (:sysType = '-1' OR sysType = :sysType) AND (:hourType = '-1' OR hourType = :hourType) + AND (:sysType = 'canteen' OR strftime('%Y-%m-%d', saleDate) = strftime('%Y-%m-%d', 'now', 'localtime')) ''') Future> getDefault(String sysType, String hourType); } diff --git a/lib/common/services/database/database.g.dart b/lib/common/services/database/database.g.dart index d8c59fd..7dbdeba 100644 --- a/lib/common/services/database/database.g.dart +++ b/lib/common/services/database/database.g.dart @@ -112,7 +112,7 @@ class _$AppDatabase extends AppDatabase { await database.execute( 'CREATE TABLE IF NOT EXISTS `order_record` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `uniqueCode` TEXT NOT NULL, `serviceUniqueCode` TEXT NOT NULL, `sysType` TEXT NOT NULL, `userCode` TEXT NOT NULL, `username` TEXT, `hourType` TEXT, `price` INTEGER NOT NULL, `extraPrice` INTEGER NOT NULL, `payPrice` INTEGER NOT NULL, `walletId` TEXT, `orderSourceTypeId` TEXT, `type` TEXT NOT NULL, `status` TEXT NOT NULL, `payType` TEXT NOT NULL, `productDesc` TEXT, `count` INTEGER NOT NULL, `weight` REAL NOT NULL, `payTime` TEXT, `createTime` TEXT NOT NULL)'); await database.execute( - 'CREATE TABLE IF NOT EXISTS `product` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `serviceUniqueCode` TEXT NOT NULL, `sysType` TEXT NOT NULL, `classifyServiceUniqueCode` TEXT NOT NULL, `hourType` INTEGER, `name` TEXT NOT NULL, `price` INTEGER NOT NULL, `image` TEXT, `isDefault` INTEGER NOT NULL, `status` INTEGER NOT NULL, `sort` INTEGER NOT NULL, `createTime` TEXT NOT NULL, `updateTime` TEXT NOT NULL, `delFlag` INTEGER NOT NULL)'); + 'CREATE TABLE IF NOT EXISTS `product` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `serviceUniqueCode` TEXT NOT NULL, `sysType` TEXT NOT NULL, `classifyServiceUniqueCode` TEXT NOT NULL, `hourType` INTEGER, `saleDate` TEXT, `name` TEXT NOT NULL, `price` INTEGER NOT NULL, `image` TEXT, `isDefault` INTEGER NOT NULL, `status` INTEGER NOT NULL, `sort` INTEGER NOT NULL, `createTime` TEXT NOT NULL, `updateTime` TEXT NOT NULL, `delFlag` INTEGER NOT NULL)'); await database.execute( 'CREATE TABLE IF NOT EXISTS `shop_card` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `orderId` INTEGER NOT NULL, `productServiceUniqueCode` TEXT NOT NULL, `productName` TEXT NOT NULL, `productPic` TEXT NOT NULL, `productPrice` INTEGER NOT NULL, `productNumber` INTEGER NOT NULL, `productWidget` REAL NOT NULL, `totalPrice` INTEGER NOT NULL)'); await database.execute( @@ -287,7 +287,7 @@ class _$OrderDao extends OrderDao { String hourType, ) async { return _queryAdapter.queryList( - 'SELECT * FROM order_record WHERE (?1 == \"-1\" OR status = ?1) AND (?6 = \'-1\' OR sysType = ?6) AND (?7 = \'-1\' OR hourType = ?7) AND createTime >= ?2 AND createTime <= ?3 ORDER BY createTime DESC LIMIT ?4 OFFSET ?5', + 'SELECT * FROM order_record WHERE (?1 == \"-1\" OR status = ?1) AND (?6 = \'-1\' OR sysType = ?6) AND (?7 = \'-1\' OR hourType = ?7) AND strftime(\'%Y-%m-%d\', createTime) >= strftime(\'%Y-%m-%d\', ?2) AND strftime(\'%Y-%m-%d\', createTime) <= strftime(\'%Y-%m-%d\', ?3) ORDER BY createTime DESC LIMIT ?4 OFFSET ?5', mapper: (Map row) => OrderEntity( id: row['id'] as int?, uniqueCode: row['uniqueCode'] as String, @@ -329,7 +329,7 @@ class _$OrderDao extends OrderDao { String hourType, ) async { return _queryAdapter.query( - 'SELECT COUNT(0) FROM order_record WHERE (?1 == \"-1\" OR status = ?1) AND (?4 = \'-1\' OR sysType = ?4) AND (?5 = \'-1\' OR hourType = ?5) AND createTime >= ?2 AND createTime <= ?3', + 'SELECT COUNT(0) FROM order_record WHERE (?1 == \"-1\" OR status = ?1) AND (?4 = \'-1\' OR sysType = ?4) AND (?5 = \'-1\' OR hourType = ?5) AND strftime(\'%Y-%m-%d\', createTime) >= strftime(\'%Y-%m-%d\', ?2) AND strftime(\'%Y-%m-%d\', createTime) <= strftime(\'%Y-%m-%d\', ?3)', mapper: (Map row) => row.values.first as int, arguments: [ status, @@ -452,6 +452,7 @@ class _$ProductDao extends ProductDao { 'sysType': _sysTypeConverter.encode(item.sysType), 'classifyServiceUniqueCode': item.classifyServiceUniqueCode, 'hourType': item.hourType?.index, + 'saleDate': _dateTimeEmptyConverter.encode(item.saleDate), 'name': item.name, 'price': item.price, 'image': item.image, @@ -472,6 +473,7 @@ class _$ProductDao extends ProductDao { 'sysType': _sysTypeConverter.encode(item.sysType), 'classifyServiceUniqueCode': item.classifyServiceUniqueCode, 'hourType': item.hourType?.index, + 'saleDate': _dateTimeEmptyConverter.encode(item.saleDate), 'name': item.name, 'price': item.price, 'image': item.image, @@ -492,6 +494,7 @@ class _$ProductDao extends ProductDao { 'sysType': _sysTypeConverter.encode(item.sysType), 'classifyServiceUniqueCode': item.classifyServiceUniqueCode, 'hourType': item.hourType?.index, + 'saleDate': _dateTimeEmptyConverter.encode(item.saleDate), 'name': item.name, 'price': item.price, 'image': item.image, @@ -529,7 +532,7 @@ class _$ProductDao extends ProductDao { String hourType, ) async { await _queryAdapter.queryNoReturn( - 'UPDATE product SET isDefault = ?1 WHERE delFlag = 0 AND serviceUniqueCode = ?2 AND hourType = ?3', + 'UPDATE product SET isDefault = ?1 WHERE delFlag = 0 AND serviceUniqueCode = ?2 AND hourType = ?3 AND (sysType = \'canteen\' OR strftime(\'%Y-%m-%d\', saleDate) = strftime(\'%Y-%m-%d\', \'now\', \'localtime\'))', arguments: [_boolConverter.encode(isDefault), uniqueCode, hourType]); } @@ -539,7 +542,7 @@ class _$ProductDao extends ProductDao { String hourType, ) async { return _queryAdapter.query( - 'SELECT DISTINCT COUNT(0) FROM product WHERE delFlag = 0 AND (?1 = \'-1\' OR sysType = ?1) AND (?2 = \'-1\' OR INSTR(\',\' || hourType || \',\', \',\' || ?2 || \',\') > 0)', + 'SELECT DISTINCT COUNT(0) FROM product WHERE delFlag = 0 AND (?1 = \'-1\' OR sysType = ?1) AND (?2 = \'-1\' OR INSTR(\',\' || hourType || \',\', \',\' || ?2 || \',\') > 0) AND (?1 = \'canteen\' OR strftime(\'%Y-%m-%d\', saleDate) = strftime(\'%Y-%m-%d\', \'now\', \'localtime\'))', mapper: (Map row) => row.values.first as int, arguments: [sysType, hourType]); } @@ -557,6 +560,7 @@ class _$ProductDao extends ProductDao { hourType: row['hourType'] == null ? null : ProductHourType.values[row['hourType'] as int], + saleDate: _dateTimeEmptyConverter.decode(row['saleDate'] as String), name: row['name'] as String, price: row['price'] as int, image: row['image'] as String?, @@ -577,12 +581,12 @@ class _$ProductDao extends ProductDao { ) async { return _queryAdapter.queryList( 'SELECT product.* FROM product LEFT JOIN classify ON product.classifyServiceUniqueCode = classify.serviceUniqueCode WHERE product.delFlag = 0 AND (?1 = \'-1\' OR product.classifyServiceUniqueCode = ?1) AND (?2 = \'-1\' OR INSTR(\',\' || hourType || \',\', \',\' || ?2 || \',\') > 0) AND (?3 = \'-1\' OR product.sysType = ?3) ORDER BY classify.sort, product.price', - mapper: (Map row) => ProductEntity(id: row['id'] as int?, serviceUniqueCode: row['serviceUniqueCode'] as String, sysType: _sysTypeConverter.decode(row['sysType'] as String), classifyServiceUniqueCode: row['classifyServiceUniqueCode'] as String, hourType: row['hourType'] == null ? null : ProductHourType.values[row['hourType'] as int], name: row['name'] as String, price: row['price'] as int, image: row['image'] as String?, isDefault: _boolConverter.decode(row['isDefault'] as int), status: row['status'] as int, sort: row['sort'] as int, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String), delFlag: _boolConverter.decode(row['delFlag'] as int)), + mapper: (Map row) => ProductEntity(id: row['id'] as int?, serviceUniqueCode: row['serviceUniqueCode'] as String, sysType: _sysTypeConverter.decode(row['sysType'] as String), classifyServiceUniqueCode: row['classifyServiceUniqueCode'] as String, hourType: row['hourType'] == null ? null : ProductHourType.values[row['hourType'] as int], saleDate: _dateTimeEmptyConverter.decode(row['saleDate'] as String), name: row['name'] as String, price: row['price'] as int, image: row['image'] as String?, isDefault: _boolConverter.decode(row['isDefault'] as int), status: row['status'] as int, sort: row['sort'] as int, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String), delFlag: _boolConverter.decode(row['delFlag'] as int)), arguments: [classifyServiceUniqueCode, hourType, sysType]); } @override - Future> getCurrentDayAllPage( + Future> getAllPage( String classifyServiceUniqueCode, String hourType, String sysType, @@ -590,8 +594,8 @@ class _$ProductDao extends ProductDao { int offset, ) async { return _queryAdapter.queryList( - 'SELECT product.* FROM product LEFT JOIN classify ON product.classifyServiceUniqueCode = classify.serviceUniqueCode WHERE product.delFlag = 0 AND (?1 = \'-1\' OR product.classifyServiceUniqueCode = ?1) AND (?2 = \'-1\' OR INSTR(\',\' || product.hourType || \',\', \',\' || ?2 || \',\') > 0) AND (?3 = \'-1\' OR product.sysType = ?3) ORDER BY classify.sort, classify.id, product.price LIMIT ?4 OFFSET ?5', - mapper: (Map row) => ProductEntity(id: row['id'] as int?, serviceUniqueCode: row['serviceUniqueCode'] as String, sysType: _sysTypeConverter.decode(row['sysType'] as String), classifyServiceUniqueCode: row['classifyServiceUniqueCode'] as String, hourType: row['hourType'] == null ? null : ProductHourType.values[row['hourType'] as int], name: row['name'] as String, price: row['price'] as int, image: row['image'] as String?, isDefault: _boolConverter.decode(row['isDefault'] as int), status: row['status'] as int, sort: row['sort'] as int, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String), delFlag: _boolConverter.decode(row['delFlag'] as int)), + 'SELECT product.* FROM product LEFT JOIN classify ON product.classifyServiceUniqueCode = classify.serviceUniqueCode WHERE product.delFlag = 0 AND (?1 = \'-1\' OR product.classifyServiceUniqueCode = ?1) AND (?2 = \'-1\' OR INSTR(\',\' || product.hourType || \',\', \',\' || ?2 || \',\') > 0) AND (?3 = \'-1\' OR product.sysType = ?3) AND (?3 = \'canteen\' OR strftime(\'%Y-%m-%d\', product.saleDate) = strftime(\'%Y-%m-%d\', \'now\', \'localtime\')) ORDER BY classify.sort, classify.id, product.price LIMIT ?4 OFFSET ?5', + mapper: (Map row) => ProductEntity(id: row['id'] as int?, serviceUniqueCode: row['serviceUniqueCode'] as String, sysType: _sysTypeConverter.decode(row['sysType'] as String), classifyServiceUniqueCode: row['classifyServiceUniqueCode'] as String, hourType: row['hourType'] == null ? null : ProductHourType.values[row['hourType'] as int], saleDate: _dateTimeEmptyConverter.decode(row['saleDate'] as String), name: row['name'] as String, price: row['price'] as int, image: row['image'] as String?, isDefault: _boolConverter.decode(row['isDefault'] as int), status: row['status'] as int, sort: row['sort'] as int, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String), delFlag: _boolConverter.decode(row['delFlag'] as int)), arguments: [ classifyServiceUniqueCode, hourType, @@ -607,8 +611,8 @@ class _$ProductDao extends ProductDao { String hourType, ) async { return _queryAdapter.queryList( - 'SELECT * FROM product WHERE product.delFlag = 0 AND isDefault = 1 AND (?1 = \'-1\' OR sysType = ?1) AND (?2 = \'-1\' OR hourType = ?2)', - mapper: (Map row) => ProductEntity(id: row['id'] as int?, serviceUniqueCode: row['serviceUniqueCode'] as String, sysType: _sysTypeConverter.decode(row['sysType'] as String), classifyServiceUniqueCode: row['classifyServiceUniqueCode'] as String, hourType: row['hourType'] == null ? null : ProductHourType.values[row['hourType'] as int], name: row['name'] as String, price: row['price'] as int, image: row['image'] as String?, isDefault: _boolConverter.decode(row['isDefault'] as int), status: row['status'] as int, sort: row['sort'] as int, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String), delFlag: _boolConverter.decode(row['delFlag'] as int)), + 'SELECT * FROM product WHERE delFlag = 0 AND isDefault = 1 AND (?1 = \'-1\' OR sysType = ?1) AND (?2 = \'-1\' OR hourType = ?2) AND (?1 = \'canteen\' OR strftime(\'%Y-%m-%d\', saleDate) = strftime(\'%Y-%m-%d\', \'now\', \'localtime\'))', + mapper: (Map row) => ProductEntity(id: row['id'] as int?, serviceUniqueCode: row['serviceUniqueCode'] as String, sysType: _sysTypeConverter.decode(row['sysType'] as String), classifyServiceUniqueCode: row['classifyServiceUniqueCode'] as String, hourType: row['hourType'] == null ? null : ProductHourType.values[row['hourType'] as int], saleDate: _dateTimeEmptyConverter.decode(row['saleDate'] as String), name: row['name'] as String, price: row['price'] as int, image: row['image'] as String?, isDefault: _boolConverter.decode(row['isDefault'] as int), status: row['status'] as int, sort: row['sort'] as int, createTime: _dateTimeConverter.decode(row['createTime'] as String), updateTime: _dateTimeConverter.decode(row['updateTime'] as String), delFlag: _boolConverter.decode(row['delFlag'] as int)), arguments: [sysType, hourType]); } diff --git a/lib/common/services/database/entity/product_entity.dart b/lib/common/services/database/entity/product_entity.dart index 1609e4d..00fd0ef 100644 --- a/lib/common/services/database/entity/product_entity.dart +++ b/lib/common/services/database/entity/product_entity.dart @@ -25,6 +25,9 @@ class ProductEntity extends Equatable { /// 菜品时间类型 ProductHourType? hourType; + /// 菜品上架日期 + DateTime? saleDate; + /// 商品名 String name; @@ -57,7 +60,8 @@ class ProductEntity extends Equatable { required this.serviceUniqueCode, required this.sysType, required this.classifyServiceUniqueCode, - required this.hourType, + this.hourType, + this.saleDate, required this.name, required this.price, this.image, diff --git a/lib/common/services/database/entity/product_entity.g.dart b/lib/common/services/database/entity/product_entity.g.dart index 4307757..be7c2c1 100644 --- a/lib/common/services/database/entity/product_entity.g.dart +++ b/lib/common/services/database/entity/product_entity.g.dart @@ -13,6 +13,9 @@ ProductEntity _$ProductEntityFromJson(Map json) => sysType: $enumDecode(_$SysTypeEnumMap, json['sysType']), classifyServiceUniqueCode: json['classifyServiceUniqueCode'] as String, hourType: $enumDecodeNullable(_$ProductHourTypeEnumMap, json['hourType']), + saleDate: json['saleDate'] == null + ? null + : DateTime.parse(json['saleDate'] as String), name: json['name'] as String, price: (json['price'] as num).toInt(), image: json['image'] as String?, @@ -31,6 +34,7 @@ Map _$ProductEntityToJson(ProductEntity instance) => 'sysType': _$SysTypeEnumMap[instance.sysType]!, 'classifyServiceUniqueCode': instance.classifyServiceUniqueCode, 'hourType': _$ProductHourTypeEnumMap[instance.hourType], + 'saleDate': instance.saleDate?.toIso8601String(), 'name': instance.name, 'price': instance.price, 'image': instance.image, diff --git a/lib/common/utils/app/app_file_tool.dart b/lib/common/utils/app/app_file_tool.dart index ea82e12..8579232 100644 --- a/lib/common/utils/app/app_file_tool.dart +++ b/lib/common/utils/app/app_file_tool.dart @@ -4,14 +4,15 @@ import 'package:common_utils/common_utils.dart'; import 'package:external_path/external_path.dart'; import 'package:pj_supermarket_cloud/common/index.dart'; +import 'package:sqflite/sqflite.dart'; abstract class AppFileTool { static const _tag = "app文件工具"; static const _baseDir = "pj"; static const _baseBackupDir = "backup"; - static const _backupDatabaseDir = ".database"; + static const _backupDatabaseDir = "database"; static const _backupLoggerDir = "logger"; - static const _backupFaceDir = ".face"; + static const _backupFaceDir = "face"; /// 检查并创建目录 static Future _checkAndcreateDir(String dir) async { @@ -53,14 +54,14 @@ abstract class AppFileTool { /// 创建数据库文件备份地址 static Future getDatabaseBackupPath() async { - String backupDir = await getExternalPath(); + String backupDir = await getExternalPath(backupExternalPath: false); String dir = "$backupDir/$_baseBackupDir/$_backupDatabaseDir"; DateTime now = DateTime.now(); int year = now.year; int month = now.month; int day = now.day; dir = "$dir/$year-$month"; - dir = await _checkAndcreateDir(backupDir); + dir = await _checkAndcreateDir(dir); dir = "$dir/$day.db"; return dir; } @@ -104,13 +105,18 @@ abstract class AppFileTool { logger.e("|$_tag|备份sql文件失败,无效的sourcePath路径path:|$sourcePath|"); return false; } + final databaseFilePath = "$sourcePath${Constants.databaseName}"; + if (await File(databaseFilePath).exists()) { + logger.w("|$_tag|备份sql文件失败,无效的sourcePath路径path|$databaseFilePath|"); + return false; + } String? backupPath = await getDatabaseBackupPath(); if (ObjectUtil.isEmpty(backupPath)) { logger.e("|$_tag|备份sql文件失败,无效的backupPath路径path:|$backupPath|"); return false; } try { - await File("$sourcePath/${Constants.databaseName}").copy(backupPath!); + await File(databaseFilePath).copy(backupPath!); return true; } catch (e, stack) { logger.e("|$_tag|备份sql文件失败,意外的错误error|$e|stack|$stack|"); @@ -118,5 +124,45 @@ abstract class AppFileTool { } } + // 如果没有数据库将最新的数据库移动为使用的数据库 + static Future useLastBackDatabase() async { + final databasePath = getDatabasesPath(); + final databaseFilePath = "$databasePath${Constants.databaseName}"; + if (await File(databaseFilePath).exists()) { + logger.w("|$_tag|替换数据库错误,数据库文件已存在path|$databaseFilePath|"); + return; + } + final path = await getDatabaseBackupPath(); + if (ObjectUtil.isEmpty(path)) { + logger.w("|$_tag|替换数据库错误,无效的数据库备份path|$path|"); + return; + } + final dir = Directory(path!).parent; + if (!await dir.exists()) { + logger.w("|$_tag|替换数据库错误,无效的数据库备份目录path|$dir|"); + return; + } + final files = dir.listSync(); + files.sort( + (a, b) => b.statSync().modified.compareTo(a.statSync().modified), + ); + if (files.isEmpty) { + logger.w("|$_tag|替换数据库错误,数据库备份目录为空path|$dir|"); + return; + } + final lastFile = files.first; + try { + if (lastFile is File) { + final sourcePath = lastFile.path; + await File(sourcePath).copy(databaseFilePath); + logger.i( + "|$_tag|替换数据库成功,sourcePath|$sourcePath|targetPath|$databaseFilePath|", + ); + } + } catch (e, stack) { + logger.e("|$_tag|替换数据库错误,意外的错误error|$e|stack|$stack|"); + } + } + // 备份日志 } diff --git a/lib/common/utils/app/control/app_control.dart b/lib/common/utils/app/control/app_control.dart index 0980fb5..05faaae 100644 --- a/lib/common/utils/app/control/app_control.dart +++ b/lib/common/utils/app/control/app_control.dart @@ -31,8 +31,6 @@ class AppControl extends GetxController { // 是否有网络 RxBool isNetwork = RxBool(false); - Rx hourType = Rx(ProductHourType.morning); - @override void onClose() { super.onClose(); diff --git a/lib/common/utils/app/control/app_theme_control.dart b/lib/common/utils/app/control/app_theme_control.dart index 65940f0..0f833ad 100644 --- a/lib/common/utils/app/control/app_theme_control.dart +++ b/lib/common/utils/app/control/app_theme_control.dart @@ -16,9 +16,9 @@ class AppThemeControl extends GetxController { } Future initAsync() async { - final userInfo = await AppSettingTool.getUserSetting(); - if (userInfo.globalFontSize != null) { - sizeScalar.value = userInfo.globalFontSize!.fontSize; + final appSetting = await AppSettingTool.getSysSetting(); + if (appSetting.globalFontSize != null) { + sizeScalar.value = appSetting.globalFontSize!.fontSize; } } diff --git a/lib/common/utils/sync/sync_product_tool.dart b/lib/common/utils/sync/sync_product_tool.dart index c554cad..f0c51dd 100644 --- a/lib/common/utils/sync/sync_product_tool.dart +++ b/lib/common/utils/sync/sync_product_tool.dart @@ -146,6 +146,7 @@ abstract class SyncProductTool { DateTime.now(), format: DateFormats.y_mo_d, ); + final dayStr = DateUtil.getDateTime(day); final pa = { "day": day, "hourType": null, @@ -153,6 +154,9 @@ abstract class SyncProductTool { "merchantId": sysSetting.serviceMerchantId, }; apiList = await ProductApi.canteenProduct(pa); + if (!ObjectUtil.isEmptyList(apiList)) { + apiList?.forEach((v) => v.saleDate = dayStr); + } } else if (sysType == SysType.supermarket) { apiList = await ProductApi.supermarketProduct(null); } @@ -246,6 +250,7 @@ abstract class SyncProductTool { createTime: DateTime.now(), updateTime: DateTime.now(), hourType: ProductHourType.values.fromCode(v.hourType), + saleDate: v.saleDate, isDefault: false, delFlag: false, ); diff --git a/lib/common/widgets/app/app_date_picker.dart b/lib/common/widgets/app/app_date_picker.dart index b9da22f..a6dc5a7 100644 --- a/lib/common/widgets/app/app_date_picker.dart +++ b/lib/common/widgets/app/app_date_picker.dart @@ -1,15 +1,155 @@ +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:syncfusion_flutter_datepicker/datepicker.dart'; -Widget appDatePicer( - BuildContext context, -) { - return FCalendar( - controller: FCalendarController.range( - initialSelection: (DateTime(2024, 7, 17), DateTime(2024, 7, 20)), +import 'package:pj_supermarket_cloud/common/index.dart'; + +Widget appDatePicker( + BuildContext context, { + required Function(List?) onChnage, + required List? datetimeRange, +}) { + final theme = FTheme.of(context); + String detail = "请选择"; + if (!ObjectUtil.isEmpty(datetimeRange)) { + final sartStr = DateUtil.formatDate( + datetimeRange![0], + format: DateFormats.y_mo_d, + ); + final endStr = DateUtil.formatDate( + datetimeRange[1], + format: DateFormats.y_mo_d, + ); + detail = "$sartStr-$endStr"; + } + return FTile( + prefixIcon: FIcon( + FAssets.icons.calendar, + size: theme.typography.xl.fontSize, + ), + suffixIcon: FIcon( + FAssets.icons.chevronsUpDown, + size: theme.typography.sm.fontSize, + ), + title: const SizedBox.shrink(), + details: Text( + detail, + style: theme.typography.base, + ), + onPress: () async { + final result = await appShowDatePicker( + context, + datetimeRange: datetimeRange, + ); + onChnage(result); + }, + ); +} + +Future?> appShowDatePicker( + BuildContext context, { + List? datetimeRange, +}) async { + final theme = FTheme.of(context); + final width = context.width; + final height = context.height; + // 默认时间为当天 + DateTime startTIme = DateTime.now(); + DateTime endTime = DateTime.now().add(const Duration(days: 1)); + if (!ObjectUtil.isEmptyList(datetimeRange)) { + startTIme = datetimeRange![0]; + endTime = datetimeRange[1]; + } + List slectDateTime = []; + return await showAdaptiveDialog?>( + context: context, + builder: (context) => FDialog( + style: theme.dialogStyle.copyWith( + insetPadding: EdgeInsets.zero, + maxWidth: width * 0.6, + minWidth: width * 0.6, + horizontalStyle: theme.dialogStyle.horizontalStyle.copyWith( + padding: EdgeInsets.all(20.w), + ), + ), + direction: Axis.horizontal, + title: const SizedBox.shrink(), + body: SfDateRangePicker( + onSelectionChanged: (date) { + if (date.value is PickerDateRange) { + final v = date.value as PickerDateRange; + if (v.startDate == null || v.endDate == null) { + return; + } + slectDateTime = [v.startDate!, v.endDate!]; + } + }, + initialSelectedDates: [startTIme, endTime], + selectionMode: DateRangePickerSelectionMode.range, + headerHeight: 60.h, + todayHighlightColor: theme.colorScheme.primary, + backgroundColor: theme.colorScheme.background, + headerStyle: DateRangePickerHeaderStyle( + textStyle: theme.typography.xl, + textAlign: TextAlign.center, + backgroundColor: theme.colorScheme.background, + ), + selectionColor: theme.colorScheme.primary, + startRangeSelectionColor: theme.colorScheme.primary, + endRangeSelectionColor: theme.colorScheme.primary, + rangeSelectionColor: theme.colorScheme.mutedForeground, + selectionTextStyle: theme.typography.sm.copyWith( + color: theme.colorScheme.secondary, + ), + rangeTextStyle: theme.typography.sm, + monthCellStyle: DateRangePickerMonthCellStyle( + textStyle: theme.typography.sm, + todayTextStyle: theme.typography.sm, + weekendTextStyle: theme.typography.sm, + ), + monthViewSettings: DateRangePickerMonthViewSettings( + viewHeaderHeight: 50.h, + showWeekNumber: true, + weekNumberStyle: DateRangePickerWeekNumberStyle( + textStyle: theme.typography.sm, + backgroundColor: theme.colorScheme.mutedForeground, + ), + viewHeaderStyle: DateRangePickerViewHeaderStyle( + textStyle: theme.typography.base, + ), + ), + ).width(width).height(height * 0.6), + actions: [ + FButton( + label: Text( + "确定", + style: theme.typography.xl.copyWith( + color: theme.colorScheme.secondary, + ), + ), + onPress: () { + if (ObjectUtil.isEmptyList(slectDateTime)) { + Toast.error(msg: "请选择日期范围"); + return; + } + Navigator.of(context).pop(slectDateTime); + }, + ).width(200.w), + SizedBox(width: 30.w), + FButton( + style: FButtonStyle.destructive, + label: Text( + "取消", + style: theme.typography.xl.copyWith( + color: theme.colorScheme.secondary, + ), + ), + onPress: () => Navigator.of(context).pop(null), + ).width(200.w), + ], ), - start: DateTime(2024), - today: DateTime(2024, 7, 15), - end: DateTime(2030), ); } diff --git a/lib/common/widgets/app/app_message_dialog.dart b/lib/common/widgets/app/app_message_dialog.dart index 5fe3ec0..3d1307d 100644 --- a/lib/common/widgets/app/app_message_dialog.dart +++ b/lib/common/widgets/app/app_message_dialog.dart @@ -28,13 +28,14 @@ Future appMessageDialog(BuildContext context, String msg) async { label: Text('取消', style: theme.typography.base), onPress: () => Navigator.of(context).pop(false)), FButton( - label: Text( - '确定', - style: theme.typography.base.copyWith( - color: theme.colorScheme.secondary, - ), + label: Text( + '确定', + style: theme.typography.base.copyWith( + color: theme.colorScheme.secondary, ), - onPress: () => Navigator.of(context).pop(true)), + ), + onPress: () => Navigator.of(context).pop(true), + ), ], ), ); diff --git a/lib/common/widgets/app/app_page.dart b/lib/common/widgets/app/app_page.dart index fd1d51d..4d248e6 100644 --- a/lib/common/widgets/app/app_page.dart +++ b/lib/common/widgets/app/app_page.dart @@ -16,7 +16,7 @@ Widget appPage( return [ [ Text( - "共 $total 条", + "每页$pageSize条,共$total条", style: theme.typography.lg.copyWith( fontWeight: theme.typography.xl8.fontWeight, color: theme.colorScheme.primary, diff --git a/lib/common/widgets/order/mixin/order_mixin.dart b/lib/common/widgets/order/mixin/order_mixin.dart index af6e0d6..ebaf2b2 100644 --- a/lib/common/widgets/order/mixin/order_mixin.dart +++ b/lib/common/widgets/order/mixin/order_mixin.dart @@ -122,9 +122,6 @@ mixin OrderMixin { Future getProduct({ String classifyCode = "-1", }) async { - if (hourType.value != appController.hourType.value) { - hourType.value = appController.hourType.value; - } final list = await appController.dataBase.getProductDao.getAll( classifyCode, hourType.value.code, diff --git a/lib/common/widgets/order/select_pay_type_dialog.dart b/lib/common/widgets/order/select_pay_type_dialog.dart index f245f0b..844120b 100644 --- a/lib/common/widgets/order/select_pay_type_dialog.dart +++ b/lib/common/widgets/order/select_pay_type_dialog.dart @@ -38,12 +38,17 @@ class SelectPayTypeDialogController extends GetxController { final app = Get.find(); + final payTypeRadioC = FRadioSelectGroupController(); + Rxn payUser = Rxn(null); Rxn orderPayType = Rxn(OrderPayType.face); Rxn orderPayDisplayType = Rxn(OrderPayDisplayType.face); + RxList usePayDisplayTypeList = + [].obs; + Rxn orderType = Rxn(OrderType.below); RxBool isRecognition = RxBool(false); @@ -59,6 +64,34 @@ class SelectPayTypeDialogController extends GetxController { // 人脸识别回调锁 bool _faceCallbackLock = false; + @override + void onInit() async { + super.onInit(); + final appSetting = await AppSettingTool.getSysSetting(); + if (appSetting.defaultPayDisplayType != null) { + payTypeRadioC.value = {appSetting.defaultPayDisplayType!}; + } + if (!ObjectUtil.isEmptyList(appSetting.usePayDisplayType)) { + usePayDisplayTypeList.value = appSetting.usePayDisplayType!; + } + // 监听支付方式变化 + payTypeRadioC.addValueListener((v) { + final payType = OrderPayDisplayType.values.fromCode( + v.first.code, + ); + if (payType == null || payType == orderPayDisplayType.value) { + return; + } + orderPayDisplayType.value = payType; + }); + } + + @override + void onClose() { + super.onClose(); + payTypeRadioC.dispose(); + } + _closeStatus() { payUser.value = null; isRecognition.value = false; @@ -427,12 +460,6 @@ class SelectPayTypeDialogController extends GetxController { Future selectPayTypeDialog(BuildContext context) async { final payTypeC = Get.find(); final payUser = payTypeC.payUser.value; - payTypeC.orderPayType.value = OrderPayType.face; - payTypeC.orderPayDisplayType.value = OrderPayDisplayType.face; - - final controller = FRadioSelectGroupController( - value: payTypeC.orderPayDisplayType.value, - ); final theme = FTheme.of(context); final screenWidth = context.screenWidth; @@ -443,50 +470,59 @@ Future selectPayTypeDialog(BuildContext context) async { direction: Axis.vertical, title: Text("选择支付方式", style: theme.typography.lg), body: [ - FSelectGroup( - controller: controller, - style: theme.selectGroupStyle.copyWith( - labelLayoutStyle: theme.selectGroupStyle.labelLayoutStyle.copyWith( - childPadding: EdgeInsets.symmetric( - vertical: 10.h, - ), - ), - radioStyle: theme.selectGroupStyle.radioStyle.copyWith( - padding: EdgeInsets.symmetric( - vertical: 10.h, - ), - ), - ), - items: OrderPayDisplayType.values - .map>( - (v) => FSelectGroupItem.radio( - value: v, - label: Text( - v.title, - style: theme.typography.xl, - ), + Obx( + () => FSelectGroup( + controller: payTypeC.payTypeRadioC, + style: theme.selectGroupStyle.copyWith( + labelLayoutStyle: + theme.selectGroupStyle.labelLayoutStyle.copyWith( + childPadding: EdgeInsets.symmetric( + vertical: 10.h, ), - ) - .toList(), + ), + radioStyle: theme.selectGroupStyle.radioStyle.copyWith( + padding: EdgeInsets.symmetric( + vertical: 10.h, + ), + ), + ), + items: payTypeC.usePayDisplayTypeList + .map>( + (v) => FSelectGroupItem.radio( + value: v, + label: Text( + v.title, + style: theme.typography.xl, + ), + ), + ) + .toList(), + ), ), SizedBox(height: 20.h), Obx(() { - final payTypeCode = payTypeC.orderPayDisplayType.value?.code; - if (payTypeCode == null) return const SizedBox.shrink(); + final payType = payTypeC.orderPayDisplayType.value; + if (payType == null) return const SizedBox.shrink(); const baseMsg = "请点击开始识别按钮"; String msg = ""; SvgAsset icon = FAssets.icons.bird; - if (payTypeCode == "1") { - msg = "$baseMsg,并让用户扫描二维码"; - icon = FAssets.icons.qrCode; - } - if (payTypeCode == "2") { - msg = "$baseMsg,并让用户刷饭卡"; - icon = FAssets.icons.idCard; - } - if (payTypeCode == "3") { - msg = "$baseMsg,并让用户进行刷脸"; - icon = FAssets.icons.scanFace; + switch (payType) { + case OrderPayDisplayType.qrCode: + msg = "$baseMsg,并让用户扫描二维码"; + icon = FAssets.icons.qrCode; + break; + case OrderPayDisplayType.walletCard: + msg = "$baseMsg,并让用户刷饭卡"; + icon = FAssets.icons.idCard; + break; + case OrderPayDisplayType.face: + msg = "$baseMsg,并让用户进行刷脸"; + icon = FAssets.icons.scanFace; + break; + case OrderPayDisplayType.cash: + msg = "请打开钱箱,放入现金"; + icon = FAssets.icons.circleDollarSign; + break; } return [ FIcon( diff --git a/lib/pages/canteen_product/controller.dart b/lib/pages/canteen_product/controller.dart index 3eadba0..7e39c0e 100644 --- a/lib/pages/canteen_product/controller.dart +++ b/lib/pages/canteen_product/controller.dart @@ -17,10 +17,12 @@ class CanteenProductController extends GetxController with OrderMixin { StreamSubscription? mqUpdateListen; - final hourTypeC = FRadioSelectGroupController( + final hourTypeC = FRadioSelectGroupController( value: ProductHourType.morning.code, ); + late SysSetting appSetting; + _initData() { update(["canteen_product"]); } @@ -36,12 +38,15 @@ class CanteenProductController extends GetxController with OrderMixin { maskType: EasyLoadingMaskType.black, ); + appSetting = await AppSettingTool.getSysSetting(); + // 打开副屏 SubScreenPlugin.doubleScreenShow(); SubScreenPlugin.sendMsgToViceScreen(SubScreenAction.jumpSubPage.name); /// **************** start 组件初始化 start **************** - hourType.value = app.hourType.value; + hourType.value = appSetting.hourType ?? ProductHourType.morning; + hourTypeC.value = {hourType.value.code}; sysType = SysType.canteen; // 重置状态 closeStatus(); @@ -50,37 +55,40 @@ class CanteenProductController extends GetxController with OrderMixin { /// **************** end 组件初始化 end **************** /// **************** start 获取分类和商品 start **************** + await getClassify(); await getProduct(); /// **************** end 获取分类和商品 end **************** + await _clearShopCard(); + + EasyLoading.dismiss(); + hourTypeC.addValueListener((v) async { final currentHourType = ProductHourType.values.fromCode( v.first, ); - if (currentHourType == null) return; + if (currentHourType == null) { + return; + } EasyLoading.show( status: '切换中...', maskType: EasyLoadingMaskType.black, ); hourType.value = currentHourType; - app.hourType.value = currentHourType; + appSetting.hourType = currentHourType; await getClassify(); await getProduct(); await _clearShopCard(); + await AppSettingTool.setSysSetting(appSetting); EasyLoading.dismiss(); }); - - EasyLoading.dismiss(); } @override void onReady() { super.onReady(); - if (hourType.value != app.hourType.value) { - app.hourType.value = app.hourType.value; - } _initData(); } @@ -106,7 +114,6 @@ class CanteenProductController extends GetxController with OrderMixin { final payTypeC = Get.find(); payTypeC.payUser.value = payUser.value; payTypeC.orderPayDisplayType.value = orderPayDisplayType.value; - // payTypeSelectDialog(); } // |下单|点击购买 @@ -180,9 +187,7 @@ class CanteenProductController extends GetxController with OrderMixin { void _listenPayTypeSelectCallback() { final payTypeSelect = Get.find(); // |支付方式|点击|开始识别| - payTypeSelect.onRecognition = () async { - // await createSqlOrder(); - }; + payTypeSelect.onRecognition = () async {}; // 识别出用户的回调 payTypeSelect.onDiscernUser = (payUser) { if (payUser == null) return; diff --git a/lib/pages/canteen_product/view.dart b/lib/pages/canteen_product/view.dart index 82fe44a..b9183fd 100644 --- a/lib/pages/canteen_product/view.dart +++ b/lib/pages/canteen_product/view.dart @@ -209,10 +209,12 @@ class CanteenProductPage extends GetView { }, ), ).expanded(), - orderAllPrice( - context, - totalPrice: controller.totalPrice.value, - amountMealPrice: controller.amountMealPrice.value, + Obx( + () => orderAllPrice( + context, + totalPrice: controller.totalPrice.value, + amountMealPrice: controller.amountMealPrice.value, + ), ), [ SizedBox(height: 20.h), diff --git a/lib/pages/order_history/controller.dart b/lib/pages/order_history/controller.dart index e63292d..148ff9d 100644 --- a/lib/pages/order_history/controller.dart +++ b/lib/pages/order_history/controller.dart @@ -8,22 +8,22 @@ import 'package:pj_supermarket_cloud/common/index.dart'; class OrderHistoryController extends GetxController { final appC = Get.find(); + late SysSetting appSetting; + PrintManage get printManage => appC.printManage; Rx hourType = Rx(ProductHourType.morning); - DateTime startOrderCreateTime = DateTime.now().subtract( - const Duration(days: 7), - ); - - DateTime endOrderCreateTime = DateTime.now().add( - const Duration(days: 1), - ); - - Rx currentTab = OrderStatus.total.obs; + Rx currentStatus = OrderStatus.total.obs; RxList tabList = [].obs; + // 选择的时间 + RxList selectDateTime = [ + DateTime.now(), + DateTime.now().add(const Duration(days: 1)), + ].obs; + // table RxInt currentPage = 1.obs; @@ -33,7 +33,7 @@ class OrderHistoryController extends GetxController { RxList orderList = RxList([]); - final hourTypeC = FRadioSelectGroupController( + var hourTypeC = FRadioSelectGroupController( value: ProductHourType.morning.code, ); @@ -41,15 +41,14 @@ class OrderHistoryController extends GetxController { update(["order_history"]); } - void onTap() {} - @override void onInit() async { super.onInit(); - final app = Get.find(); - hourType.value = app.hourType.value; + appSetting = await AppSettingTool.getSysSetting(); + hourType.value = appSetting.hourType ?? ProductHourType.morning; + hourTypeC.value = {hourType.value.code}; // tabs - await getTableList(); + await getTotalList(); await getOrder(); hourTypeC.addValueListener((v) async { @@ -62,8 +61,8 @@ class OrderHistoryController extends GetxController { maskType: EasyLoadingMaskType.black, ); hourType.value = currentHourType; - await getTableList(); currentPage.value = 1; + await getTotalList(); await getOrder(); EasyLoading.dismiss(); }); @@ -91,41 +90,52 @@ class OrderHistoryController extends GetxController { // 订单列表 Future getOrder() async { final appSetting = await AppSettingTool.getSysSetting(); - final app = Get.find(); final sysType = appSetting.sysType.name; - final orderDao = app.dataBase.getOrderDao; + final orderDao = appC.dataBase.getOrderDao; + + String orderStatus = currentStatus.value.name; + if (currentStatus.value == OrderStatus.total) { + orderStatus = "-1"; + } + final list = await orderDao.findAll( - currentTab.value.code, - startOrderCreateTime, - endOrderCreateTime, + orderStatus, + selectDateTime[0], + selectDateTime[1], pageSize.value, (currentPage.value - 1) * pageSize.value, sysType, hourType.value.code, ); final total = await orderDao.count( - currentTab.value.code, - startOrderCreateTime, - endOrderCreateTime, + orderStatus, + selectDateTime[0], + selectDateTime[1], sysType, hourType.value.code, ); - if (total == null) { - totalPage.value = 1; - } else { - totalPage.value = (total / pageSize.value).ceil(); - } + totalPage.value = total ?? 0; orderList.value = list; } Future doTab(OrderStatus i) async { - if (i.code == currentTab.value.code) return; - currentTab.value = i; + if (i.code == currentStatus.value.code) return; + currentStatus.value = i; currentPage.value = 1; await getOrder(); } - Future getTableList() async { + Future doDateRangeDate(List? dateTime) async { + if (ObjectUtil.isEmptyList(dateTime)) { + return; + } + selectDateTime.value = dateTime!; + currentPage.value = 1; + await getTotalList(); + await getOrder(); + } + + Future getTotalList() async { final total = await _getTotal(); List tabs = OrderStatus.values .map((v) => OrderHistoryTableItem(status: v)) @@ -142,7 +152,6 @@ class OrderHistoryController extends GetxController { // 根据日期查询统计 Future> _getTotal() async { final appSetting = await AppSettingTool.getSysSetting(); - final app = Get.find(); Map map = { "pay": 0, "nonePay": 0, @@ -160,20 +169,20 @@ class OrderHistoryController extends GetxController { FROM order_record WHERE sysType = ? - AND createTime BETWEEN ? AND ? + AND strftime('%Y-%m-%d', createTime) BETWEEN ? AND ? """; final sysType = appSetting.sysType.name; List? args = [ sysType, - startOrderCreateTime.millisecondsSinceEpoch, - endOrderCreateTime.millisecondsSinceEpoch + DateUtil.formatDate(selectDateTime[0], format: DateFormats.y_mo_d), + DateUtil.formatDate(selectDateTime[1], format: DateFormats.y_mo_d), ]; // 组装where条件 if (hourType.value.code != "-1") { totalSql += " AND hourType = ?"; args.add(hourType.value.code); } - final list = await app.dataBase.database.rawQuery(totalSql, args); + final list = await appC.dataBase.database.rawQuery(totalSql, args); if (!ObjectUtil.isEmptyList(list)) { final map = list[0]; if (ObjectUtil.isNotEmpty(map)) { diff --git a/lib/pages/order_history/view.dart b/lib/pages/order_history/view.dart index 7af3bac..dba79d6 100644 --- a/lib/pages/order_history/view.dart +++ b/lib/pages/order_history/view.dart @@ -42,7 +42,8 @@ class OrderHistoryPage extends GetView { Obx( () => controller.tabList .map((v) { - final active = v.status.code == controller.currentTab.value.code; + final active = + v.status.code == controller.currentStatus.value.code; return FButton( style: active ? FButtonStyle.primary : FButtonStyle.secondary, label: Text( @@ -62,11 +63,16 @@ class OrderHistoryPage extends GetView { .toList() .toRowSpace(space: 20.w), ).scrollable(scrollDirection: Axis.horizontal).expanded(), - appRadioHourTypeDialog( - context, - controller.hourTypeC, - ).width(300.w), - ].toRow(); + // 用餐时间段 + appRadioHourTypeDialog(context, controller.hourTypeC).width(300.w), + SizedBox(width: 30.w), + // 用餐时间 + Obx(() => appDatePicker( + context, + datetimeRange: controller.selectDateTime, + onChnage: (dateList) => controller.doDateRangeDate(dateList), + )).width(400.w), + ].toRow(mainAxisAlignment: MainAxisAlignment.center); } Widget _buildTable(BuildContext context) { diff --git a/lib/pages/panel/controller.dart b/lib/pages/panel/controller.dart index 11dac60..2b66338 100644 --- a/lib/pages/panel/controller.dart +++ b/lib/pages/panel/controller.dart @@ -80,7 +80,7 @@ class PanelController extends GetxController { final sysSetting = await AppSettingTool.getSysSetting(); final id = sysSetting.serviceMerchantId; if (ObjectUtil.isEmpty(id)) { - Toast.base(msg: "请前往设置绑定设备"); + Toast.error(msg: "请前往设置绑定设备"); return false; } return true; diff --git a/lib/pages/setting/controller.dart b/lib/pages/setting/controller.dart index d985d48..667cb88 100644 --- a/lib/pages/setting/controller.dart +++ b/lib/pages/setting/controller.dart @@ -1,3 +1,4 @@ +import 'package:common_utils/common_utils.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:forui/forui.dart'; import 'package:get/get.dart'; @@ -19,14 +20,12 @@ class SettingController extends GetxController { ); // 付款方式 - var globalPayTableC = FMultiSelectGroupController( - values: OrderPayDisplayType.values.map((v) => v.code).toSet(), + var globalPayTableC = FMultiSelectGroupController( + values: {}, ); // 默认付款方式 - var defaultGlobalPayTableC = FRadioSelectGroupController( - value: OrderPayDisplayType.face.code, - ); + var defaultGlobalPayTableC = FRadioSelectGroupController(); _initData() { update(["setting"]); @@ -39,6 +38,11 @@ class SettingController extends GetxController { title: "基本信息", type: SettingMenuType.baseInfo, ), + SettingMenu( + prefixIcon: FAssets.icons.databaseBackup, + title: "资源备份", + type: SettingMenuType.backup, + ), SettingMenu( prefixIcon: FAssets.icons.refreshCw, title: "同步设置", @@ -49,11 +53,6 @@ class SettingController extends GetxController { title: "支付设置", type: SettingMenuType.paySetting, ), - SettingMenu( - prefixIcon: FAssets.icons.databaseBackup, - title: "资源备份", - type: SettingMenuType.backup, - ), SettingMenu( prefixIcon: FAssets.icons.scanFace, title: "人脸管理", @@ -79,6 +78,26 @@ class SettingController extends GetxController { final appTheme = Get.find(); appTheme.setSizeScalar(fontSizeType); }); + globalPayTableC.addValueListener((v) async { + List usePayList = []; + for (final i in v) { + final payType = OrderPayDisplayType.values.fromCode( + i, + ); + if (payType == null) continue; + usePayList.add(payType); + } + sysSetting.value?.usePayDisplayType = usePayList; + await AppSettingTool.setSysSetting(sysSetting.value!); + }); + defaultGlobalPayTableC.addValueListener((v) async { + final payType = OrderPayDisplayType.values.fromCode( + v.first, + ); + if (payType == null) return; + sysSetting.value?.defaultPayDisplayType = payType; + await AppSettingTool.setSysSetting(sysSetting.value!); + }); } @override @@ -213,6 +232,7 @@ class SettingController extends GetxController { EasyLoading.dismiss(); } catch (e) { Toast.error(msg: "备份中sql失败"); + logger.e("|$_tag|备份中sqlerror:|$e|"); EasyLoading.dismiss(); } } @@ -222,13 +242,46 @@ class SettingController extends GetxController { Toast.success(msg: "当前日志为实时备份"); } - Future getSetting() async { - sysSetting.value = await AppSettingTool.getSysSetting(); - userSetting.value = await AppSettingTool.getUserSetting(); - if (userSetting.value!.globalFontSize != null) { - globalFontSizeC = FRadioSelectGroupController( - value: SettingGlobalFontSize.xl3.code, - ); + // sql恢复 + Future recoverSql() async { + EasyLoading.show( + status: '恢复中...', + maskType: EasyLoadingMaskType.black, + ); + try { + await AppFileTool.useLastBackDatabase(); + EasyLoading.dismiss(); + Toast.success(msg: "sql恢复成功"); + EasyLoading.dismiss(); + } catch (e) { + Toast.error(msg: "sql恢复失败"); + logger.e("|$_tag|sql恢复失败error:|$e|"); + EasyLoading.dismiss(); } } + + Future getSetting() async { + sysSetting.value = await AppSettingTool.getSysSetting(); + if (sysSetting.value!.globalFontSize != null) { + globalFontSizeC.value = {sysSetting.value!.globalFontSize!.code}; + } + if (!ObjectUtil.isEmptyList(sysSetting.value!.usePayDisplayType)) { + globalPayTableC.value = + sysSetting.value!.usePayDisplayType!.map((v) => v.code).toSet(); + } + if (sysSetting.value!.defaultPayDisplayType != null) { + defaultGlobalPayTableC.value = { + sysSetting.value!.defaultPayDisplayType!.code + }; + } + } + + Future checkIsBind() async { + final sysSetting = await AppSettingTool.getSysSetting(); + final id = sysSetting.serviceMerchantId; + if (ObjectUtil.isEmpty(id)) { + return false; + } + return true; + } } diff --git a/lib/pages/setting/view.dart b/lib/pages/setting/view.dart index 90990cd..613e245 100644 --- a/lib/pages/setting/view.dart +++ b/lib/pages/setting/view.dart @@ -3,7 +3,8 @@ import 'package:flutter/material.dart'; import 'package:forui/forui.dart'; import 'package:get/get.dart'; -import 'package:pj_supermarket_cloud/common/models/index.dart'; +import 'package:pj_supermarket_cloud/common/index.dart'; + import 'package:pj_supermarket_cloud/pages/setting/widgets/index.dart'; import 'index.dart'; @@ -85,22 +86,43 @@ class SettingPage extends GetView { } Widget _buildDetail(BuildContext context, SettingMenuType type) { - switch (type) { - case SettingMenuType.baseInfo: - return settingBaseInfo(context); - case SettingMenuType.syncSetting: - return settingSync(context); - case SettingMenuType.paySetting: - return settingPay(context); - case SettingMenuType.backup: - return settingBackup(context); - case SettingMenuType.faceSetting: - return settingFace(context); - case SettingMenuType.productSetting: - return settingProduct(context); - default: - return SizedBox.shrink(); - } + return FutureBuilder( + future: controller.checkIsBind(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const SizedBox.shrink(); + } + final isBand = snapshot.data!; + switch (type) { + case SettingMenuType.baseInfo: + return settingBaseInfo(context); + case SettingMenuType.backup: + return settingBackup(context); + case SettingMenuType.syncSetting: + if (!isBand) { + return const SizedBox.shrink(); + } + return settingSync(context); + case SettingMenuType.paySetting: + if (!isBand) { + return const SizedBox.shrink(); + } + return settingPay(context); + case SettingMenuType.faceSetting: + if (!isBand) { + return const SizedBox.shrink(); + } + return settingFace(context); + case SettingMenuType.productSetting: + if (!isBand) { + return const SizedBox.shrink(); + } + return settingProduct(context); + default: + return SizedBox.shrink(); + } + }, + ); } @override diff --git a/lib/pages/setting/widgets/setting_backup.dart b/lib/pages/setting/widgets/setting_backup.dart index 42f1d35..4557cab 100644 --- a/lib/pages/setting/widgets/setting_backup.dart +++ b/lib/pages/setting/widgets/setting_backup.dart @@ -13,6 +13,7 @@ Widget settingBackup(BuildContext context) { final sys = controller.sysSetting.value; if (sys == null) return const SizedBox.shrink(); return [ + appDividerTitle(context, "备份"), FTile( prefixIcon: appPrefixIcon(context, FAssets.icons.user), suffixIcon: appSuffixIcon(context, FAssets.icons.files), @@ -32,6 +33,13 @@ 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); }); }); diff --git a/lib/pages/setting/widgets/setting_pay.dart b/lib/pages/setting/widgets/setting_pay.dart index ddd338f..68f7937 100644 --- a/lib/pages/setting/widgets/setting_pay.dart +++ b/lib/pages/setting/widgets/setting_pay.dart @@ -14,26 +14,21 @@ Widget settingPay(BuildContext context) { final sys = controller.sysSetting.value; if (sys == null) return const SizedBox.shrink(); return [ - FSelectMenuTile.builder( + FSelectMenuTile( groupController: controller.globalPayTableC, validator: (value) => value == null ? '请选择' : null, - autoHide: true, prefixIcon: appPrefixIcon(context, FAssets.icons.settings), suffixIcon: appSuffixIcon(context, FAssets.icons.audioLines), title: appPrefixTitle(context, "使用支付方式"), - menuTileBuilder: (context, index) { - if (index >= OrderPayDisplayType.values.length) { - return null; - } - final type = OrderPayDisplayType.values[index]; + menu: OrderPayDisplayType.values.map((v) { return FSelectTile( title: Text( - type.title, + v.title, style: theme.typography.xl, ), - value: type.code, + value: v.code, ); - }, + }).toList(), details: ListenableBuilder( listenable: controller.globalPayTableC, builder: (context, _) { diff --git a/lib/pages/setting/widgets/setting_product.dart b/lib/pages/setting/widgets/setting_product.dart index fab8440..e947860 100644 --- a/lib/pages/setting/widgets/setting_product.dart +++ b/lib/pages/setting/widgets/setting_product.dart @@ -70,10 +70,8 @@ class ProductManageController extends GetxController { sysType, currnetHourType, ); - if (findCount != null) { - totalPage.value = (findCount / pageSize.value).ceil(); - } - final list = await productDao.getCurrentDayAllPage( + if (findCount != null) totalPage.value = findCount; + final list = await productDao.getAllPage( "-1", currnetHourType, sysType, @@ -101,7 +99,7 @@ class ProductManageController extends GetxController { try { final isSure = await appMessageDialog( Get.context!, - "是否${v.isDefault ? '设置为' : '取消'}默认菜品", + "是否${v.isDefault ? '取消' : '设置为'}默认菜品", ); if (!isSure) return; EasyLoading.show( @@ -151,58 +149,57 @@ Widget buildSearch(BuildContext context) { Widget buildList(BuildContext context) { final theme = FTheme.of(context); final productC = Get.find(); - return GridView.builder( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 8, - mainAxisSpacing: 10.w, - crossAxisSpacing: 10.w, - childAspectRatio: 0.7, - ), - itemCount: productC.productList.length, - itemBuilder: (BuildContext context, int index) { - final v = productC.productList[index]; - return FCard( - style: theme.cardStyle.copyWith( - contentStyle: theme.cardStyle.contentStyle.copyWith( - padding: EdgeInsets.all(0), + return Obx( + () => GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 8, + mainAxisSpacing: 10.w, + crossAxisSpacing: 10.w, + childAspectRatio: 0.7, + ), + itemCount: productC.productList.length, + itemBuilder: (BuildContext context, int index) { + final v = productC.productList[index]; + return FCard( + style: theme.cardStyle.copyWith( + contentStyle: theme.cardStyle.contentStyle.copyWith( + padding: EdgeInsets.all(0), + ), ), - ), - image: appImg(v.image, width: double.infinity, height: 120.h), - title: Text(v.name, maxLines: 2, style: theme.typography.base).center(), - subtitle: appPrice(context, v.price.toString()) - .center() - .paddingOnly(top: 10.h), - child: [ - Text("是否默认", style: theme.typography.sm), - FSwitch( - value: v.isDefault, - onChange: (value) => productC.trigger(v), - ) - ].toRow(mainAxisAlignment: MainAxisAlignment.center), - ); - }, - ); -} - -/// 分页 -Widget buildPage(BuildContext context) { - final productC = Get.find(); - return appPage( - context, - pageNo: productC.currentPage.value, - pageSize: productC.pageSize.value, - total: productC.totalPage.value * productC.pageSize.value, - onPageChanged: (pageNo) => productC.doPage(page: pageNo), + image: appImg(v.image, width: double.infinity, height: 120.h), + title: + Text(v.name, maxLines: 2, style: theme.typography.base).center(), + subtitle: appPrice(context, v.price.toString()) + .center() + .paddingOnly(top: 10.h), + child: [ + Text("是否默认", style: theme.typography.sm), + FSwitch( + value: v.isDefault, + onChange: (value) => productC.trigger(v), + ) + ].toRow(mainAxisAlignment: MainAxisAlignment.center), + ); + }, + ), ); } Widget settingProduct(BuildContext context) { - Get.put( + final productC = Get.put( ProductManageController(), ); return [ buildSearch(context), buildList(context).expanded(), - buildPage(context), + Obx( + () => appPage( + context, + pageNo: productC.currentPage.value, + pageSize: productC.pageSize.value, + total: productC.totalPage.value, + onPageChanged: (pageNo) => productC.doPage(page: pageNo), + ), + ), ].toColumnSpace(space: 10.h); } diff --git a/pubspec.lock b/pubspec.lock index bc0632a..9ffbb3f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1151,6 +1151,22 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "4.0.0" + syncfusion_flutter_core: + dependency: transitive + description: + name: syncfusion_flutter_core + sha256: "59b6d2a7deacade6129d2f15615ca49ed56278fea055cd2e52cace78a343dd5e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "28.2.11" + syncfusion_flutter_datepicker: + dependency: "direct main" + description: + name: syncfusion_flutter_datepicker + sha256: "7e598b8933d906ef7a3b8f47c59e942409f71c8e59e3d1b88e67acc9eea48817" + url: "https://pub.flutter-io.cn" + source: hosted + version: "28.2.11" synchronized: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b2bd160..92ba5c9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,8 @@ dependencies: data_table_2: ^2.5.18 # 分页 number_pagination: ^1.1.6 + # 日期选择 + syncfusion_flutter_datepicker: ^28.2.11 # 权限判断 permission_handler: ^11.4.0