328 lines
11 KiB
Dart
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;
|
|
}
|
|
}
|