killapp/Assets/Scripts/Managers/DataManager.cs

582 lines
21 KiB
C#
Raw Normal View History

2026-04-24 16:57:44 +08:00
using System;
2026-04-16 14:57:19 +08:00
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Kill.Network;
2026-06-17 15:42:55 +08:00
using Kill.Managers.ResponseModels;
2026-04-24 16:57:44 +08:00
using Kill.UI.Components;
2026-04-16 14:57:19 +08:00
using UnityEngine;
namespace Kill.Managers
{
public class DataManager : MonoBehaviour
{
public string selectedDeviceMac="";
2026-04-16 14:57:19 +08:00
public static DataManager Instance { get; private set; }
public DeviceInfo selectedDevice;
2026-06-10 15:04:14 +08:00
public List<DeviceInfo> OwnedDevices = new List<DeviceInfo>();
public List<DeviceInfo> SharedDevices = new List<DeviceInfo>();
2026-05-18 08:42:33 +08:00
public bool isOwner;
2026-06-12 09:42:44 +08:00
public bool hasWifi;
2026-06-17 15:42:55 +08:00
public bool hasBluetooth;
public FingerprintListResponseData fingerprintListData = new FingerprintListResponseData();
public List<FingerprintUserData> fingerprintUserDatas = new List<FingerprintUserData>();
public List<ScheduleTaskData> scheduleTaskDatas = new List<ScheduleTaskData>();
2026-06-12 09:42:44 +08:00
2026-04-16 14:57:19 +08:00
private void Awake()
{
Instance = this;
}
public async Task Init()
{
InitUser();
GetSelectedDeviceMac();
LoadLockSettings();
2026-04-16 14:57:19 +08:00
}
public string token = "";
public UserInfo userInfo = new UserInfo();
public void SetToken(string token,UserInfo userInfo)
{
this.token = token;
this.userInfo = userInfo;
string userData =JsonUtility.ToJson(userInfo);
2026-04-20 08:31:41 +08:00
Debug.Log(userData);
2026-04-16 14:57:19 +08:00
PlayerPrefs.SetString("token", token);
PlayerPrefs.SetString("userData", userData);
2026-04-24 16:57:44 +08:00
NetworkCtrl.Instance.RemoveGlobalHeader("token");
NetworkCtrl.Instance.AddGlobalHeader("token", token);
2026-04-16 14:57:19 +08:00
}
public void SavaSelectedDeviceMac(string mac)
{
selectedDeviceMac=mac;
PlayerPrefs.SetString("selectedDeviceMac", selectedDeviceMac);
}
public void GetSelectedDeviceMac()
{
selectedDeviceMac=PlayerPrefs.GetString("selectedDeviceMac", "");
}
#region 使
private const string OWNED_DEVICES_KEY = "ownedDevicesCache";
private const string SHARED_DEVICES_KEY = "sharedDevicesCache";
/// <summary>
/// 将当前 OwnedDevices/SharedDevices 持久化到本地(按当前登录用户隔离)
/// </summary>
public void SaveDeviceLists()
{
try
{
string userId = userInfo?.id ?? "";
string ownedJson = JsonUtility.ToJson(OwnedDevices != null ? new DeviceInfoListWrapper(OwnedDevices) : new DeviceInfoListWrapper());
string sharedJson = JsonUtility.ToJson(SharedDevices != null ? new DeviceInfoListWrapper(SharedDevices) : new DeviceInfoListWrapper());
PlayerPrefs.SetString(OWNED_DEVICES_KEY + "_" + userId, ownedJson);
PlayerPrefs.SetString(SHARED_DEVICES_KEY + "_" + userId, sharedJson);
PlayerPrefs.Save();
}
catch (Exception ex)
{
Debug.LogError($"[DataManager] 保存设备列表缓存失败: {ex.Message}");
}
}
/// <summary>
/// 从本地恢复 OwnedDevices/SharedDevices返回是否成功恢复
/// </summary>
public bool LoadDeviceLists()
{
try
{
string userId = userInfo?.id ?? "";
string ownedJson = PlayerPrefs.GetString(OWNED_DEVICES_KEY + "_" + userId, "");
string sharedJson = PlayerPrefs.GetString(SHARED_DEVICES_KEY + "_" + userId, "");
OwnedDevices = string.IsNullOrEmpty(ownedJson) ? new List<DeviceInfo>() : JsonUtility.FromJson<DeviceInfoListWrapper>(ownedJson)?.ToList() ?? new List<DeviceInfo>();
SharedDevices = string.IsNullOrEmpty(sharedJson) ? new List<DeviceInfo>() : JsonUtility.FromJson<DeviceInfoListWrapper>(sharedJson)?.ToList() ?? new List<DeviceInfo>();
return OwnedDevices.Count > 0 || SharedDevices.Count > 0;
}
catch (Exception ex)
{
Debug.LogError($"[DataManager] 读取设备列表缓存失败: {ex.Message}");
OwnedDevices = new List<DeviceInfo>();
SharedDevices = new List<DeviceInfo>();
return false;
}
}
/// <summary>
/// 清空本地缓存的设备列表(登出时调用)
/// </summary>
public void ClearDeviceLists()
{
string userId = userInfo?.id ?? "";
PlayerPrefs.DeleteKey(OWNED_DEVICES_KEY + "_" + userId);
PlayerPrefs.DeleteKey(SHARED_DEVICES_KEY + "_" + userId);
PlayerPrefs.Save();
OwnedDevices = new List<DeviceInfo>();
SharedDevices = new List<DeviceInfo>();
}
[Serializable]
private class DeviceInfoListWrapper
{
public List<DeviceInfo> items = new List<DeviceInfo>();
public DeviceInfoListWrapper() { }
public DeviceInfoListWrapper(List<DeviceInfo> source)
{
if (source != null) items.AddRange(source);
}
public List<DeviceInfo> ToList() => new List<DeviceInfo>(items);
}
#endregion
#region
private const string LOCK_TIME_KEY = "autoLockTime";
/// <summary>自动锁定时间默认值(秒)</summary>
private const int DEFAULT_LOCK_TIME = 180;
/// <summary>永不锁定的哨兵值(秒,极大值)</summary>
public const int NEVER_LOCK = int.MaxValue;
/// <summary>
/// 自动锁定时间(秒),可配置项,按当前登录账号保存在本地
/// </summary>
public int lockTime = DEFAULT_LOCK_TIME;
/// <summary>
/// 上次解锁时间(秒基于Time.realtimeSinceStartup)
/// <para>进入app时重置为0解锁后记录时间0表示进入app后尚未解锁</para>
/// </summary>
public float lastUnlockTime = 0;
/// <summary>进入app时调用重置解锁时间并读取当前账号的自动锁定时间配置</summary>
public void LoadLockSettings()
{
lastUnlockTime = 0;
string userId = userInfo?.id ?? "";
lockTime = PlayerPrefs.GetInt(LOCK_TIME_KEY + "_" + userId, DEFAULT_LOCK_TIME);
}
/// <summary>设置自动锁定时间(秒)并保存到本地(与当前登录账号关联),传 NEVER_LOCK 表示永不锁定</summary>
public void SetLockTime(int seconds)
{
lockTime = seconds;
PlayerPrefs.SetInt(LOCK_TIME_KEY + "_" + (userInfo?.id ?? ""), seconds);
PlayerPrefs.Save();
}
/// <summary>是否启用了永不锁定</summary>
public bool IsNeverLock => lockTime == NEVER_LOCK;
/// <summary>解锁后记录当前时间(作为自动锁定倒计时的起点)</summary>
public void RecordUnlock()
{
lastUnlockTime = Time.realtimeSinceStartup;
}
#endregion
2026-04-16 14:57:19 +08:00
public void InitUser()
{
token = PlayerPrefs.GetString("token", "");
string userData = PlayerPrefs.GetString("userData", "");
userInfo = JsonUtility.FromJson<UserInfo>(userData);
2026-04-24 16:57:44 +08:00
NetworkCtrl.Instance.RemoveGlobalHeader("token");
NetworkCtrl.Instance.AddGlobalHeader("token",token);
Debug.Log(token);
2026-04-16 14:57:19 +08:00
}
public void ClearInfo()
{
token = "";
userInfo = new UserInfo();
PlayerPrefs.DeleteKey("token");
PlayerPrefs.DeleteKey("userData");
}
2026-04-28 16:35:51 +08:00
public async Task<bool> TokenLogin()
2026-04-24 16:57:44 +08:00
{
LoadingUI.Show();
try
{
// 获取用户详情
var response = await NetworkCtrl.Instance.Post<LoginResponse>("/api/v1/auth/token-login");
LoadingUI.Hide();
2026-04-28 16:35:51 +08:00
if(response.Data.code==200)
{
SetToken(response.Data.data.token,response.Data.data.user);
return true;
}
else
{
ClearInfo();
return false;
}
2026-04-24 16:57:44 +08:00
}
catch (Exception ex)
{
LoadingUI.Hide();
Debug.LogError($"TokenLogin 异常: {ex.Message}");
2026-04-28 16:35:51 +08:00
return false;
2026-04-24 16:57:44 +08:00
}
}
2026-06-12 09:42:44 +08:00
public DeviceConfig deviceConfig;
// 从服务器获取的原始配置快照,用于比对变化字段
private DeviceConfig _originalDeviceConfig;
2026-06-12 09:42:44 +08:00
#region
/// <summary>
/// 获取设备配置
/// </summary>
public async Task GetDeviceConfig(string deviceSn)
{
var response = await NetworkCtrl.Instance.Get<DeviceConfigResponse>(
"/api/v1/device/config",
new Dictionary<string, string> { { "device_sn", deviceSn } }
);
DeviceConfig result = null;
ResponseCodeHandler.HandleResponse(response,
onSuccess: (data) =>
{
result = data.data;
deviceConfig = result;
// 保存原始快照,用于后续差异对比
_originalDeviceConfig = result?.Clone();
2026-06-12 09:42:44 +08:00
},
onError: (code, msg) =>
{
Debug.LogError($"[DataManager] 获取设备配置失败: {msg}");
},
silentErrorTip: true
2026-06-12 09:42:44 +08:00
);
}
/// <summary>
/// 修改设备配置(只提交与原始配置相比发生变化的字段)
2026-06-12 09:42:44 +08:00
/// </summary>
/// <param name="deviceSn">设备 MAC/序列号</param>
/// <param name="config">当前设备配置</param>
/// <param name="original">原始配置快照,传 null 时会提交所有非空字段</param>
public async Task<bool> UpdateDeviceConfig(string deviceSn, DeviceConfig config, DeviceConfig original = null)
2026-06-12 09:42:44 +08:00
{
if (config == null)
{
Debug.LogError("[DataManager] UpdateDeviceConfig: config 为 null");
return false;
}
2026-06-12 09:42:44 +08:00
config.device_sn = deviceSn;
var changedFields = config.GetChangedFields(original);
// device_sn 必须始终携带
changedFields["device_sn"] = deviceSn;
2026-06-12 09:42:44 +08:00
if (changedFields.Count == 0)
{
Debug.Log("[DataManager] UpdateDeviceConfig: 没有字段变化,跳过同步");
return true;
}
2026-06-12 09:42:44 +08:00
var response = await NetworkCtrl.Instance.Put<NoDataResponse>("/api/v1/device/config", changedFields);
2026-06-12 09:42:44 +08:00
bool success = false;
ResponseCodeHandler.HandleResponse(response,
onSuccess: (data) =>
{
success = true;
},
onError: (code, msg) =>
{
Debug.LogError($"[DataManager] 修改设备配置失败: {msg}");
},
silentErrorTip: true
2026-06-12 09:42:44 +08:00
);
return success;
}
/// <summary>
/// 构建设备配置JSON只包含非null字段
/// </summary>
private string BuildDeviceConfigJson(DeviceConfig config)
{
var sb = new System.Text.StringBuilder();
sb.Append("{");
AppendField(sb, "device_sn", config.device_sn);
AppendField(sb, "language", config.language);
AppendField(sb, "is_locked", config.is_locked);
AppendField(sb, "fov_angle", config.fov_angle);
AppendField(sb, "detection_distance", config.detection_distance);
AppendField(sb, "aim_distance", config.aim_distance);
AppendField(sb, "work_mode", config.work_mode);
AppendField(sb, "fill_light_enable", config.fill_light_enable);
AppendField(sb, "fill_light_type", config.fill_light_type);
AppendField(sb, "fill_light_intensity", config.fill_light_intensity);
AppendField(sb, "laser_visible_enable", config.laser_visible_enable);
AppendField(sb, "visual_detect_enable", config.visual_detect_enable);
AppendField(sb, "visual_sensitivity", config.visual_sensitivity);
AppendField(sb, "radar_enable", config.radar_enable);
AppendField(sb, "radar_sensitivity", config.radar_sensitivity);
AppendField(sb, "radar_safe_distance", config.radar_safe_distance);
AppendField(sb, "rgb_enable", config.rgb_enable);
AppendField(sb, "rgb_red", config.rgb_red);
AppendField(sb, "rgb_green", config.rgb_green);
AppendField(sb, "rgb_blue", config.rgb_blue);
AppendField(sb, "rgb_effect", config.rgb_effect);
AppendField(sb, "lcd_auto_brightness", config.lcd_auto_brightness);
AppendField(sb, "lcd_brightness", config.lcd_brightness);
AppendField(sb, "lcd_sleep_enable", config.lcd_sleep_enable);
AppendField(sb, "lcd_sleep_time", config.lcd_sleep_time);
AppendField(sb, "wifi_enable", config.wifi_enable);
AppendField(sb, "wifi_ssid", config.wifi_ssid);
AppendField(sb, "wifi_password", config.wifi_password);
AppendField(sb, "video_record_enable", config.video_record_enable);
AppendField(sb, "record_duration", config.record_duration);
AppendField(sb, "sound_enable", config.sound_enable);
AppendField(sb, "sound_type", config.sound_type);
AppendField(sb, "volume", config.volume);
// 移除末尾逗号
if (sb[sb.Length - 1] == ',')
sb.Length--;
sb.Append("}");
return sb.ToString();
}
private void AppendField(System.Text.StringBuilder sb, string key, object value)
{
if (value == null) return;
sb.Append("\"");
sb.Append(key);
sb.Append("\":");
if (value is string s)
{
sb.Append("\"");
sb.Append(s);
sb.Append("\"");
}
else if (value is bool b)
{
sb.Append(b ? "true" : "false");
}
else
{
sb.Append(value.ToString());
}
sb.Append(",");
}
#endregion
2026-06-17 15:42:55 +08:00
2026-06-24 10:20:15 +08:00
/// <summary>
/// 同步设备配置到服务器WiFi在线时调用由各设置页面Sync方法调用
/// 只提交与原始配置相比发生变化的字段
2026-06-24 10:20:15 +08:00
/// </summary>
public async void SyncDeviceConfigToServer()
{
if (!hasWifi) return;
bool success = await UpdateDeviceConfig(selectedDevice.ble_mac, deviceConfig, _originalDeviceConfig);
if (success)
{
// 同步成功后刷新原始快照
_originalDeviceConfig = deviceConfig?.Clone();
}
2026-06-24 10:20:15 +08:00
}
/// <summary>
/// 更新定时任务到服务器
/// </summary>
public async Task<bool> UpdateScheduleTasksToServer(string deviceSn, List<ScheduleTaskData> tasks)
{
var requestData = new ScheduleTasksUploadRequest
{
device_sn = deviceSn,
tasks = tasks
};
var response = await NetworkCtrl.Instance.Put<NoDataResponse>(
"/api/v1/device/schedule-tasks", requestData);
2026-06-24 10:20:15 +08:00
bool success = false;
ResponseCodeHandler.HandleResponse(response,
onSuccess: (data) =>
{
success = true;
Debug.Log($"[DataManager] 定时任务已同步到服务器,共 {tasks.Count} 条");
},
onError: (code, msg) =>
{
Debug.LogError($"[DataManager] 同步定时任务失败: {msg}");
}
);
return success;
}
/// <summary>
/// 更新指纹列表到服务器
/// </summary>
public async Task<bool> UpdateFingerprintsToServer(string deviceSn, List<FingerprintUserData> fingerprints)
{
var requestData = new FingerprintsUploadRequest
{
device_sn = deviceSn,
fingerprints = fingerprints
};
var response = await NetworkCtrl.Instance.Put<NoDataResponse>(
"/api/v1/device/fingerprints", requestData);
2026-06-24 10:20:15 +08:00
bool success = false;
ResponseCodeHandler.HandleResponse(response,
onSuccess: (data) =>
{
success = true;
Debug.Log($"[DataManager] 指纹列表已同步到服务器,共 {fingerprints.Count} 条");
},
onError: (code, msg) =>
{
Debug.LogError($"[DataManager] 同步指纹列表失败: {msg}");
}
);
return success;
}
2026-06-17 15:42:55 +08:00
/// <summary>
/// 通过WiFi获取指纹列表
/// </summary>
2026-06-17 17:37:49 +08:00
public async Task GetFingerprints()
2026-06-17 15:42:55 +08:00
{
var response = await NetworkCtrl.Instance.Get<FingerprintListResponse>(
"/api/v1/device/fingerprints",
new Dictionary<string, string> { { "device_sn", selectedDevice.ble_mac } }
2026-06-17 15:42:55 +08:00
);
ResponseCodeHandler.HandleResponse(response,
onSuccess: (data) =>
{
fingerprintUserDatas.Clear();
if (data.data?.list != null)
{
fingerprintUserDatas.AddRange(data.data.list);
}
Debug.Log($"[DataManager] 获取到 {fingerprintUserDatas.Count} 条指纹记录");
},
onError: (code, msg) =>
{
Debug.LogError($"[DataManager] 获取指纹列表失败: {msg}");
}
);
}
/// <summary>
/// 通过WiFi获取定时任务列表
/// </summary>
public async Task GetScheduleTasks(string deviceSn)
{
var response = await NetworkCtrl.Instance.Get<ScheduleTaskListDataResponse>(
"/api/v1/device/schedule-tasks",
new Dictionary<string, string> { { "device_sn", deviceSn } }
);
ResponseCodeHandler.HandleResponse(response,
onSuccess: (data) =>
{
scheduleTaskDatas.Clear();
Debug.Log($"[DataManager] 定时任务API返回: total={data.data?.total}, list count={data.data?.list?.Count ?? 0}");
if (data.data?.list != null)
{
scheduleTaskDatas.AddRange(data.data.list);
foreach (var d in scheduleTaskDatas)
{
Debug.Log($"[DataManager] 任务 ID={d.task_id}, enabled={d.enabled}, start={d.start_hour}:{d.start_minute:D2}, end={d.end_hour}:{d.end_minute:D2}, mode={d.mode}, repeat={d.repeat_mask}");
}
}
Debug.Log($"[DataManager] 获取到 {scheduleTaskDatas.Count} 条定时任务");
},
onError: (code, msg) =>
{
Debug.LogError($"[DataManager] 获取定时任务列表失败: {msg}");
}
);
}
}
/// <summary>
/// 指纹用户数据(从服务器获取)
/// </summary>
[System.Serializable]
public class FingerprintUserData
{
public string username;
public int fingerprint_id;
public bool has_fingerprint;
}
}
// 响应模型
namespace Kill.Managers.ResponseModels
{
[System.Serializable]
public class FingerprintListResponse
{
public int code;
public string message;
public FingerprintListResponseData data;
}
[System.Serializable]
public class FingerprintListResponseData
{
public int total;
public int pages;
public int limit;
public int page;
public List<FingerprintUserData> list;
}
[System.Serializable]
public class ScheduleTaskListDataResponse
{
public int code;
public string message;
public ScheduleTaskListData data;
}
[System.Serializable]
public class ScheduleTaskListData
{
public int total;
public int pages;
public int limit;
public int page;
public List<ScheduleTaskData> list;
}
[System.Serializable]
public class ScheduleTaskData
{
public byte task_id;
public bool enabled;
public byte start_hour;
public byte start_minute;
public byte end_hour;
public byte end_minute;
public string mode;
public byte repeat_mask;
2026-04-16 14:57:19 +08:00
}
2026-06-24 10:20:15 +08:00
[System.Serializable]
public class ScheduleTasksUploadRequest
{
public string device_sn;
public List<ScheduleTaskData> tasks;
}
[System.Serializable]
public class FingerprintsUploadRequest
{
public string device_sn;
public List<FingerprintUserData> fingerprints;
}
2026-04-16 14:57:19 +08:00
}