Files
biz_xfj_cloud/lib/common/utils/app/app_setting_tool.dart
T
2026-07-24 15:27:20 +08:00

328 lines
11 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 final CacheManager _settingCache = CacheManager(
Config(
'setting_cache',
stalePeriod: const Duration(days: 7),
maxNrOfCacheObjects: 10,
),
);
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);
}
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<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;
}
}