1. 新增多语言国家配置项,完善语言包 2. 实现国家选择弹窗组件,支持搜索、滚动定位和返回逻辑 3. 个人页面添加国家选择入口与展示逻辑 4. 排行榜列表新增国家名称展示 5. 优化数据变更检测逻辑,过滤无意义空值 6. 调整部分UI布局适配新增元素
677 lines
16 KiB
C#
677 lines
16 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace Kill.Managers
|
||
{
|
||
|
||
#region AssetBundle 数据
|
||
|
||
[System.Serializable]
|
||
public class AssetBundleInfoList
|
||
{
|
||
public string version;
|
||
public List<AssetBundleInfo> assetbundles;
|
||
|
||
public AssetBundleInfoList(List<AssetBundleInfo> list)
|
||
{
|
||
assetbundles = list;
|
||
}
|
||
}
|
||
|
||
[System.Serializable]
|
||
public class AssetBundleInfo
|
||
{
|
||
public string name;
|
||
public long size;
|
||
public string md5;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 用户数据
|
||
|
||
/// <summary>
|
||
/// 登录请求数据
|
||
/// </summary>
|
||
[Serializable]
|
||
public class LoginRequest
|
||
{
|
||
public string email;
|
||
public string password;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 登录响应数据
|
||
/// </summary>
|
||
[Serializable]
|
||
public class LoginResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public LoginData data;
|
||
}
|
||
|
||
[Serializable]
|
||
public class LoginData
|
||
{
|
||
public string token;
|
||
public UserInfo user;
|
||
}
|
||
|
||
[Serializable]
|
||
public class UserInfo
|
||
{
|
||
public string id;
|
||
public string email;
|
||
public string avatar;
|
||
public string username;
|
||
public string role;
|
||
public string country_code;
|
||
public bool exam_completed;
|
||
public int device_count;
|
||
public int total_kill_count;
|
||
/// <summary>
|
||
/// 单位系统 0公制 1英制
|
||
/// </summary>
|
||
public int unit_system;
|
||
public bool has_simple_password;
|
||
public bool has_complex_password;
|
||
}
|
||
#endregion
|
||
#region 登录注册
|
||
public class EmailCodeRequest
|
||
{
|
||
public string email;
|
||
}
|
||
|
||
public class NoDataResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
}
|
||
public class BoolResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public BoolData data;
|
||
}
|
||
public class BoolData
|
||
{
|
||
public bool registered;
|
||
}
|
||
public class VerifyCodeRequest
|
||
{
|
||
public string email;
|
||
public string code;
|
||
}
|
||
public class RegisterRequest
|
||
{
|
||
public string email;
|
||
public string password;
|
||
public int password_type;
|
||
}
|
||
public class ResetPasswordRequest
|
||
{
|
||
public string email;
|
||
public string password;
|
||
public int password_type;
|
||
}
|
||
public class FireBaseLoginRequest
|
||
{
|
||
public string firebase_token;
|
||
}
|
||
public class BindFireBaseRequest
|
||
{
|
||
public string code;
|
||
public string email;
|
||
public string temp_token;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Firebase 绑定响应
|
||
/// </summary>
|
||
public class FirebaseBindResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public FirebaseBindData data;
|
||
}
|
||
|
||
public class FirebaseBindData
|
||
{
|
||
public bool firebase_bind;
|
||
}
|
||
#endregion
|
||
|
||
#region 安全学习题目
|
||
|
||
/// <summary>
|
||
/// 题目列表响应
|
||
/// </summary>
|
||
[Serializable]
|
||
public class QuestionListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public QuestionListData data;
|
||
}
|
||
|
||
[Serializable]
|
||
public class QuestionListData
|
||
{
|
||
public int total;
|
||
public int pages;
|
||
public int limit;
|
||
public int page;
|
||
public List<QuestionInfo> list;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 题目信息
|
||
/// </summary>
|
||
[Serializable]
|
||
public class QuestionInfo
|
||
{
|
||
public int id;
|
||
public string questionNumber;
|
||
public string questionContent;
|
||
public string questionContentEn;
|
||
public string correctAnswer;
|
||
public string videoUrl;
|
||
public string videoUrlEn;
|
||
public List<QuestionOption> options;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 题目选项
|
||
/// </summary>
|
||
[Serializable]
|
||
public class QuestionOption
|
||
{
|
||
public int id;
|
||
public string optionLabel;
|
||
public string optionContent;
|
||
public string optionContentEn;
|
||
public bool isCorrect;
|
||
public string explanation;
|
||
public string explanationEn;
|
||
}
|
||
|
||
|
||
|
||
#endregion
|
||
|
||
#region 答题记录
|
||
/// <summary>
|
||
/// 答题记录(用于本地存储)
|
||
/// </summary>
|
||
[Serializable]
|
||
public class QuestionRecord
|
||
{
|
||
public int questionId;
|
||
public int correctCount; // 累计答对次数
|
||
}
|
||
|
||
/// <summary>
|
||
/// 答题记录数据
|
||
/// </summary>
|
||
[Serializable]
|
||
public class QuestionRecordData
|
||
{
|
||
public List<QuestionRecord> records = new List<QuestionRecord>();
|
||
public int totalAnsweredCount; // 总答题序号(累加)
|
||
}
|
||
#endregion
|
||
[Serializable]
|
||
public class BandDeviceRequest
|
||
{
|
||
public string device_sn;
|
||
public string user_id;
|
||
}
|
||
#region 设备列表
|
||
|
||
/// <summary>
|
||
/// 设备列表响应
|
||
/// </summary>
|
||
[Serializable]
|
||
public class DeviceListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public DeviceListData data;
|
||
}
|
||
|
||
[Serializable]
|
||
public class DeviceListData
|
||
{
|
||
public List<DeviceInfo> owned_devices;
|
||
public List<DeviceInfo> shared_devices;
|
||
public int? online_count;
|
||
public int? offline_count;
|
||
public int? fault_count;
|
||
public int? total;
|
||
public int? page;
|
||
public int? size;
|
||
public int? pages;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设备信息
|
||
/// </summary>
|
||
[Serializable]
|
||
public class DeviceInfo
|
||
{
|
||
public string device_sn;
|
||
public string ble_mac;
|
||
public string wifi_mac;
|
||
public string device_name;
|
||
public string product_id;
|
||
public string status;
|
||
public string bind_time;
|
||
public string device_model;
|
||
public string firmware_version;
|
||
public float? total_work_hours;
|
||
public int? total_mosquitoes_killed;
|
||
public string location;
|
||
public string last_online_time;
|
||
public string owner_id;
|
||
public string owner_name;
|
||
public string owner_username;
|
||
public string share_time;
|
||
}
|
||
|
||
#endregion
|
||
/// <summary>
|
||
/// 单位设置请求数据
|
||
/// </summary>
|
||
[Serializable]
|
||
public class UnitRequest
|
||
{
|
||
/// <summary>
|
||
/// 0公制 1英制
|
||
/// </summary>
|
||
public int unit_system;
|
||
}
|
||
/// <summary>
|
||
/// 密码校验
|
||
/// </summary>
|
||
[Serializable]
|
||
public class PasswordRequest
|
||
{
|
||
public string password;
|
||
}
|
||
/// <summary>
|
||
/// 重置设备请求数据
|
||
/// </summary>
|
||
[Serializable]
|
||
public class ResetDeviceRequest
|
||
{
|
||
public string device_sn;
|
||
}
|
||
public class ShareDeviceRequest
|
||
{
|
||
public string device_sn;
|
||
public string target_user_id;
|
||
public string owner_id;
|
||
}
|
||
[Serializable]
|
||
public class SharedUserInfo
|
||
{
|
||
public string user_id;
|
||
public string user_name;
|
||
public string avatar;
|
||
public DateTime share_time;
|
||
}
|
||
public class SharedUserInfoListData
|
||
{
|
||
public List<SharedUserInfo> list;
|
||
}
|
||
public class ShareUserInfoRequest
|
||
{
|
||
public string device_sn;
|
||
}
|
||
|
||
public class ShareUserListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public SharedUserInfoListData data;
|
||
}
|
||
public class OTAResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public OTAData data;
|
||
}
|
||
public class OTAData
|
||
{
|
||
public string version;
|
||
public string download_url;
|
||
public string md5;
|
||
public string release_notes;
|
||
}
|
||
|
||
public class MessageData
|
||
{
|
||
public string id;
|
||
public string title;
|
||
public string type;
|
||
public string content;
|
||
public DateTime create_at;
|
||
public DateTime publish_time;
|
||
public bool is_read;
|
||
}
|
||
public class AnnouncementData
|
||
{
|
||
public string id;
|
||
public string title;
|
||
public string type;
|
||
public string content;
|
||
public DateTime publish_time;
|
||
public bool is_read;
|
||
}
|
||
public enum MessageType
|
||
{
|
||
device,
|
||
warning,
|
||
announcement
|
||
}
|
||
[Serializable]
|
||
public class MessageTypeData
|
||
{
|
||
public int device;
|
||
public int warning;
|
||
public int announcement;
|
||
}
|
||
public class MessageTypeDataListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public MessageTypeData data;
|
||
}
|
||
public class RecordData
|
||
{
|
||
public string id;
|
||
public DateTime time;
|
||
public float angle;
|
||
public float distance;
|
||
}
|
||
public class DeviceVideoData
|
||
{
|
||
public string id;
|
||
public string video_url;
|
||
public string cover_url;
|
||
public DateTime record_time;
|
||
|
||
}
|
||
public class RecordDataList
|
||
{
|
||
public int total;
|
||
public List<RecordData> records;
|
||
|
||
}
|
||
public class DeviceVideoDataList
|
||
{
|
||
public int total;
|
||
public List<DeviceVideoData> list;
|
||
|
||
}
|
||
public class RecordDataListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public RecordDataList data;
|
||
}
|
||
public class DeviceVideoDataListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public DeviceVideoDataList data;
|
||
}
|
||
public class KillCountData
|
||
{
|
||
public string time_point;
|
||
public int count;
|
||
}
|
||
public class KillCountDataList
|
||
{
|
||
public int total_count;
|
||
public List<KillCountData> stats;
|
||
}
|
||
public class KillCountDataResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public KillCountDataList data;
|
||
}
|
||
public class HeatmapData
|
||
{
|
||
public float angle;
|
||
public float distance;
|
||
public int count;
|
||
}
|
||
public class HeatmapDataList
|
||
{
|
||
public List<HeatmapData> points;
|
||
}
|
||
public class HeatmapDataListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public HeatmapDataList data;
|
||
}
|
||
|
||
public class RankData
|
||
{
|
||
public int rank;
|
||
public string nickname;
|
||
public string avatar;
|
||
public int kill_count;
|
||
public string country_code;
|
||
}
|
||
public class RankDataList
|
||
{
|
||
public List<RankData> top_list;
|
||
public RankData my_rank;
|
||
}
|
||
public class RankDataListResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public RankDataList data;
|
||
}
|
||
public class BundleData
|
||
{
|
||
public string bundle_version;
|
||
public string bundle_url;
|
||
}
|
||
public class BundleDataResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public BundleData data;
|
||
}
|
||
[Serializable]
|
||
public class PostRecordData
|
||
{
|
||
public string device_sn;
|
||
public string record_time;
|
||
public float angle;
|
||
public float distance;
|
||
}
|
||
|
||
public class PostStatisticsData
|
||
{
|
||
public string device_sn;
|
||
public uint kill_count;
|
||
public uint total_work_time;
|
||
}
|
||
|
||
public class CountryCodeRequest
|
||
{
|
||
public string country_code;
|
||
}
|
||
|
||
public class FileRequest
|
||
{
|
||
public byte[] file;
|
||
}
|
||
/// <summary>
|
||
/// 设备在线状态响应
|
||
/// </summary>
|
||
[System.Serializable]
|
||
public class DeviceOnlineResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public bool data;
|
||
}
|
||
|
||
#region 设备配置
|
||
|
||
/// <summary>
|
||
/// 设备配置(对应Java DeviceConfig实体)
|
||
/// </summary>
|
||
[System.Serializable]
|
||
public class DeviceConfig
|
||
{
|
||
public string device_sn;
|
||
public int? language;
|
||
public bool? is_locked;
|
||
public int? fov_angle;
|
||
public int? detection_distance;
|
||
public int? aim_distance;
|
||
public string work_mode;
|
||
public bool? fill_light_enable;
|
||
public string fill_light_type;
|
||
public string fill_light_intensity;
|
||
public bool? laser_visible_enable;
|
||
public bool? visual_detect_enable;
|
||
public string visual_sensitivity;
|
||
public bool? radar_enable;
|
||
public string radar_sensitivity;
|
||
public int? radar_safe_distance;
|
||
public bool? rgb_enable;
|
||
public byte? rgb_red;
|
||
public byte? rgb_green;
|
||
public byte? rgb_blue;
|
||
public string rgb_effect;
|
||
public bool? lcd_auto_brightness;
|
||
public byte? lcd_brightness;
|
||
public bool? lcd_sleep_enable;
|
||
public byte? lcd_sleep_time;
|
||
public bool? wifi_enable;
|
||
public string wifi_ssid;
|
||
public string wifi_password;
|
||
public bool? video_record_enable;
|
||
public byte? record_duration;
|
||
public bool? sound_enable;
|
||
public string sound_type;
|
||
public byte? volume;
|
||
|
||
/// <summary>
|
||
/// 将服务器配置字符串解析为枚举值
|
||
/// </summary>
|
||
public static T ParseServerEnum<T>(string serverValue, T defaultValue) where T : struct
|
||
{
|
||
if (string.IsNullOrEmpty(serverValue))
|
||
return defaultValue;
|
||
|
||
if (System.Enum.TryParse<T>(serverValue, true, out T result))
|
||
return result;
|
||
|
||
return defaultValue;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将枚举值转换为服务器配置字符串(大写)
|
||
/// </summary>
|
||
public static string ToServerString<T>(T enumValue) where T : struct
|
||
{
|
||
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 (IsMeaningfulValue(value))
|
||
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) && IsMeaningfulValue(currentValue))
|
||
{
|
||
changed[field.Name] = currentValue;
|
||
}
|
||
}
|
||
return changed;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查值是否有意义(非 null、非空字符串)
|
||
/// </summary>
|
||
private static bool IsMeaningfulValue(object value)
|
||
{
|
||
if (value == null) return false;
|
||
if (value is string str && string.IsNullOrEmpty(str)) return false;
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设备配置响应
|
||
/// </summary>
|
||
[System.Serializable]
|
||
public class DeviceConfigResponse
|
||
{
|
||
public int code;
|
||
public string message;
|
||
public DeviceConfig data;
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
}
|
||
|
||
|