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
|
|
|
|
|
|
{
|
2026-05-11 08:39:33 +08:00
|
|
|
|
public string selectedDeviceMac="";
|
2026-04-16 14:57:19 +08:00
|
|
|
|
public static DataManager Instance { get; private set; }
|
2026-05-11 08:39:33 +08:00
|
|
|
|
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()
|
|
|
|
|
|
{
|
2026-05-11 08:39:33 +08:00
|
|
|
|
InitUser();
|
|
|
|
|
|
GetSelectedDeviceMac();
|
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
|
|
|
|
}
|
2026-05-11 08:39:33 +08:00
|
|
|
|
public void SavaSelectedDeviceMac(string mac)
|
|
|
|
|
|
{
|
|
|
|
|
|
selectedDeviceMac=mac;
|
|
|
|
|
|
PlayerPrefs.SetString("selectedDeviceMac", selectedDeviceMac);
|
|
|
|
|
|
}
|
|
|
|
|
|
public void GetSelectedDeviceMac()
|
|
|
|
|
|
{
|
|
|
|
|
|
selectedDeviceMac=PlayerPrefs.GetString("selectedDeviceMac", "");
|
|
|
|
|
|
}
|
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;
|
|
|
|
|
|
#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;
|
|
|
|
|
|
},
|
|
|
|
|
|
onError: (code, msg) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[DataManager] 获取设备配置失败: {msg}");
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 修改设备配置(空值字段不会被修改)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public async Task<bool> UpdateDeviceConfig(string deviceSn, DeviceConfig config)
|
|
|
|
|
|
{
|
|
|
|
|
|
config.device_sn = deviceSn;
|
|
|
|
|
|
|
|
|
|
|
|
// 构建JSON,跳过null值字段
|
|
|
|
|
|
string json = BuildDeviceConfigJson(config);
|
|
|
|
|
|
|
|
|
|
|
|
var response = await NetworkCtrl.Instance.Post<NoDataResponse>("/api/v1/device/config", json);
|
|
|
|
|
|
|
|
|
|
|
|
bool success = false;
|
|
|
|
|
|
ResponseCodeHandler.HandleResponse(response,
|
|
|
|
|
|
onSuccess: (data) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
success = true;
|
|
|
|
|
|
},
|
|
|
|
|
|
onError: (code, msg) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[DataManager] 修改设备配置失败: {msg}");
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
/// <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",
|
2026-06-17 17:37:49 +08:00
|
|
|
|
new Dictionary<string, string> { { "device_sn", selectedDevice.device_sn } }
|
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
|
|
|
|
}
|
|
|
|
|
|
}
|