refactor: 优化设备配置同步逻辑,修复参数传递问题

主要变更:
1.  修复相机背景色为纯黑
2.  调整HTTP请求序列化库为Newtonsoft.Json并添加调试日志
3.  统一设备请求使用ble_mac而非device_sn
4.  重构DeviceConfig实现深拷贝和差异对比,仅同步变更字段
5.  优化指纹数据同步逻辑,新增本地状态更新方法
6.  新增亮度配置同步调用
7.  修复用户列表UI缺少遮罩
This commit is contained in:
“虞渠成” 2026-06-29 13:12:20 +08:00
parent e3cdc4b539
commit cc336fd4af
9 changed files with 187 additions and 27 deletions

View File

@ -972,6 +972,8 @@ GameObject:
- component: {fileID: 6156444094017917638}
- component: {fileID: 196291696332333663}
- component: {fileID: 6174687206804186718}
- component: {fileID: 6802373552931830562}
- component: {fileID: 7282265199794192874}
m_Layer: 5
m_Name: "\u88AB\u5206\u4EAB\u8005\u5217\u8868"
m_TagString: Untagged
@ -1037,6 +1039,49 @@ MonoBehaviour:
m_OnValueChanged:
m_PersistentCalls:
m_Calls: []
--- !u!114 &6802373552931830562
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7074308004564379890}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_ShowMaskGraphic: 0
--- !u!114 &7282265199794192874
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7074308004564379890}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &7279844199628844094
GameObject:
m_ObjectHideFlags: 0

View File

@ -855,7 +855,7 @@ Camera:
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 2
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0

View File

@ -571,11 +571,65 @@ namespace Kill.Managers
}
/// <summary>
/// 将枚举值转换为服务器配置字符串(写)
/// 将枚举值转换为服务器配置字符串(写)
/// </summary>
public static string ToServerString<T>(T enumValue) where T : struct
{
return enumValue.ToString().ToLower();
return enumValue.ToString().ToUpper();
}
/// <summary>
/// 深拷贝当前配置
/// </summary>
public DeviceConfig Clone()
{
var clone = new DeviceConfig();
var fields = typeof(DeviceConfig).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var field in fields)
{
var value = field.GetValue(this);
if (value != null)
{
// 值类型和字符串直接赋值即可
field.SetValue(clone, value);
}
}
return clone;
}
/// <summary>
/// 获取与原始配置相比发生变化的字段(包含 device_sn
/// </summary>
/// <param name="original">原始配置</param>
/// <returns>变化字段字典key 为字段名value 为当前值;若无变化返回空字典</returns>
public Dictionary<string, object> GetChangedFields(DeviceConfig original)
{
var changed = new Dictionary<string, object>();
if (original == null)
{
// 没有原始配置时,认为所有非空字段都发生变化
var allFields = typeof(DeviceConfig).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var field in allFields)
{
var value = field.GetValue(this);
if (value != null)
changed[field.Name] = value;
}
return changed;
}
var fields = typeof(DeviceConfig).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var field in fields)
{
var currentValue = field.GetValue(this);
var originalValue = field.GetValue(original);
if (!Equals(currentValue, originalValue))
{
changed[field.Name] = currentValue;
}
}
return changed;
}
}

View File

@ -98,6 +98,8 @@ namespace Kill.Managers
}
}
public DeviceConfig deviceConfig;
// 从服务器获取的原始配置快照,用于比对变化字段
private DeviceConfig _originalDeviceConfig;
#region
/// <summary>
@ -115,7 +117,9 @@ namespace Kill.Managers
onSuccess: (data) =>
{
result = data.data;
deviceConfig=result;
deviceConfig = result;
// 保存原始快照,用于后续差异对比
_originalDeviceConfig = result?.Clone();
},
onError: (code, msg) =>
{
@ -125,16 +129,31 @@ namespace Kill.Managers
}
/// <summary>
/// 修改设备配置(空值字段不会被修改
/// 修改设备配置(只提交与原始配置相比发生变化的字段
/// </summary>
public async Task<bool> UpdateDeviceConfig(string deviceSn, DeviceConfig config)
/// <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)
{
if (config == null)
{
Debug.LogError("[DataManager] UpdateDeviceConfig: config 为 null");
return false;
}
config.device_sn = deviceSn;
var changedFields = config.GetChangedFields(original);
// device_sn 必须始终携带
changedFields["device_sn"] = deviceSn;
// 构建JSON跳过null值字段
string json = BuildDeviceConfigJson(config);
if (changedFields.Count == 0)
{
Debug.Log("[DataManager] UpdateDeviceConfig: 没有字段变化,跳过同步");
return true;
}
var response = await NetworkCtrl.Instance.Post<NoDataResponse>("/api/v1/device/config", json);
var response = await NetworkCtrl.Instance.Put<NoDataResponse>("/api/v1/device/config", changedFields);
bool success = false;
ResponseCodeHandler.HandleResponse(response,
@ -231,11 +250,17 @@ namespace Kill.Managers
/// <summary>
/// 同步设备配置到服务器WiFi在线时调用由各设置页面Sync方法调用
/// 只提交与原始配置相比发生变化的字段
/// </summary>
public async void SyncDeviceConfigToServer()
{
if (!hasWifi) return;
await UpdateDeviceConfig(selectedDevice.ble_mac, deviceConfig);
bool success = await UpdateDeviceConfig(selectedDevice.ble_mac, deviceConfig, _originalDeviceConfig);
if (success)
{
// 同步成功后刷新原始快照
_originalDeviceConfig = deviceConfig?.Clone();
}
}
/// <summary>
@ -249,8 +274,8 @@ namespace Kill.Managers
tasks = tasks
};
var response = await NetworkCtrl.Instance.Post<NoDataResponse>(
"/api/v1/device/schedule-tasks", JsonUtility.ToJson(requestData));
var response = await NetworkCtrl.Instance.Put<NoDataResponse>(
"/api/v1/device/schedule-tasks", requestData);
bool success = false;
ResponseCodeHandler.HandleResponse(response,
@ -278,8 +303,8 @@ namespace Kill.Managers
fingerprints = fingerprints
};
var response = await NetworkCtrl.Instance.Post<NoDataResponse>(
"/api/v1/device/fingerprints", JsonUtility.ToJson(requestData));
var response = await NetworkCtrl.Instance.Put<NoDataResponse>(
"/api/v1/device/fingerprints", requestData);
bool success = false;
ResponseCodeHandler.HandleResponse(response,
@ -303,7 +328,7 @@ namespace Kill.Managers
{
var response = await NetworkCtrl.Instance.Get<FingerprintListResponse>(
"/api/v1/device/fingerprints",
new Dictionary<string, string> { { "device_sn", selectedDevice.device_sn } }
new Dictionary<string, string> { { "device_sn", selectedDevice.ble_mac } }
);
ResponseCodeHandler.HandleResponse(response,

View File

@ -171,8 +171,8 @@ namespace Kill.Network
/// </summary>
public async Task<HttpResponse<T>> Put<T>(string url, object data, HttpRequestConfig config = null)
{
string jsonData = data != null ? JsonUtility.ToJson(data) : "";
Debug.Log(jsonData);
string jsonData = data != null ? JsonConvert.SerializeObject(data) : "";
Debug.Log("发送数据:" + jsonData);
return await SendRequest<T>(url, HttpMethod.PUT, jsonData, config, "application/json");
}

View File

@ -100,12 +100,23 @@ namespace Kill.UI.Pages
{
Loom.QueueOnMainThread(() =>
{
foreach (var user in UserListResponse.Users)
// 将蓝牙用户列表同步到本地,供后续上传到服务器使用
DataManager.Instance.fingerprintUserDatas.Clear();
if (UserListResponse.Users != null)
{
if (user.Username == nowUserid)
foreach (var user in UserListResponse.Users)
{
bool isfingerOn = user.HasFingerprint;
break;
DataManager.Instance.fingerprintUserDatas.Add(new FingerprintUserData
{
username = user.Username,
fingerprint_id = user.FingerprintId,
has_fingerprint = user.HasFingerprint
});
if (user.Username == nowUserid)
{
isfingerOn = user.HasFingerprint;
}
}
}
initActions.Remove(ReadFingerprint);
@ -159,7 +170,8 @@ namespace Kill.UI.Pages
if (response.IsSuccess)
{
fingerTip.SetActive(true);
// 录制成功,同步到服务器
// 录制成功,更新当前用户指纹状态并同步到服务器
UpdateLocalFingerprintState(nowUserid, true);
await SyncFingerprintsToServerAsync();
LoadingUI.Hide();
}
@ -171,11 +183,33 @@ namespace Kill.UI.Pages
});
}
/// <summary>
/// 更新本地 fingerprintUserDatas 中指定用户的指纹状态
/// </summary>
private void UpdateLocalFingerprintState(string username, bool hasFingerprint)
{
var list = DataManager.Instance.fingerprintUserDatas;
var existing = list.Find(u => u.username == username);
if (existing.username != null)
{
existing.has_fingerprint = hasFingerprint;
}
else
{
list.Add(new FingerprintUserData
{
username = username,
fingerprint_id = 0,
has_fingerprint = hasFingerprint
});
}
}
private async Task SyncFingerprintsToServerAsync()
{
if (!DataManager.Instance.hasWifi) return;
await DataManager.Instance.UpdateFingerprintsToServer(
DataManager.Instance.selectedDevice.device_sn,
DataManager.Instance.selectedDevice.ble_mac,
DataManager.Instance.fingerprintUserDatas);
}

View File

@ -123,6 +123,8 @@ namespace Kill.UI.Pages
{
if (success)
{
SyncBrightnessConfig();
DataManager.Instance.SyncDeviceConfigToServer();
UpdateUI();
}
else

View File

@ -873,7 +873,7 @@ namespace Kill.UI.Pages
{
deviceCtrl?.InitDeviceControl(false);
await DataManager.Instance.GetDeviceConfig(selectedDevice.ble_mac);
await DataManager.Instance.GetScheduleTasks(selectedDevice.device_sn);
await DataManager.Instance.GetScheduleTasks(selectedDevice.ble_mac);
scheduleSettingButton.interactable = true;
moreSettingButton.interactable = true;
InitDeviceUIFromConfig();
@ -1612,7 +1612,7 @@ namespace Kill.UI.Pages
Debug.Log("[HomePageCtrl] 设备WiFi上线初始化UI");
await DataManager.Instance.GetDeviceConfig(selectedDevice.ble_mac);
if (stopPolling) break;
await DataManager.Instance.GetScheduleTasks(selectedDevice.device_sn);
await DataManager.Instance.GetScheduleTasks(selectedDevice.ble_mac);
if (stopPolling) break;
ScheduleUIUpdate(() =>
{

View File

@ -112,7 +112,7 @@ namespace Kill.UI.Pages
if (DataManager.Instance.hasWifi && !DataManager.Instance.hasBluetooth)
{
Debug.Log("[ScheduleSettingPage] WiFi模式读取定时任务...");
await DataManager.Instance.GetScheduleTasks(DataManager.Instance.selectedDevice.device_sn);
await DataManager.Instance.GetScheduleTasks(DataManager.Instance.selectedDevice.ble_mac);
Debug.Log($"[ScheduleSettingPage] WiFi获取到 {DataManager.Instance.scheduleTaskDatas.Count} 条原始数据");
// 将API数据转换为ScheduleTask过滤全0无效任务
@ -636,7 +636,7 @@ namespace Kill.UI.Pages
});
}
await DataManager.Instance.UpdateScheduleTasksToServer(
DataManager.Instance.selectedDevice.device_sn, tasksData);
DataManager.Instance.selectedDevice.ble_mac, tasksData);
}
}
else