feat:交易记录、日期组建

This commit is contained in:
dzc committed 2025-03-11 18:04:58 +08:00
1 parent 08ad1c2d81
commit 88e73ad950
32 files changed
+672 -279

No files matched your search

@@ -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<String, dynamic> json) =>
@@ -38,6 +38,9 @@ ServiceProduct _$ServiceProductFromJson(Map<String, dynamic> 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<String, dynamic> _$ServiceProductToJson(ServiceProduct instance) =>
@@ -51,4 +54,5 @@ Map<String, dynamic> _$ServiceProductToJson(ServiceProduct instance) =>
'price': instance.price,
'sort': instance.sort,
'categoryType': instance.categoryType,
'saleDate': instance.saleDate?.toIso8601String(),
};
@@ -54,7 +54,7 @@ enum OrderPayType implements BaseEnum {
/// 订单状态
enum OrderStatus implements BaseEnum {
// 查询使用
total("-1", "未付款"),
total("-1", "全部"),
nonePay("1", "未付款"),
pay("5", "已付款"),
@@ -88,6 +88,18 @@ class SysSetting extends Equatable {
/// 长链接重连
DateTime? mqSyncTime;
/// 商品时间段类型
ProductHourType? hourType;
// 全局字体大小
SettingGlobalFontSize? globalFontSize;
// 使用支付方式
List<OrderPayDisplayType>? 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,
];
}
@@ -49,7 +49,16 @@ SysSetting _$SysSettingFromJson(Map<String, dynamic> 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<dynamic>?)
?.map((e) => $enumDecode(_$OrderPayDisplayTypeEnumMap, e))
.toList()
..defaultPayDisplayType = $enumDecodeNullable(
_$OrderPayDisplayTypeEnumMap, json['defaultPayDisplayType']);
Map<String, dynamic> _$SysSettingToJson(SysSetting instance) =>
<String, dynamic>{
@@ -84,6 +93,13 @@ Map<String, dynamic> _$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<String, dynamic> 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<String, dynamic> _$UserSettingToJson(UserSetting instance) =>
<String, dynamic>{
'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<String, dynamic> 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<String, dynamic> _$UserSettingToJson(UserSetting instance) =>
<String, dynamic>{
'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<String, dynamic> json) =>
CanteenExtraPriceSetting(
@@ -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<int?> count(
String status,
@@ -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<void> 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<int?> 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<List<ProductEntity>> getCurrentDayAllPage(
Future<List<ProductEntity>> 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<List<ProductEntity>> getDefault(String sysType, String hourType);
}
+15 -11
View File
@@ -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<String, Object?> 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<String, Object?> 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<String, Object?> 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<String, Object?> 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<String, Object?> 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<List<ProductEntity>> getCurrentDayAllPage(
Future<List<ProductEntity>> 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<String, Object?> 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<String, Object?> 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<String, Object?> 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<String, Object?> 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]);
}
@@ -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,
@@ -13,6 +13,9 @@ ProductEntity _$ProductEntityFromJson(Map<String, dynamic> 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<String, dynamic> _$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,
+51 -5
View File
@@ -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<String> _checkAndcreateDir(String dir) async {
@@ -53,14 +54,14 @@ abstract class AppFileTool {
/// 创建数据库文件备份地址
static Future<String?> 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<void> 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|");
}
}
// 备份日志
}
@@ -31,8 +31,6 @@ class AppControl extends GetxController {
// 是否有网络
RxBool isNetwork = RxBool(false);
Rx<ProductHourType> hourType = Rx(ProductHourType.morning);
@override
void onClose() {
super.onClose();
@@ -16,9 +16,9 @@ class AppThemeControl extends GetxController {
}
Future<void> 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;
}
}
@@ -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,
);
+149 -9
View File
@@ -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<DateTime>?) onChnage,
required List<DateTime>? 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<List<DateTime>?> appShowDatePicker(
BuildContext context, {
List<DateTime>? 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<DateTime> slectDateTime = [];
return await showAdaptiveDialog<List<DateTime>?>(
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),
);
}
@@ -28,13 +28,14 @@ Future<bool> 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),
),
],
),
);
+1 -1
View File
@@ -16,7 +16,7 @@ Widget appPage(
return <Widget>[
<Widget>[
Text(
"共 $total 条",
"每页$pageSize条,共$total条",
style: theme.typography.lg.copyWith(
fontWeight: theme.typography.xl8.fontWeight,
color: theme.colorScheme.primary,
@@ -122,9 +122,6 @@ mixin OrderMixin {
Future<void> 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,
@@ -38,12 +38,17 @@ class SelectPayTypeDialogController extends GetxController {
final app = Get.find<AppControl>();
final payTypeRadioC = FRadioSelectGroupController<OrderPayDisplayType>();
Rxn<ServiceUser?> payUser = Rxn(null);
Rxn<OrderPayType> orderPayType = Rxn(OrderPayType.face);
Rxn<OrderPayDisplayType> orderPayDisplayType = Rxn(OrderPayDisplayType.face);
RxList<OrderPayDisplayType> usePayDisplayTypeList =
<OrderPayDisplayType>[].obs;
Rxn<OrderType> 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<void> selectPayTypeDialog(BuildContext context) async {
final payTypeC = Get.find<SelectPayTypeDialogController>();
final payUser = payTypeC.payUser.value;
payTypeC.orderPayType.value = OrderPayType.face;
payTypeC.orderPayDisplayType.value = OrderPayDisplayType.face;
final controller = FRadioSelectGroupController<OrderPayDisplayType>(
value: payTypeC.orderPayDisplayType.value,
);
final theme = FTheme.of(context);
final screenWidth = context.screenWidth;
@@ -443,50 +470,59 @@ Future<void> selectPayTypeDialog(BuildContext context) async {
direction: Axis.vertical,
title: Text("选择支付方式", style: theme.typography.lg),
body: <Widget>[
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<FSelectGroupItem<OrderPayDisplayType>>(
(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<FSelectGroupItem<OrderPayDisplayType>>(
(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 <Widget>[
FIcon(