feat:购买失败修改

fix:购买副屏展示用户余额
This commit is contained in:
dzc committed 2026-10-26 17:46:54 +08:00
1 parent 3c11805958
commit c6f9ffb998
20 files changed
+1357 -289

No files matched your search

-36
View File
@@ -276,19 +276,6 @@ abstract class SyncFaceTool {
return byRowId.values.toList();
}
/// 供调试清理入口读取完整部门树,空部门也属于设备同步范围。
static Future<Set<String>> getDepartmentScopeDeptIds() async {
if (!AppNetworkTool.isAutoNetwork()) {
throw const FaceSyncSnapshotException('网络不可用,无法获取部门范围');
}
final setting = await AppSettingTool.getSysSetting();
final merchantDeptId = setting.merchantDeptId?.trim();
if (merchantDeptId == null || merchantDeptId.isEmpty) {
throw const FaceSyncSnapshotException('终端尚未绑定商户部门');
}
return UserApi.getFaceDepartmentScope(merchantDeptId);
}
/// 拉取 V3 固定上界游标快照并校验页面连续性、记录唯一性和字段有效性。
///
/// [onProgress] 在每页合并后上报当前已获取条数;分页总数未知,回调总数为空。
@@ -848,23 +835,6 @@ abstract class SyncFaceTool {
_deleteLocalFace(face, Get.find<AppControl>().dataBase.getFaceDao),
);
/// 按批量管线清理一组本地人脸(不触碰服务端数据),返回成功删除数。
///
/// 供人脸管理页的调试清理入口使用;同步孤儿删除走同一条 [_deleteFacesInBulk] 管线。
static Future<int> deleteLocalFaces(
List<FaceEntity> faces, {
void Function(int processed, int? total)? onProgress,
}) async {
final result = await AppFaceTool.runLibraryMutation(
() => _deleteFacesInBulk(
faces,
Get.find<AppControl>().dataBase.getFaceDao,
onProgress: onProgress,
),
);
return result.deleted;
}
/// 批量删除本地人脸的统一管线:并行改名 → 原生批量移除 → SQL 批量删除 → 并行清理文件。
///
/// 逐条删除实测约 664ms/条(每条包含独立的原生通道往返、SQLite 提交和多次
@@ -1366,12 +1336,6 @@ abstract class SyncFaceTool {
/// 只处理目录顶层文件:修改时间超过一小时、不属于任何本地记录且扩展名为
/// 图片的文件视为历史孤儿删除;`.pending-delete` 残留同样清理。跳过全部
/// 子目录(同步临时目录与原生头像目录都不在顶层规则覆盖范围内)。
static Future<int> sweepFaceStorage() async {
final storagePath = await AppFileTool.getFacePath();
if (storagePath == null || storagePath.isEmpty) return 0;
return _sweepFaceDirectory(storagePath);
}
static Future<int> _sweepFaceDirectory(String storagePath) async {
try {
final directory = Directory(storagePath);
+100 -95
View File
@@ -1,5 +1,8 @@
import 'package:get/get.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
import 'package:sqflite/sqflite.dart' as sqflite;
enum _UserCacheWrite { added, updated, unchanged }
/// 一次离线人员同步的不可变结果汇总。
class OfflineUserSyncSummary {
@@ -46,35 +49,23 @@ abstract class SyncUserTool {
/// 存储用户
static Future<void> storageUser({required ServiceUser user}) async {
try {
final app = Get.find<AppControl>();
final userDao = app.dataBase.getUserDao;
final detail = await userDao.findByUserId(user.userId!);
if (detail == null) {
final obj = _parseStorageUser(user: user, createDate: true);
await userDao.save(obj);
logger.i("|$_tag|,存储用户,新增成功|${obj.toJson()}|");
} else {
final obj = _parseStorageUser(user: user, updateDate: true);
obj.id = detail.id;
if (obj == detail) return;
// 规则查询可能与人员刷新并发,不能用旧快照整行回写覆盖新规则。
await app.dataBase.database.update(
'user_record',
{
'nickname': obj.nickname,
'mobile': obj.mobile,
'avatar': obj.avatar,
'walletCardNumber': obj.walletCardNumber,
'walletId': obj.walletId,
'walletTypeId': obj.walletTypeId,
'walletBalance': obj.walletBalance,
'canteenId': obj.canteenId,
'updateTime': DateTimeConverter().encode(obj.updateTime!),
},
where: 'id = ?',
whereArgs: [detail.id],
);
logger.i("|$_tag|,存储用户,修改成功|${obj.toJson()}|");
final userId = user.userId?.trim();
if (userId == null || userId.isEmpty) {
throw ArgumentError('不能缓存缺少用户编号的人员');
}
final result = await _storeUserSnapshot(UserEntity(
userId: userId,
nickname: user.username ?? '未知',
mobile: user.userMobile,
avatar: user.userAvatar,
walletCardNumber: user.walletCardNumber,
walletId: user.walletId,
walletTypeId: user.walletTypeId,
walletBalance: user.walletBalance,
canteenId: user.canteenId,
));
if (result != _UserCacheWrite.unchanged) {
logger.i('|$_tag|存储用户成功|userId:$userId|${result.name}|');
}
} catch (e, stack) {
logger.e("|$_tag|,存储用户失败意外的错误error:|$e|stack:|$stack|");
@@ -99,29 +90,67 @@ abstract class SyncUserTool {
);
}
static UserEntity _parseStorageUser({
required ServiceUser user,
bool createDate = false,
bool updateDate = false,
/// 所有人员缓存入口共用同一事务,首次缓存的查询与插入不可交错。
/// 数据库唯一索引兜底限制一人一条;更新仅触碰当前快照拥有的字段,
/// 不回写优惠列,也不让脱敏同步覆盖消费时取得的完整身份信息。
static Future<_UserCacheWrite> _storeUserSnapshot(
UserEntity user, {
bool preserveIdentity = false,
}) {
final userEntity = UserEntity(
userId: user.userId ?? "-1",
nickname: user.username ?? "未知",
mobile: user.userMobile,
avatar: user.userAvatar,
walletCardNumber: user.walletCardNumber,
walletId: user.walletId,
walletTypeId: user.walletTypeId,
walletBalance: user.walletBalance,
canteenId: user.canteenId,
);
if (createDate) {
userEntity.createTime = DateTime.now();
}
if (updateDate) {
userEntity.updateTime = DateTime.now();
}
return userEntity;
final database =
Get.find<AppControl>().dataBase.database as sqflite.Database;
return database.transaction((transaction) async {
final rows = await transaction.query(
'user_record',
where: 'userId = ?',
whereArgs: [user.userId],
);
if (rows.length > 1) {
throw StateError('人员缓存存在重复,请重启应用完成数据库修复');
}
final now = DateTimeConverter().encode(DateTime.now());
final wallet = <String, Object?>{
'walletCardNumber': user.walletCardNumber,
'walletId': user.walletId,
'walletTypeId': user.walletTypeId,
'walletBalance': user.walletBalance,
'canteenId': user.canteenId,
};
final identity = <String, Object?>{
'nickname': user.nickname,
'mobile': user.mobile,
'avatar': user.avatar,
};
if (rows.isEmpty) {
await transaction.insert('user_record', {
'userId': user.userId,
...identity,
...wallet,
'createTime': now,
'updateTime': now,
});
return _UserCacheWrite.added;
}
final existing = rows.single;
final changes = <String, Object?>{
if (!preserveIdentity) ...identity,
...wallet,
};
if (preserveIdentity && user.canteenId == null) {
changes.remove('canteenId');
}
if (changes.entries
.every((entry) => existing[entry.key] == entry.value)) {
return _UserCacheWrite.unchanged;
}
await transaction.update(
'user_record',
{...changes, 'updateTime': now},
where: 'userId = ?',
whereArgs: [user.userId],
);
return _UserCacheWrite.updated;
});
}
/// 按设备绑定部门树(或全租户)同步脱敏后的离线人员到本机缓存。
@@ -130,12 +159,11 @@ abstract class SyncUserTool {
/// 服务端返回的记录姓名已脱敏且不含手机号头像;本地已有的完整消费缓存
/// (真实姓名、手机号)优先保留,同步只补齐缺失人员和刷新钱包快照字段。
/// 分页期间快照上界变化会立即中断,已写入的本地数据保持有效。
static Future<OfflineUserSyncSummary> syncOfflineUsers({bool isAll = false}) async {
static Future<OfflineUserSyncSummary> syncOfflineUsers(
{bool isAll = false}) async {
if (!AppNetworkTool.isAutoNetwork()) {
throw StateError('网络不可用,无法同步离线人员');
}
final app = Get.find<AppControl>();
final userDao = app.dataBase.getUserDao;
var afterId = '0';
String? snapshotMaxId;
var added = 0;
@@ -153,48 +181,25 @@ abstract class SyncUserTool {
throw StateError('离线人员快照上界在分页期间发生变化');
}
for (final record in snapshot.records) {
final existing = await userDao.findByUserId(record.userId);
if (existing == null) {
final now = DateTime.now();
await userDao.save(
UserEntity(
userId: record.userId,
nickname: record.username,
walletCardNumber: record.walletCardNumber,
walletId: record.walletId,
walletTypeId: record.walletTypeId,
walletBalance: record.walletBalance,
canteenId: record.canteenId?.toString(),
createTime: now,
updateTime: now,
),
);
added++;
continue;
}
// 姓名、手机号、头像和优惠保留本地消费缓存的真实数据,仅刷新钱包快照。
final merged = UserEntity(
id: existing.id,
userId: existing.userId,
nickname: existing.nickname,
mobile: existing.mobile,
avatar: existing.avatar,
walletCardNumber: record.walletCardNumber,
walletId: record.walletId,
walletTypeId: record.walletTypeId,
walletBalance: record.walletBalance,
canteenId: record.canteenId?.toString() ?? existing.canteenId,
discountsList: existing.discountsList,
discountsUpdateTime: existing.discountsUpdateTime,
createTime: existing.createTime,
updateTime: DateTime.now(),
final result = await _storeUserSnapshot(
UserEntity(
userId: record.userId,
nickname: record.username,
walletCardNumber: record.walletCardNumber,
walletId: record.walletId,
walletTypeId: record.walletTypeId,
walletBalance: record.walletBalance,
canteenId: record.canteenId?.toString(),
),
preserveIdentity: true,
);
// UserEntity 等值比较不含时间戳;完全一致时避免无谓写库。
if (merged == existing) {
unchanged++;
} else {
await userDao.edit(merged);
updated++;
switch (result) {
case _UserCacheWrite.added:
added++;
case _UserCacheWrite.updated:
updated++;
case _UserCacheWrite.unchanged:
unchanged++;
}
}
if (!snapshot.hasMore) break;