664 lines
25 KiB
Dart
664 lines
25 KiB
Dart
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:common_utils/common_utils.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
|
|
|
import 'package:pj_supermarket_cloud/common/index.dart';
|
|
|
|
abstract class AppSettingTool {
|
|
static const String _tag = "app配置工具";
|
|
|
|
static const String _settingKey = "setting";
|
|
static const String _terminalMenuOrderKey = "terminalMenuOrder";
|
|
static const String _hiddenTerminalMenusKey = "hiddenTerminalMenus";
|
|
static const String _payTypeOrderKey = "payTypeOrder";
|
|
static const String _cashierShowHoldActionKey = "cashierShowHoldAction";
|
|
static const String _cashierShowMoreActionKey = "cashierShowMoreAction";
|
|
static const String _reservationQueryMethodOrderKey =
|
|
"reservationQueryMethodOrder";
|
|
static const String _reservationQueryDefaultMethodKey =
|
|
"reservationQueryDefaultMethod";
|
|
static const String _reservationQueryNameMaskEnabledKey =
|
|
"reservationQueryNameMaskEnabled";
|
|
static const String _reservationQueryVerificationEnabledKey =
|
|
"reservationQueryVerificationEnabled";
|
|
static const String _reservationQueryVerificationDateScopeKey =
|
|
"reservationQueryVerificationDateScope";
|
|
static const String _serialCardConfigKey = "serialCardConfig";
|
|
|
|
/// v8 之前短暂保存定时任务配置的旧 sysJson 键,仅供一次性迁移读取。
|
|
static const String _scheduledTaskConfigsKey = "scheduledTaskConfigs";
|
|
|
|
/// v8 之前短暂保存任务最近执行结果的旧 sysJson 键,仅供一次性迁移读取。
|
|
static const String _scheduledTaskRecordsKey = "scheduledTaskRecords";
|
|
|
|
/// v8 之前保存日志文件成功上传状态的旧 sysJson 键,仅供一次性迁移读取。
|
|
static const String _terminalLogUploadStatesKey = "terminalLogUploadStates";
|
|
|
|
/// v8 之前保存最近日志上传汇总的旧 sysJson 键,仅供一次性迁移清理。
|
|
static const String _terminalLogUploadSummaryKey = "terminalLogUploadSummary";
|
|
|
|
/// 人工硬件输入历史在现有 sysJson 扩展配置中的存储键。
|
|
static const String _hardwareInputHistoryKey = "hardwareInputHistory";
|
|
|
|
// 自定义缓存管理器
|
|
static final CacheManager _settingCache = CacheManager(
|
|
Config(
|
|
'setting_cache',
|
|
stalePeriod: const Duration(days: 7),
|
|
maxNrOfCacheObjects: 10,
|
|
),
|
|
);
|
|
|
|
/// sysJson 扩展数据的进程内写入队列,避免迁移清理与设置保存相互覆盖。
|
|
static Future<void> _extensionWriteQueue = Future.value();
|
|
|
|
static Future<void> removeSettingCache() async {
|
|
await _settingCache.emptyCache();
|
|
}
|
|
|
|
static Future<SettingEntity> _getSetting() async {
|
|
// 尝试从缓存获取
|
|
final fileInfo = await _settingCache.getFileFromCache(_settingKey);
|
|
if (fileInfo != null) {
|
|
final content = await fileInfo.file.readAsString();
|
|
if (ObjectUtil.isNotEmpty(content)) {
|
|
return SettingEntity.fromJson(json.decode(content));
|
|
}
|
|
}
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) {
|
|
final initSysInfo = SysSetting(
|
|
sysType: SysType.CANTEEN,
|
|
androidId: await AppSysTool.getAndroidId(),
|
|
sqlAddress: "",
|
|
);
|
|
final initUserInfo = UserSetting(
|
|
username: "",
|
|
password: "",
|
|
);
|
|
SettingEntity addObj = SettingEntity(
|
|
userJson: json.encode(initUserInfo.toJson()),
|
|
sysJson: json.encode(initSysInfo.toJson()),
|
|
);
|
|
final addId = await settingDao.save(addObj);
|
|
if (ObjectUtil.isEmpty(addId)) {
|
|
throw Exception("|$_tag|_getSetting新增错误");
|
|
}
|
|
addObj.id = addId;
|
|
return addObj;
|
|
}
|
|
return setting;
|
|
}
|
|
|
|
static Future<bool> _setSetting({
|
|
SysSetting? sysJson,
|
|
UserSetting? userJson,
|
|
CanteenExtraPriceSetting? canteenExtraPriceConfig,
|
|
}) async {
|
|
if (ObjectUtil.isEmpty(sysJson) &&
|
|
ObjectUtil.isEmpty(userJson) &&
|
|
ObjectUtil.isEmpty(canteenExtraPriceConfig)) {
|
|
return false;
|
|
}
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
SettingEntity? setting = await settingDao.get();
|
|
if (setting == null) {
|
|
logger.e("|$_tag|_setSetting新增错误settingDao.get()方法返回为null");
|
|
return false;
|
|
}
|
|
if (sysJson != null) {
|
|
final current = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
// sysJson 允许保存不涉及数据库结构的终端 UI 扩展配置,更新业务设置时必须保留这些键。
|
|
setting.sysJson = json.encode({...current, ...sysJson.toJson()});
|
|
}
|
|
if (userJson != null) {
|
|
setting.userJson = json.encode(userJson.toJson());
|
|
}
|
|
if (canteenExtraPriceConfig != null) {
|
|
setting.canteenExtraPriceConfigJson = json.encode(
|
|
canteenExtraPriceConfig.toJson(),
|
|
);
|
|
}
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
return true;
|
|
}
|
|
|
|
static Future<SysSetting> getSysSetting() async {
|
|
final setting = await _getSetting();
|
|
return SysSetting.fromJson(json.decode(setting.sysJson));
|
|
}
|
|
|
|
static Future<UserSetting> getUserSetting() async {
|
|
final setting = await _getSetting();
|
|
return UserSetting.fromJson(json.decode(setting.userJson));
|
|
}
|
|
|
|
static Future<CanteenExtraPriceSetting?> getCanteenExtraPriceConfig() async {
|
|
final setting = await _getSetting();
|
|
if (ObjectUtil.isEmpty(setting.canteenExtraPriceConfigJson)) {
|
|
return null;
|
|
}
|
|
return CanteenExtraPriceSetting.fromJson(
|
|
json.decode(setting.canteenExtraPriceConfigJson!),
|
|
);
|
|
}
|
|
|
|
static Future<void> setSysSetting(SysSetting sysInfo) async {
|
|
await _setSetting(sysJson: sysInfo);
|
|
}
|
|
|
|
/// 读取完整 sysJson 为可修改映射,仅供旧结构化数据迁移方法使用。
|
|
static Future<Map<String, dynamic>> _getSysExtensionJson() async {
|
|
final setting = await _getSetting();
|
|
return Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
}
|
|
|
|
/// 仅用于把 v8 之前短暂写入 sysJson 的任务配置导入结构化表,不再提供 JSON 写入口。
|
|
static Future<List<ScheduledTaskConfig>> getScheduledTaskConfigs() async {
|
|
final sysJson = await _getSysExtensionJson();
|
|
final raw = sysJson[_scheduledTaskConfigsKey];
|
|
if (raw is! List) return const [];
|
|
return raw
|
|
.whereType<Map>()
|
|
.map((item) => ScheduledTaskConfig.fromJson(
|
|
Map<String, dynamic>.from(item),
|
|
))
|
|
.toList(growable: false);
|
|
}
|
|
|
|
/// 读取 v8 之前的任务执行快照并按当前枚举过滤未知任务,仅用于迁移。
|
|
static Future<Map<ScheduledTaskType, ScheduledTaskRecord>>
|
|
getScheduledTaskRecords() async {
|
|
final sysJson = await _getSysExtensionJson();
|
|
final raw = sysJson[_scheduledTaskRecordsKey];
|
|
if (raw is! Map) return const {};
|
|
final result = <ScheduledTaskType, ScheduledTaskRecord>{};
|
|
for (final entry in raw.entries) {
|
|
ScheduledTaskType? type;
|
|
for (final item in ScheduledTaskType.values) {
|
|
if (item.name == entry.key.toString()) {
|
|
type = item;
|
|
break;
|
|
}
|
|
}
|
|
if (type == null || entry.value is! Map) continue;
|
|
result[type] = ScheduledTaskRecord.fromJson(
|
|
Map<String, dynamic>.from(entry.value as Map),
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// 读取 v8 之前按相对路径保存的成功上传状态,仅用于导入文件上传记录表。
|
|
static Future<Map<String, TerminalLogUploadState>>
|
|
getTerminalLogUploadStates() async {
|
|
final sysJson = await _getSysExtensionJson();
|
|
final raw = sysJson[_terminalLogUploadStatesKey];
|
|
if (raw is! Map) return const {};
|
|
return raw.map(
|
|
(key, value) => MapEntry(
|
|
key.toString(),
|
|
TerminalLogUploadState.fromJson(
|
|
Map<String, dynamic>.from(value as Map),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 读取 v8 之前的最近上传汇总;仅保留兼容能力,不再作为运行时数据源。
|
|
static Future<TerminalLogUploadSummary> getTerminalLogUploadSummary() async {
|
|
final sysJson = await _getSysExtensionJson();
|
|
final raw = sysJson[_terminalLogUploadSummaryKey];
|
|
if (raw is! Map) return const TerminalLogUploadSummary();
|
|
return TerminalLogUploadSummary.fromJson(Map<String, dynamic>.from(raw));
|
|
}
|
|
|
|
/// v8 已将任务与上传状态迁入独立表,导入成功后移除旧 JSON,避免形成双写数据源。
|
|
static Future<void> clearLegacyScheduledTaskState({
|
|
required bool includeUploadState,
|
|
}) async {
|
|
final operation = _extensionWriteQueue.catchError((_) {}).then((_) async {
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) throw StateError('终端设置尚未初始化');
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
sysJson.remove(_scheduledTaskConfigsKey);
|
|
sysJson.remove(_scheduledTaskRecordsKey);
|
|
if (includeUploadState) {
|
|
sysJson.remove(_terminalLogUploadStatesKey);
|
|
sysJson.remove(_terminalLogUploadSummaryKey);
|
|
}
|
|
setting.sysJson = json.encode(sysJson);
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
});
|
|
_extensionWriteQueue = operation;
|
|
await operation;
|
|
}
|
|
|
|
static Future<void> setUserSetting(UserSetting userInfo) async {
|
|
final globalUserInfo = await getUserSetting();
|
|
if (globalUserInfo == userInfo) return;
|
|
if (ObjectUtil.isEmpty(userInfo.tenantId) &&
|
|
ObjectUtil.isNotEmpty(globalUserInfo.tenantId)) {
|
|
userInfo.tenantId = globalUserInfo.tenantId;
|
|
}
|
|
await _setSetting(userJson: userInfo);
|
|
}
|
|
|
|
static Future<void> setCanteenExtraPriceConfig(
|
|
CanteenExtraPriceSetting canteenExtraPriceConfig,
|
|
) async {
|
|
final config = await getCanteenExtraPriceConfig();
|
|
if (config == canteenExtraPriceConfig) return;
|
|
await _setSetting(canteenExtraPriceConfig: canteenExtraPriceConfig);
|
|
}
|
|
|
|
/// 读取左侧菜单的顺序和隐藏状态,未知或缺失项由控制器按默认菜单补齐。
|
|
static Future<({List<String> order, Set<String> hidden})>
|
|
getTerminalMenuPreferences() async {
|
|
final setting = await _getSetting();
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
final order = (sysJson[_terminalMenuOrderKey] as List<dynamic>?)
|
|
?.whereType<String>()
|
|
.toList() ??
|
|
const <String>[];
|
|
final hidden = (sysJson[_hiddenTerminalMenusKey] as List<dynamic>?)
|
|
?.whereType<String>()
|
|
.toSet() ??
|
|
const <String>{};
|
|
return (order: order, hidden: hidden);
|
|
}
|
|
|
|
/// 菜单布局属于设备级 UI 设置,直接复用 setting 表中的 sysJson,避免增加数据库字段和迁移。
|
|
static Future<void> setTerminalMenuPreferences({
|
|
required List<String> order,
|
|
required Set<String> hidden,
|
|
}) async {
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) {
|
|
throw StateError('终端设置尚未初始化');
|
|
}
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
sysJson[_terminalMenuOrderKey] = order;
|
|
sysJson[_hiddenTerminalMenusKey] = hidden.toList();
|
|
setting.sysJson = json.encode(sysJson);
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
}
|
|
|
|
/// 读取支付方式的完整顺序;显隐仍由 SysSetting.usePayDisplayType 维护。
|
|
static Future<List<String>> getPayTypeOrder() async {
|
|
final setting = await _getSetting();
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
return (sysJson[_payTypeOrderKey] as List<dynamic>?)
|
|
?.whereType<String>()
|
|
.toList() ??
|
|
const <String>[];
|
|
}
|
|
|
|
/// 支付排序属于终端 UI 扩展配置,与现有支付显隐和默认方式一起原子保存。
|
|
static Future<void> setPayTypePreferences({
|
|
required SysSetting sysInfo,
|
|
required List<OrderPayDisplayType> order,
|
|
}) async {
|
|
// 在首次异步等待前生成快照,避免连续拖动时后一次修改污染本次落盘内容。
|
|
final nextSysJson = sysInfo.toJson();
|
|
final visiblePayTypes = nextSysJson['usePayDisplayType'];
|
|
final defaultPayType = nextSysJson['defaultPayDisplayType'];
|
|
final orderCodes = order.map((item) => item.code).toList();
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) {
|
|
throw StateError('终端设置尚未初始化');
|
|
}
|
|
final current = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
current['usePayDisplayType'] = visiblePayTypes;
|
|
current['defaultPayDisplayType'] = defaultPayType;
|
|
current[_payTypeOrderKey] = orderCodes;
|
|
setting.sysJson = json.encode(current);
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
}
|
|
|
|
/// 读取收银页底部快捷操作显隐;旧终端没有配置时保持两个入口都显示。
|
|
static Future<({bool showHoldAction, bool showMoreAction})>
|
|
getCashierPagePreferences() async {
|
|
final setting = await _getSetting();
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
return (
|
|
showHoldAction: sysJson[_cashierShowHoldActionKey] != false,
|
|
showMoreAction: sysJson[_cashierShowMoreActionKey] != false,
|
|
);
|
|
}
|
|
|
|
/// 收银快捷操作属于本机页面布局配置,继续复用 sysJson,避免增加数据库字段。
|
|
static Future<void> setCashierPagePreferences({
|
|
required bool showHoldAction,
|
|
required bool showMoreAction,
|
|
}) async {
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) throw StateError('终端设置尚未初始化');
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
sysJson[_cashierShowHoldActionKey] = showHoldAction;
|
|
sysJson[_cashierShowMoreActionKey] = showMoreAction;
|
|
setting.sysJson = json.encode(sysJson);
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
}
|
|
|
|
/// 读写卡协议配置属于设备本地扩展设置,复用 sysJson 保存且不修改数据库结构。
|
|
static Future<SerialCardConfig> getSerialCardConfig() async {
|
|
final setting = await _getSetting();
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
final source = sysJson[_serialCardConfigKey];
|
|
if (source is! Map) return const SerialCardConfig();
|
|
try {
|
|
return SerialCardConfig.fromJson(Map<String, dynamic>.from(source));
|
|
} on Object {
|
|
// 旧版本或人工修改的异常配置不能阻断收银读卡,无法解析时回退设备默认参数。
|
|
return const SerialCardConfig();
|
|
}
|
|
}
|
|
|
|
/// 密钥只写入本机设置和串口模块,不记录到日志,也不随普通业务接口上传。
|
|
static Future<void> setSerialCardConfig(SerialCardConfig config) async {
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) throw StateError('终端设置尚未初始化');
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
sysJson[_serialCardConfigKey] = config.toJson();
|
|
setting.sysJson = json.encode(sysJson);
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
}
|
|
|
|
/// 查询方式顺序和默认项属于页面交互配置,继续保存在 sysJson 中,不增加数据库字段。
|
|
static Future<ReservationQueryPagePreferences>
|
|
getReservationQueryPagePreferences() async {
|
|
final setting = await _getSetting();
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
final byCode = {
|
|
for (final method in ReservationRecognitionMethod.values)
|
|
method.code: method,
|
|
};
|
|
final restored = <ReservationRecognitionMethod>[];
|
|
final storedOrder =
|
|
(sysJson[_reservationQueryMethodOrderKey] as List<dynamic>?)
|
|
?.whereType<String>() ??
|
|
const <String>[];
|
|
for (final code in storedOrder) {
|
|
final method = byCode[code];
|
|
if (method != null && !restored.contains(method)) restored.add(method);
|
|
}
|
|
for (final method in ReservationRecognitionMethod.values) {
|
|
if (!restored.contains(method)) restored.add(method);
|
|
}
|
|
final storedDefault =
|
|
byCode[sysJson[_reservationQueryDefaultMethodKey] as String?];
|
|
final defaultMethod =
|
|
storedDefault != null && restored.contains(storedDefault)
|
|
? storedDefault
|
|
: restored.first;
|
|
final verificationDateScope = ReservationVerificationDateScope.values
|
|
.where(
|
|
(scope) =>
|
|
scope.code ==
|
|
sysJson[_reservationQueryVerificationDateScopeKey],
|
|
)
|
|
.firstOrNull ??
|
|
ReservationVerificationDateScope.today;
|
|
return ReservationQueryPagePreferences(
|
|
methodOrder: List.unmodifiable(restored),
|
|
defaultMethod: defaultMethod,
|
|
// 旧设置没有该键时继续脱敏,避免升级后意外展示完整姓名。
|
|
nameMaskEnabled: sysJson[_reservationQueryNameMaskEnabledKey] != false,
|
|
verificationEnabled:
|
|
sysJson[_reservationQueryVerificationEnabledKey] == true,
|
|
verificationDateScope: verificationDateScope,
|
|
);
|
|
}
|
|
|
|
/// 顺序与默认项一起保存,避免连续操作后出现“默认项不在当前列表中”的矛盾状态。
|
|
static Future<void> setReservationQueryPagePreferences({
|
|
required List<ReservationRecognitionMethod> order,
|
|
required ReservationRecognitionMethod defaultMethod,
|
|
required bool nameMaskEnabled,
|
|
required bool verificationEnabled,
|
|
required ReservationVerificationDateScope verificationDateScope,
|
|
}) async {
|
|
final normalized = <ReservationRecognitionMethod>[];
|
|
for (final method in order) {
|
|
if (!normalized.contains(method)) normalized.add(method);
|
|
}
|
|
for (final method in ReservationRecognitionMethod.values) {
|
|
if (!normalized.contains(method)) normalized.add(method);
|
|
}
|
|
final normalizedDefault =
|
|
normalized.contains(defaultMethod) ? defaultMethod : normalized.first;
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) {
|
|
throw StateError('终端设置尚未初始化');
|
|
}
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
sysJson[_reservationQueryMethodOrderKey] =
|
|
normalized.map((method) => method.code).toList();
|
|
sysJson[_reservationQueryDefaultMethodKey] = normalizedDefault.code;
|
|
sysJson[_reservationQueryNameMaskEnabledKey] = nameMaskEnabled;
|
|
sysJson[_reservationQueryVerificationEnabledKey] = verificationEnabled;
|
|
sysJson[_reservationQueryVerificationDateScopeKey] =
|
|
verificationDateScope.code;
|
|
setting.sysJson = json.encode(sysJson);
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
}
|
|
|
|
/// 读取指定“路由 + 功能键”场景最近使用的人工硬件输入,异常旧数据会被忽略。
|
|
static Future<List<HardwareInputHistoryEntry>> getHardwareInputHistory(
|
|
String sceneKey,
|
|
) async {
|
|
final store = await _getHardwareInputHistoryStore();
|
|
return List.unmodifiable(store.entriesFor(sceneKey));
|
|
}
|
|
|
|
/// 保存当前场景最近 5 条输入;相同输入只更新备注和时间并置顶,不产生重复记录。
|
|
static Future<void> saveHardwareInputHistory({
|
|
required String sceneKey,
|
|
required String value,
|
|
String? remark,
|
|
}) async {
|
|
final normalizedValue = value.trim();
|
|
if (normalizedValue.isEmpty) return;
|
|
final app = Get.find<AppControl>();
|
|
final settingDao = app.dataBase.getSettingDao;
|
|
final setting = await settingDao.get();
|
|
if (setting == null) throw StateError('终端设置尚未初始化');
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
final store = _decodeHardwareInputHistoryStore(
|
|
sysJson[_hardwareInputHistoryKey],
|
|
);
|
|
final nextStore = store.save(
|
|
sceneKey: sceneKey,
|
|
value: normalizedValue,
|
|
remark: remark ?? '',
|
|
updatedAt: DateTime.now(),
|
|
);
|
|
sysJson[_hardwareInputHistoryKey] = nextStore.toJson();
|
|
setting.sysJson = json.encode(sysJson);
|
|
await settingDao.edit(setting);
|
|
await _settingCache.putFile(
|
|
_settingKey,
|
|
Uint8List.fromList(utf8.encode(json.encode(setting.toJson()))),
|
|
fileExtension: 'json',
|
|
);
|
|
}
|
|
|
|
/// 从现有 sysJson 扩展配置读取强类型历史模型,单条异常数据不影响人工输入主流程。
|
|
static Future<HardwareInputHistoryStore>
|
|
_getHardwareInputHistoryStore() async {
|
|
final setting = await _getSetting();
|
|
final sysJson = Map<String, dynamic>.from(json.decode(setting.sysJson));
|
|
return _decodeHardwareInputHistoryStore(sysJson[_hardwareInputHistoryKey]);
|
|
}
|
|
|
|
/// JSON Map 仅停留在设置存储边界,弹窗与去重逻辑统一操作强类型模型。
|
|
static HardwareInputHistoryStore _decodeHardwareInputHistoryStore(
|
|
Object? source,
|
|
) {
|
|
if (source is! Map) return HardwareInputHistoryStore.empty;
|
|
try {
|
|
return HardwareInputHistoryStore.fromJson(
|
|
Map<String, dynamic>.from(source),
|
|
);
|
|
} on Object {
|
|
return HardwareInputHistoryStore.empty;
|
|
}
|
|
}
|
|
|
|
// 根据后台返回的数据更新到缓存
|
|
static Future<void> updateSysInfoByService(ServiceHardware data) async {
|
|
if (ObjectUtil.isEmpty(data)) {
|
|
final setting = SysSetting(
|
|
sysType: SysType.CANTEEN,
|
|
androidId: await AppSysTool.getAndroidId(),
|
|
sqlAddress: await AppFileTool.getDatabaseBackupPath(),
|
|
);
|
|
await _setSetting(sysJson: setting);
|
|
return;
|
|
}
|
|
final sysSetting = await AppSettingTool.getSysSetting();
|
|
final id = data.id;
|
|
if (ObjectUtil.isNotEmpty(id)) {
|
|
sysSetting.serviceId = id;
|
|
}
|
|
final name = data.name;
|
|
if (ObjectUtil.isNotEmpty(name)) {
|
|
sysSetting.serviceName = name;
|
|
}
|
|
final type = data.type.toString();
|
|
if (ObjectUtil.isNotEmpty(type)) {
|
|
final t = SysType.values.fromCode(type);
|
|
if (ObjectUtil.isNotEmpty(t)) {
|
|
sysSetting.sysType = t!;
|
|
}
|
|
}
|
|
final merchantId = data.merchantId;
|
|
if (ObjectUtil.isNotEmpty(merchantId)) {
|
|
sysSetting.serviceMerchantId = merchantId;
|
|
}
|
|
final hardGroupId = data.hardGroupId;
|
|
if (ObjectUtil.isNotEmpty(hardGroupId)) {
|
|
sysSetting.hardGroupId = hardGroupId;
|
|
}
|
|
final merchantDeptId = data.merchantDeptId;
|
|
if (ObjectUtil.isNotEmpty(merchantDeptId)) {
|
|
sysSetting.merchantDeptId = merchantDeptId;
|
|
}
|
|
final mqClientId = data.mqClientId;
|
|
if (ObjectUtil.isNotEmpty(mqClientId)) {
|
|
sysSetting.mqClientId = mqClientId;
|
|
}
|
|
final mainTopic = data.mainTopic;
|
|
if (ObjectUtil.isNotEmpty(mainTopic)) {
|
|
sysSetting.mainTopic = mainTopic;
|
|
}
|
|
final mqSocketAddress = data.mqSocketAddress;
|
|
if (ObjectUtil.isNotEmpty(mqSocketAddress)) {
|
|
sysSetting.mqSocketAddress = mqSocketAddress;
|
|
}
|
|
final mqSocketPort = data.mqSocketPort;
|
|
if (ObjectUtil.isNotEmpty(mqSocketPort)) {
|
|
sysSetting.mqSocketPort = mqSocketPort;
|
|
}
|
|
final mqUsername = data.mqUsername;
|
|
if (ObjectUtil.isNotEmpty(mqUsername)) {
|
|
sysSetting.mqUsername = mqUsername;
|
|
}
|
|
final mqPassword = data.mqPassword;
|
|
if (ObjectUtil.isNotEmpty(mqPassword)) {
|
|
sysSetting.mqPassword = mqPassword;
|
|
}
|
|
final faceAppId = data.faceAppId;
|
|
if (ObjectUtil.isNotEmpty(faceAppId)) {
|
|
sysSetting.faceAppId = faceAppId;
|
|
}
|
|
final faceSdkKey = data.faceSdkKey;
|
|
if (ObjectUtil.isNotEmpty(faceSdkKey)) {
|
|
sysSetting.faceSdkKey = faceSdkKey;
|
|
}
|
|
final faceActiveKey = data.faceActiveKey;
|
|
if (ObjectUtil.isNotEmpty(faceActiveKey)) {
|
|
sysSetting.faceActiveKey = faceActiveKey;
|
|
}
|
|
final android = data.uniqueCode;
|
|
if (ObjectUtil.isNotEmpty(android)) {
|
|
sysSetting.androidId = android;
|
|
}
|
|
sysSetting.syncTime = DateTime.now();
|
|
await _setSetting(sysJson: sysSetting);
|
|
}
|
|
|
|
/// 绑定设备信息
|
|
static Future<bool> bindSys(int serviceId) async {
|
|
var androidId = await AppSysTool.getAndroidId();
|
|
if (ObjectUtil.isEmpty(androidId)) return false;
|
|
final pa = {"id": serviceId, "uniqueCode": androidId};
|
|
try {
|
|
final data = await HardApi.bind(pa);
|
|
if (data == null) {
|
|
logger.e("绑定设备信息pa:|${jsonEncode(pa)}|;res:$data;");
|
|
return false;
|
|
}
|
|
await AppSettingTool.updateSysInfoByService(data);
|
|
return true;
|
|
} catch (e, stack) {
|
|
logger.e("|$_tag|绑定信息错误error:|$e|stack:$stack");
|
|
}
|
|
return false;
|
|
}
|
|
}
|