feat:首字母查询、医院支付方、扫一扫支付

This commit is contained in:
dzc committed 2025-08-13 19:05:55 +08:00
1 parent 9c6585e245
commit c2707899db
19 files changed
+102 -20

No files matched your search

@@ -15,7 +15,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_PATH = "pj_cashier/database";
private static final String DATABASE_NAME = "cash_register.db";
private static final int DATABASE_VERSION = 1;
private static final int DATABASE_VERSION = 2;
public DatabaseHelper(Context context) {
super(context, getCustomDatabasePath(context), null, DATABASE_VERSION);
@@ -38,6 +38,7 @@ enum OrderType implements BaseEnum {
enum OrderPayType implements BaseEnum {
WALLET_DEFAULT("1", "普通钱包支付"),
WALLET_QR_CODE("2", "钱包二维码支付"),
WALLET_QR_CODE_SCAN("22", "钱包扫一扫支付"),
WALLET_CARD("3", "钱包饭卡支付"),
FACE("4", "人脸识别支付"),
STRIDE_DEPT_QR_CODE("5", "跨单位二维码支付"),
@@ -46,6 +47,8 @@ enum OrderPayType implements BaseEnum {
CASH("8", "现金支付"),
WECHANT_SELF_QR_CODE_PAY("10", "微信付款码支付"),
ALI_SELF_QR_CODE_PAY("11", "支付宝付款码支付"),
ZYY("12", "中医院"),
RMYY("13", "人民医院"),
;
@override
@@ -130,6 +130,9 @@ const _$OrderPayDisplayTypeEnumMap = {
OrderPayDisplayType.walletCard: 'walletCard',
OrderPayDisplayType.face: 'face',
OrderPayDisplayType.cash: 'cash',
OrderPayDisplayType.zyy: 'zyy',
OrderPayDisplayType.rmyy: 'rmyy',
OrderPayDisplayType.qrCodeScan: 'qrCodeScan',
};
UserSetting _$UserSettingFromJson(Map<String, dynamic> json) => UserSetting(
@@ -161,6 +164,7 @@ CanteenExtraPriceSetting _$CanteenExtraPriceSettingFromJson(
payAmountEnable: json['payAmountEnable'] as bool,
payAmountMealLimit: (json['payAmountMealLimit'] as num).toInt(),
payAmountMealTimes: (json['payAmountMealTimes'] as num).toDouble(),
afterSaleReturnReasons: json['afterSaleReturnReasons'] as String?,
mchRoleList: (json['mchRoleList'] as List<dynamic>?)
?.map((e) => ServiceMchRule.fromJson(e as Map<String, dynamic>))
.toList(),
@@ -172,5 +176,6 @@ Map<String, dynamic> _$CanteenExtraPriceSettingToJson(
'payAmountEnable': instance.payAmountEnable,
'payAmountMealLimit': instance.payAmountMealLimit,
'payAmountMealTimes': instance.payAmountMealTimes,
'afterSaleReturnReasons': instance.afterSaleReturnReasons,
'mchRoleList': instance.mchRoleList,
};
@@ -5,6 +5,9 @@ enum OrderPayDisplayType implements BaseEnum {
walletCard("2", "饭卡支付", true),
face("3", "人脸支付", true),
cash("4", "现金支付", true),
zyy("12", "中医院", true),
rmyy("13", "人民医院", true),
qrCodeScan("22", "钱包扫一扫", false),
;
@override
@@ -49,6 +49,7 @@ abstract class SupermarketSkuDao {
supermarket_spu.productCode,
supermarket_spu.classifyServiceUniqueCode,
supermarket_spu.productName,
supermarket_spu.productNamePy,
supermarket_spu.picUrl,
supermarket_spu.productNature,
supermarket_spu.salesCount,
@@ -69,7 +70,7 @@ abstract class SupermarketSkuDao {
INNER JOIN supermarket_spu ON supermarket_sku.spuId = supermarket_spu.serviceUniqueCode AND supermarket_spu.delFlag = 0
WHERE
1 = 1
AND (:barCode = '-1' OR supermarket_sku.barCode LIKE '%' || :barCode || '%' OR supermarket_spu.productName LIKE '%' || :barCode || '%' )
AND (:barCode = '-1' OR supermarket_sku.barCode LIKE '%' || :barCode || '%' OR supermarket_spu.productName LIKE '%' || :barCode || '%' OR (:barCode != '' AND supermarket_spu.productNamePy LIKE '%' || :barCode || '%') )
AND (:classifyServiceUniqueCode = '-1' OR supermarket_spu.classifyServiceUniqueCode = :classifyServiceUniqueCode)
ORDER BY supermarket_sku.spuId
LIMIT :pageSize OFFSET :offset
+14 -2
View File
@@ -35,7 +35,7 @@ const typeConverters = <Type>[
BoolConverter,
];
@Database(version: 1, entities: entities)
@Database(version: 2, entities: entities)
@TypeConverters(typeConverters)
abstract class AppDatabase extends FloorDatabase {
BroadcastDao get getBroadcastDao;
@@ -51,6 +51,17 @@ abstract class AppDatabase extends FloorDatabase {
FaceDao get getFaceDao;
SettingDao get getSettingDao;
// 获取数据库迁移列表
static List<Migration> _getDatabaseMigrations() {
return [
// 从版本1到版本2的迁移:添加productNamePy字段
Migration(1, 2, (database) async {
await database.execute(
'ALTER TABLE supermarket_spu ADD COLUMN productNamePy TEXT');
}),
];
}
static Future<AppDatabase> getDataBase() async {
final dbPath = await AppFileTool.getDatabasePath();
final dataBase = await $FloorAppDatabase
@@ -68,7 +79,8 @@ abstract class AppDatabase extends FloorDatabase {
},
),
)
.addMigrations([]).build();
.addMigrations(_getDatabaseMigrations())
.build();
return dataBase;
}
}
+5 -3
View File
@@ -102,7 +102,7 @@ class _$AppDatabase extends AppDatabase {
Callback? callback,
]) async {
final databaseOptions = sqflite.OpenDatabaseOptions(
version: 1,
version: 2,
onConfigure: (database) async {
await database.execute('PRAGMA foreign_keys = ON');
await callback?.onConfigure?.call(database);
@@ -126,7 +126,7 @@ class _$AppDatabase extends AppDatabase {
await database.execute(
'CREATE TABLE IF NOT EXISTS `supermarket_sku` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `serviceUniqueCode` TEXT NOT NULL, `spuId` TEXT NOT NULL, `barCode` TEXT NOT NULL, `spec` TEXT NOT NULL, `unit` TEXT NOT NULL, `packageNum` INTEGER NOT NULL, `purchasePrice` INTEGER NOT NULL, `retailPrice` INTEGER NOT NULL, `promotionPrice` INTEGER NOT NULL)');
await database.execute(
'CREATE TABLE IF NOT EXISTS `supermarket_spu` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `serviceUniqueCode` TEXT NOT NULL, `classifyServiceUniqueCode` TEXT NOT NULL, `productCode` TEXT NOT NULL, `productName` TEXT NOT NULL, `productNature` TEXT NOT NULL, `barCode` TEXT, `packageNum` INTEGER NOT NULL, `unit` TEXT NOT NULL, `spec` TEXT NOT NULL, `picUrl` TEXT, `stock` REAL, `salesCount` REAL, `purchasePrice` INTEGER NOT NULL, `retailPrice` INTEGER NOT NULL, `promotionPrice` INTEGER NOT NULL, `sort` INTEGER NOT NULL, `createTime` TEXT NOT NULL, `updateTime` TEXT NOT NULL, `delFlag` INTEGER NOT NULL)');
'CREATE TABLE IF NOT EXISTS `supermarket_spu` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `serviceUniqueCode` TEXT NOT NULL, `classifyServiceUniqueCode` TEXT NOT NULL, `productCode` TEXT NOT NULL, `productName` TEXT NOT NULL, `productNamePy` TEXT, `productNature` TEXT NOT NULL, `barCode` TEXT, `packageNum` INTEGER NOT NULL, `unit` TEXT NOT NULL, `spec` TEXT NOT NULL, `picUrl` TEXT, `stock` REAL, `salesCount` REAL, `purchasePrice` INTEGER NOT NULL, `retailPrice` INTEGER NOT NULL, `promotionPrice` 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 `supermarket_code` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `serviceUniqueCode` TEXT NOT NULL, `spuId` TEXT NOT NULL, `unitId` TEXT NOT NULL, `barCode` TEXT NOT NULL)');
await database.execute(
@@ -821,7 +821,7 @@ class _$SupermarketSkuDao extends SupermarketSkuDao {
int offset,
) async {
return _queryAdapter.queryList(
'SELECT supermarket_sku.id, supermarket_sku.serviceUniqueCode, supermarket_sku.spuId, supermarket_spu.productCode, supermarket_spu.classifyServiceUniqueCode, supermarket_spu.productName, supermarket_spu.picUrl, supermarket_spu.productNature, supermarket_spu.salesCount, supermarket_spu.stock, supermarket_spu.sort, supermarket_spu.createTime, supermarket_spu.updateTime, supermarket_spu.delFlag, supermarket_sku.barCode, supermarket_sku.promotionPrice, supermarket_sku.purchasePrice, supermarket_sku.retailPrice, supermarket_sku.spec, supermarket_sku.packageNum, supermarket_sku.unit, supermarket_sku.packageNum FROM supermarket_sku INNER JOIN supermarket_spu ON supermarket_sku.spuId = supermarket_spu.serviceUniqueCode AND supermarket_spu.delFlag = 0 WHERE 1 = 1 AND (?1 = \'-1\' OR supermarket_sku.barCode LIKE \'%\' || ?1 || \'%\' OR supermarket_spu.productName LIKE \'%\' || ?1 || \'%\' ) AND (?2 = \'-1\' OR supermarket_spu.classifyServiceUniqueCode = ?2) ORDER BY supermarket_sku.spuId LIMIT ?3 OFFSET ?4',
'SELECT supermarket_sku.id, supermarket_sku.serviceUniqueCode, supermarket_sku.spuId, supermarket_spu.productCode, supermarket_spu.classifyServiceUniqueCode, supermarket_spu.productName, supermarket_spu.productNamePy, supermarket_spu.picUrl, supermarket_spu.productNature, supermarket_spu.salesCount, supermarket_spu.stock, supermarket_spu.sort, supermarket_spu.createTime, supermarket_spu.updateTime, supermarket_spu.delFlag, supermarket_sku.barCode, supermarket_sku.promotionPrice, supermarket_sku.purchasePrice, supermarket_sku.retailPrice, supermarket_sku.spec, supermarket_sku.packageNum, supermarket_sku.unit, supermarket_sku.packageNum FROM supermarket_sku INNER JOIN supermarket_spu ON supermarket_sku.spuId = supermarket_spu.serviceUniqueCode AND supermarket_spu.delFlag = 0 WHERE 1 = 1 AND (?1 = \'-1\' OR supermarket_sku.barCode LIKE \'%\' || ?1 || \'%\' OR supermarket_spu.productName LIKE \'%\' || ?1 || \'%\' OR (?1 != \'\' AND supermarket_spu.productNamePy LIKE \'%\' || ?1 || \'%\') ) AND (?2 = \'-1\' OR supermarket_spu.classifyServiceUniqueCode = ?2) ORDER BY supermarket_sku.spuId LIMIT ?3 OFFSET ?4',
mapper: (Map<String, Object?> row) => SupermarketSpuEntity(id: row['id'] as int?, serviceUniqueCode: row['serviceUniqueCode'] as String, classifyServiceUniqueCode: row['classifyServiceUniqueCode'] as String, productCode: row['productCode'] as String, productName: row['productName'] as String, productNature: _supermarketNatureConverter.decode(row['productNature'] as String), barCode: row['barCode'] as String?, packageNum: row['packageNum'] as int, unit: row['unit'] as String, spec: row['spec'] as String, picUrl: row['picUrl'] as String?, stock: row['stock'] as double?, salesCount: row['salesCount'] as double?, purchasePrice: row['purchasePrice'] as int, retailPrice: row['retailPrice'] as int, promotionPrice: row['promotionPrice'] 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: [barCode, classifyServiceUniqueCode, pageSize, offset]);
}
@@ -863,6 +863,7 @@ class _$SupermarketSpuDao extends SupermarketSpuDao {
'classifyServiceUniqueCode': item.classifyServiceUniqueCode,
'productCode': item.productCode,
'productName': item.productName,
'productNamePy': item.productNamePy,
'productNature':
_supermarketNatureConverter.encode(item.productNature),
'barCode': item.barCode,
@@ -890,6 +891,7 @@ class _$SupermarketSpuDao extends SupermarketSpuDao {
'classifyServiceUniqueCode': item.classifyServiceUniqueCode,
'productCode': item.productCode,
'productName': item.productName,
'productNamePy': item.productNamePy,
'productNature':
_supermarketNatureConverter.encode(item.productNature),
'barCode': item.barCode,
@@ -81,10 +81,15 @@ const _$OrderStatusEnumMap = {
const _$OrderPayTypeEnumMap = {
OrderPayType.WALLET_DEFAULT: 'WALLET_DEFAULT',
OrderPayType.WALLET_QR_CODE: 'WALLET_QR_CODE',
OrderPayType.WALLET_QR_CODE_SCAN: 'WALLET_QR_CODE_SCAN',
OrderPayType.WALLET_CARD: 'WALLET_CARD',
OrderPayType.FACE: 'FACE',
OrderPayType.STRIDE_DEPT_QR_CODE: 'STRIDE_DEPT_QR_CODE',
OrderPayType.FOREIGN_TICKET_QR_CODE: 'FOREIGN_TICKET_QR_CODE',
OrderPayType.RESERVE_QR_CODE: 'RESERVE_QR_CODE',
OrderPayType.CASH: 'CASH',
OrderPayType.WECHANT_SELF_QR_CODE_PAY: 'WECHANT_SELF_QR_CODE_PAY',
OrderPayType.ALI_SELF_QR_CODE_PAY: 'ALI_SELF_QR_CODE_PAY',
OrderPayType.ZYY: 'ZYY',
OrderPayType.RMYY: 'RMYY',
};
@@ -24,6 +24,9 @@ class SupermarketSpuEntity extends Equatable {
/// 商品名称
String productName;
/// 商品名称拼音
String? productNamePy;
/// 商品性质(字典)
ProductNature productNature;
@@ -29,7 +29,7 @@ SupermarketSpuEntity _$SupermarketSpuEntityFromJson(
createTime: DateTime.parse(json['createTime'] as String),
updateTime: DateTime.parse(json['updateTime'] as String),
delFlag: json['delFlag'] as bool,
);
)..productNamePy = json['productNamePy'] as String?;
Map<String, dynamic> _$SupermarketSpuEntityToJson(
SupermarketSpuEntity instance) =>
@@ -39,6 +39,7 @@ Map<String, dynamic> _$SupermarketSpuEntityToJson(
'classifyServiceUniqueCode': instance.classifyServiceUniqueCode,
'productCode': instance.productCode,
'productName': instance.productName,
'productNamePy': instance.productNamePy,
'productNature': _$ProductNatureEnumMap[instance.productNature]!,
'barCode': instance.barCode,
'packageNum': instance.packageNum,
@@ -1,5 +1,6 @@
import 'package:common_utils/common_utils.dart';
import 'package:get/get.dart';
import 'package:pinyin/pinyin.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
@@ -382,6 +383,11 @@ abstract class SyncProductTool {
updateTime: DateTime.now(),
delFlag: false,
);
// 计算一下拼音
final productNamePy = await transitionPy(item.productName);
if (ObjectUtil.isNotEmpty(productNamePy)) {
item.productNamePy = productNamePy;
}
if (isUpdate) {
final detail = await productDao.getByCode(item.serviceUniqueCode);
if (ObjectUtil.isEmpty(detail)) continue;
@@ -475,4 +481,20 @@ abstract class SyncProductTool {
// **************************************************************************
// 同步食堂商品 spu end
// **************************************************************************
// 中文转拼音
static Future<String?> transitionPy(String str) async {
try {
if (ObjectUtil.isEmpty(str)) return "";
// 尝试转换为数字,如果是数字,返回空
if (double.tryParse(str) != null) return "";
final py = PinyinHelper.getShortPinyin(str);
logger.d("|$_tag|中文转拼音|中文:|$str|转换到拼音:|$py|");
// 去除所有空格
final pyNoSpace = py.replaceAll(" ", "");
return pyNoSpace;
} catch (error, stack) {
logger.e("|$_tag|添加超市spu detail 错误error:|$error|stack:|$stack|");
}
}
}
+2 -2
View File
@@ -10,9 +10,9 @@ class Constants {
static const pwdEncKey = 'pigxpigxpigxpigx';
/// 服务 url
// static const apiUrl = 'https://stgl.pj.gov.cn/api';
static const apiUrl = 'https://stgl.pj.gov.cn/api';
static const apiUrl = 'http://192.168.101.139:9999';
// static const apiUrl = 'http://192.168.101.139:9999';
/// 静态资源 url
static const ossUrl = apiUrl;
@@ -406,7 +406,8 @@ class SelectPayTypeDialogController extends GetxController {
if (isNetwork) {
final pa = {
"id": event.userId,
"type": appSetting.sysType.name,
// 现阶段都使用饭卡钱包
"type": "CANTEEN",
};
final data = await HardApi.getUserInfoById(pa);
if (data == null) throw Error();
@@ -533,7 +534,7 @@ Future<void> selectPayTypeDialog() async {
),
),
).center().expanded(),
].toColumn().width(width * 0.5).height(height * 0.7),
].toColumn().width(width * 0.7).height(height * 0.7),
actions: [
<Widget>[
Obx(
@@ -649,8 +650,12 @@ Widget selectPayTypeHint(
String msg = "";
SvgAsset icon = FAssets.icons.bird;
switch (type) {
case OrderPayDisplayType.qrCodeScan:
msg = "$baseMsg,并让用户扫一扫二维码";
icon = FAssets.icons.qrCode;
break;
case OrderPayDisplayType.qrCode:
msg = "$baseMsg,并让用户扫描二维码";
msg = "$baseMsg,并让用户出示二维码";
icon = FAssets.icons.qrCode;
break;
case OrderPayDisplayType.walletCard:
@@ -665,6 +670,14 @@ Widget selectPayTypeHint(
msg = "请打开钱箱,放入现金";
icon = FAssets.icons.circleDollarSign;
break;
case OrderPayDisplayType.zyy:
msg = "中医院支付,请点击支付按钮";
icon = FAssets.icons.circleDollarSign;
break;
case OrderPayDisplayType.rmyy:
msg = "人民医院支付,请点击支付按钮";
icon = FAssets.icons.circleDollarSign;
break;
}
return appEmpty(
context,
@@ -144,7 +144,7 @@ class SteelyardController extends GetxController {
final w = appC.srialSteelyardManage.parseWidget(event);
if (ObjectUtil.isEmpty(w)) return;
// 保留两位小数并向上取整
final roundedWeight = (w! * 100).ceil() / 100;
final roundedWeight = (w! * 100).round() / 100;
callbackWidget.value = roundedWeight;
});
interval(
+2 -1
View File
@@ -15,7 +15,7 @@ class PanelController extends GetxController {
PanelItem(title: "购买", visible: false, type: PanelType.supermarketOrder),
PanelItem(title: "点餐", visible: false, type: PanelType.canteenOrder),
PanelItem(title: "预定", visible: false, type: PanelType.canteenReserve),
PanelItem(title: "取餐", visible: false, type: PanelType.takeFood),
PanelItem(title: "核销", visible: false, type: PanelType.takeFood),
PanelItem(title: "交易查询", visible: true, type: PanelType.orderHistory),
PanelItem(title: "交易统计", visible: false, type: PanelType.canteenOrderTotal),
PanelItem(title: "开卡管理", visible: true, type: PanelType.cardActive),
@@ -33,6 +33,7 @@ class PanelController extends GetxController {
final supermarketMenus = [
PanelType.supermarketOrder,
PanelType.takeFood,
];
final appC = Get.find<AppControl>();
+2 -1
View File
@@ -238,7 +238,8 @@ class SupermarketOrderPage extends GetView<SupermarketOrderController> {
padding: EdgeInsets.zero,
itemCount: controller.shopCardList.length,
itemBuilder: (context, index) {
final current = controller.shopCardList[index];
final reversedList = controller.shopCardList.reversed.toList();
final current = reversedList[index];
return orderSelectPanel(
Get.context!,
label: current.productName,
+3 -3
View File
@@ -116,7 +116,7 @@ class TakeFoodPage extends GetView<TakeFoodController> {
FButton(
style: FButtonStyle.destructive,
label: Text(
"取消点餐",
"取消",
style: theme.typography.xl.copyWith(
color: theme.colorScheme.secondary,
),
@@ -126,7 +126,7 @@ class TakeFoodPage extends GetView<TakeFoodController> {
SizedBox(width: 20.w),
FButton(
label: Text(
"确认点餐",
"确认核销",
style: theme.typography.xl.copyWith(
color: theme.colorScheme.secondary,
),
@@ -144,7 +144,7 @@ class TakeFoodPage extends GetView<TakeFoodController> {
id: "take_food",
builder: (_) {
return FScaffold(
header: appDefaultNav(context, title: "取餐"),
header: appDefaultNav(context, title: "核销"),
content: _buildView(context).marginOnly(top: 20.h),
resizeToAvoidBottomInset: false,
);
+8
View File
@@ -986,6 +986,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.2"
pinyin:
dependency: "direct main"
description:
name: pinyin
sha256: "240f271a3c71af20c8d2757756b5ee8e9d79a955d37abad4b3568fd406b22411"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.3.0"
platform:
dependency: transitive
description:
+3 -1
View File
@@ -14,7 +14,9 @@ dependencies:
dio: 5.7.0
http: ^1.3.0
# mq
mqtt_client: ^10.0.2
mqtt_client: ^10.0.2
# 文字转拼音
pinyin: ^3.3.0
# ui框架
ducafe_ui_core: ^1.0.6