refactor: 枚举移入Models目录,命名空间更新为Rainbow.Entity.Models
大石头 authored at 2026-07-02 12:54:58
24.44 KiB
RainbowBridge
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
using NewLife;
using NewLife.Data;
using XCode;
using XCode.Cache;
using XCode.Configuration;
using XCode.DataAccessLayer;

namespace Rainbow.Entity;

/// <summary>设备在线快照。每分钟从ARP表同步,记录当前活跃IP与MAC映射,是统计映射的核心枢纽表</summary>
[Serializable]
[DataObject]
[Description("设备在线快照。每分钟从ARP表同步,记录当前活跃IP与MAC映射,是统计映射的核心枢纽表")]
[BindIndex("IU_DeviceOnline_IP", true, "IP")]
[BindIndex("IX_DeviceOnline_Mac_IsOnline", false, "Mac,IsOnline")]
[BindIndex("IX_DeviceOnline_DeviceId_IsOnline", false, "DeviceId,IsOnline")]
[BindIndex("IX_DeviceOnline_Interface", false, "Interface")]
[BindIndex("IX_DeviceOnline_LastSeen", false, "LastSeen")]
[BindTable("DeviceOnline", Description = "设备在线快照。每分钟从ARP表同步,记录当前活跃IP与MAC映射,是统计映射的核心枢纽表", ConnName = "Rainbow", DbType = DatabaseType.None)]
public partial class DeviceOnline
{
    #region 属性
    private Int64 _Id;
    /// <summary>编号。雪花ID,保留历史快照</summary>
    [DisplayName("编号")]
    [Description("编号。雪花ID,保留历史快照")]
    [DataObjectField(true, false, false, 0)]
    [BindColumn("Id", "编号。雪花ID,保留历史快照", "", DataScale = "time")]
    public Int64 Id { get => _Id; set { if (OnPropertyChanging("Id", value)) { _Id = value; OnPropertyChanged("Id"); } } }

    private String? _IP;
    /// <summary>IP地址。当前活跃IP,IPv4/IPv6。统计时优先从此表按IP查DeviceId</summary>
    [DisplayName("IP地址")]
    [Description("IP地址。当前活跃IP,IPv4/IPv6。统计时优先从此表按IP查DeviceId")]
    [DataObjectField(false, false, true, 45)]
    [BindColumn("IP", "IP地址。当前活跃IP,IPv4/IPv6。统计时优先从此表按IP查DeviceId", "")]
    public String? IP { get => _IP; set { if (OnPropertyChanging("IP", value)) { _IP = value; OnPropertyChanged("IP"); } } }

    private String? _Mac;
    /// <summary>MAC地址。ARP解析得到,是设备唯一标识。映射第一优先级:MAC精确匹配Device表</summary>
    [DisplayName("MAC地址")]
    [Description("MAC地址。ARP解析得到,是设备唯一标识。映射第一优先级:MAC精确匹配Device表")]
    [DataObjectField(false, false, true, 17)]
    [BindColumn("Mac", "MAC地址。ARP解析得到,是设备唯一标识。映射第一优先级:MAC精确匹配Device表", "")]
    public String? Mac { get => _Mac; set { if (OnPropertyChanging("Mac", value)) { _Mac = value; OnPropertyChanged("Mac"); } } }

    private String? _HostName;
    /// <summary>主机名。DHCP/mDNS上报,如'XiaoMing-PC'。用于人工识别设备</summary>
    [DisplayName("主机名")]
    [Description("主机名。DHCP/mDNS上报,如'XiaoMing-PC'。用于人工识别设备")]
    [DataObjectField(false, false, true, 100)]
    [BindColumn("HostName", "主机名。DHCP/mDNS上报,如'XiaoMing-PC'。用于人工识别设备", "")]
    public String? HostName { get => _HostName; set { if (OnPropertyChanging("HostName", value)) { _HostName = value; OnPropertyChanged("HostName"); } } }

    private Int32 _DeviceId;
    /// <summary>关联设备。通过MAC查Device表得到,首次未知=0,后续自动关联</summary>
    [DisplayName("关联设备")]
    [Description("关联设备。通过MAC查Device表得到,首次未知=0,后续自动关联")]
    [DataObjectField(false, false, false, 0)]
    [BindColumn("DeviceId", "关联设备。通过MAC查Device表得到,首次未知=0,后续自动关联", "")]
    public Int32 DeviceId { get => _DeviceId; set { if (OnPropertyChanging("DeviceId", value)) { _DeviceId = value; OnPropertyChanged("DeviceId"); } } }

    private String? _Interface;
    /// <summary>所在网口。如eth0/br-lan/wlan0。同IP在不同网口=不同设备,用于多网段隔离</summary>
    [DisplayName("所在网口")]
    [Description("所在网口。如eth0/br-lan/wlan0。同IP在不同网口=不同设备,用于多网段隔离")]
    [DataObjectField(false, false, true, 20)]
    [BindColumn("Interface", "所在网口。如eth0/br-lan/wlan0。同IP在不同网口=不同设备,用于多网段隔离", "")]
    public String? Interface { get => _Interface; set { if (OnPropertyChanging("Interface", value)) { _Interface = value; OnPropertyChanged("Interface"); } } }

    private DateTime _LeaseExpire;
    /// <summary>DHCP租约过期。过期后IP可能被回收分配给其他设备,是IP漂移的预警信号</summary>
    [DisplayName("DHCP租约过期")]
    [Description("DHCP租约过期。过期后IP可能被回收分配给其他设备,是IP漂移的预警信号")]
    [DataObjectField(false, false, true, 0)]
    [BindColumn("LeaseExpire", "DHCP租约过期。过期后IP可能被回收分配给其他设备,是IP漂移的预警信号", "")]
    public DateTime LeaseExpire { get => _LeaseExpire; set { if (OnPropertyChanging("LeaseExpire", value)) { _LeaseExpire = value; OnPropertyChanged("LeaseExpire"); } } }

    private String? _PrevMac;
    /// <summary>前一MAC。IP漂移时的旧MAC,审计关键:本次MAC≠上次MAC→IP已换设备→触发DeviceHistory事件</summary>
    [DisplayName("前一MAC")]
    [Description("前一MAC。IP漂移时的旧MAC,审计关键:本次MAC≠上次MAC→IP已换设备→触发DeviceHistory事件")]
    [DataObjectField(false, false, true, 17)]
    [BindColumn("PrevMac", "前一MAC。IP漂移时的旧MAC,审计关键:本次MAC≠上次MAC→IP已换设备→触发DeviceHistory事件", "")]
    public String? PrevMac { get => _PrevMac; set { if (OnPropertyChanging("PrevMac", value)) { _PrevMac = value; OnPropertyChanged("PrevMac"); } } }

    private Int32 _PrevDeviceId;
    /// <summary>前一设备ID。IP漂移时旧设备关联。事后统计可按PrevDeviceId修正历史数据</summary>
    [DisplayName("前一设备ID")]
    [Description("前一设备ID。IP漂移时旧设备关联。事后统计可按PrevDeviceId修正历史数据")]
    [DataObjectField(false, false, false, 0)]
    [BindColumn("PrevDeviceId", "前一设备ID。IP漂移时旧设备关联。事后统计可按PrevDeviceId修正历史数据", "")]
    public Int32 PrevDeviceId { get => _PrevDeviceId; set { if (OnPropertyChanging("PrevDeviceId", value)) { _PrevDeviceId = value; OnPropertyChanged("PrevDeviceId"); } } }

    private DateTime _MacChangedTime;
    /// <summary>MAC变更时间。IP漂移发生的精确时刻,用于精确定位漂移窗口</summary>
    [DisplayName("MAC变更时间")]
    [Description("MAC变更时间。IP漂移发生的精确时刻,用于精确定位漂移窗口")]
    [DataObjectField(false, false, true, 0)]
    [BindColumn("MacChangedTime", "MAC变更时间。IP漂移发生的精确时刻,用于精确定位漂移窗口", "")]
    public DateTime MacChangedTime { get => _MacChangedTime; set { if (OnPropertyChanging("MacChangedTime", value)) { _MacChangedTime = value; OnPropertyChanged("MacChangedTime"); } } }

    private DateTime _FirstSeen;
    /// <summary>首次出现。本次会话首次在ARP表中出现的时间,即上线时刻</summary>
    [DisplayName("首次出现")]
    [Description("首次出现。本次会话首次在ARP表中出现的时间,即上线时刻")]
    [DataObjectField(false, false, true, 0)]
    [BindColumn("FirstSeen", "首次出现。本次会话首次在ARP表中出现的时间,即上线时刻", "")]
    public DateTime FirstSeen { get => _FirstSeen; set { if (OnPropertyChanging("FirstSeen", value)) { _FirstSeen = value; OnPropertyChanged("FirstSeen"); } } }

    private DateTime _LastSeen;
    /// <summary>最后活跃。每分钟更新。LastSeen超过2分钟未更新→设备已下线→触发Offline事件</summary>
    [DisplayName("最后活跃")]
    [Description("最后活跃。每分钟更新。LastSeen超过2分钟未更新→设备已下线→触发Offline事件")]
    [DataObjectField(false, false, true, 0)]
    [BindColumn("LastSeen", "最后活跃。每分钟更新。LastSeen超过2分钟未更新→设备已下线→触发Offline事件", "")]
    public DateTime LastSeen { get => _LastSeen; set { if (OnPropertyChanging("LastSeen", value)) { _LastSeen = value; OnPropertyChanged("LastSeen"); } } }

    private Int32 _OnlineSeconds;
    /// <summary>本日在线秒数。每分钟+60,用于快速展示今日在线时长,无需查DeviceHistory</summary>
    [DisplayName("本日在线秒数")]
    [Description("本日在线秒数。每分钟+60,用于快速展示今日在线时长,无需查DeviceHistory")]
    [DataObjectField(false, false, false, 0)]
    [BindColumn("OnlineSeconds", "本日在线秒数。每分钟+60,用于快速展示今日在线时长,无需查DeviceHistory", "", ItemType = "TimeSpan")]
    public Int32 OnlineSeconds { get => _OnlineSeconds; set { if (OnPropertyChanging("OnlineSeconds", value)) { _OnlineSeconds = value; OnPropertyChanged("OnlineSeconds"); } } }

    private Boolean _IsOnline;
    /// <summary>是否在线。LastSeen在2分钟以内=True。用于仪表盘实时在线数统计和告警</summary>
    [DisplayName("是否在线")]
    [Description("是否在线。LastSeen在2分钟以内=True。用于仪表盘实时在线数统计和告警")]
    [DataObjectField(false, false, false, 0)]
    [BindColumn("IsOnline", "是否在线。LastSeen在2分钟以内=True。用于仪表盘实时在线数统计和告警", "")]
    public Boolean IsOnline { get => _IsOnline; set { if (OnPropertyChanging("IsOnline", value)) { _IsOnline = value; OnPropertyChanged("IsOnline"); } } }

    private Int64 _RxBytes;
    /// <summary>本日累计接收字节。从iptables计数器累加。异常暴增→大流量下载或视频播放</summary>
    [DisplayName("本日累计接收字节")]
    [Description("本日累计接收字节。从iptables计数器累加。异常暴增→大流量下载或视频播放")]
    [DataObjectField(false, false, false, 0)]
    [BindColumn("RxBytes", "本日累计接收字节。从iptables计数器累加。异常暴增→大流量下载或视频播放", "")]
    public Int64 RxBytes { get => _RxBytes; set { if (OnPropertyChanging("RxBytes", value)) { _RxBytes = value; OnPropertyChanged("RxBytes"); } } }

    private Int64 _TxBytes;
    /// <summary>本日累计发送字节。上行>下行→P2P上传或直播推流,需关注是否异常</summary>
    [DisplayName("本日累计发送字节")]
    [Description("本日累计发送字节。上行>下行→P2P上传或直播推流,需关注是否异常")]
    [DataObjectField(false, false, false, 0)]
    [BindColumn("TxBytes", "本日累计发送字节。上行>下行→P2P上传或直播推流,需关注是否异常", "")]
    public Int64 TxBytes { get => _TxBytes; set { if (OnPropertyChanging("TxBytes", value)) { _TxBytes = value; OnPropertyChanged("TxBytes"); } } }

    private DateTime _CreateTime;
    /// <summary>创建时间</summary>
    [Category("扩展")]
    [DisplayName("创建时间")]
    [Description("创建时间")]
    [DataObjectField(false, false, true, 0)]
    [BindColumn("CreateTime", "创建时间", "")]
    public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } }

    private DateTime _UpdateTime;
    /// <summary>更新时间。每次采集同步时更新</summary>
    [Category("扩展")]
    [DisplayName("更新时间")]
    [Description("更新时间。每次采集同步时更新")]
    [DataObjectField(false, false, true, 0)]
    [BindColumn("UpdateTime", "更新时间。每次采集同步时更新", "")]
    public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } }
    #endregion

    #region 获取/设置 字段值
    /// <summary>获取/设置 字段值</summary>
    /// <param name="name">字段名</param>
    /// <returns></returns>
    public override Object? this[String name]
    {
        get => name switch
        {
            "Id" => _Id,
            "IP" => _IP,
            "Mac" => _Mac,
            "HostName" => _HostName,
            "DeviceId" => _DeviceId,
            "Interface" => _Interface,
            "LeaseExpire" => _LeaseExpire,
            "PrevMac" => _PrevMac,
            "PrevDeviceId" => _PrevDeviceId,
            "MacChangedTime" => _MacChangedTime,
            "FirstSeen" => _FirstSeen,
            "LastSeen" => _LastSeen,
            "OnlineSeconds" => _OnlineSeconds,
            "IsOnline" => _IsOnline,
            "RxBytes" => _RxBytes,
            "TxBytes" => _TxBytes,
            "CreateTime" => _CreateTime,
            "UpdateTime" => _UpdateTime,
            _ => base[name]
        };
        set
        {
            switch (name)
            {
                case "Id": _Id = value.ToLong(); break;
                case "IP": _IP = Convert.ToString(value); break;
                case "Mac": _Mac = Convert.ToString(value); break;
                case "HostName": _HostName = Convert.ToString(value); break;
                case "DeviceId": _DeviceId = value.ToInt(); break;
                case "Interface": _Interface = Convert.ToString(value); break;
                case "LeaseExpire": _LeaseExpire = value.ToDateTime(); break;
                case "PrevMac": _PrevMac = Convert.ToString(value); break;
                case "PrevDeviceId": _PrevDeviceId = value.ToInt(); break;
                case "MacChangedTime": _MacChangedTime = value.ToDateTime(); break;
                case "FirstSeen": _FirstSeen = value.ToDateTime(); break;
                case "LastSeen": _LastSeen = value.ToDateTime(); break;
                case "OnlineSeconds": _OnlineSeconds = value.ToInt(); break;
                case "IsOnline": _IsOnline = value.ToBoolean(); break;
                case "RxBytes": _RxBytes = value.ToLong(); break;
                case "TxBytes": _TxBytes = value.ToLong(); break;
                case "CreateTime": _CreateTime = value.ToDateTime(); break;
                case "UpdateTime": _UpdateTime = value.ToDateTime(); break;
                default: base[name] = value; break;
            }
        }
    }
    #endregion

    #region 关联映射
    /// <summary>关联设备</summary>
    [XmlIgnore, IgnoreDataMember, ScriptIgnore]
    public Device? Device => Extends.Get(nameof(Device), k => Device.FindById(DeviceId));

    /// <summary>关联设备</summary>
    [Map(nameof(DeviceId), typeof(Device), "Id")]
    public String? DeviceName => Device?.Name;

    #endregion

    #region 扩展查询
    /// <summary>根据编号查找</summary>
    /// <param name="id">编号</param>
    /// <returns>实体对象</returns>
    public static DeviceOnline? FindById(Int64 id)
    {
        if (id < 0) return null;

        return Find(_.Id == id);
    }

    /// <summary>根据IP地址查找</summary>
    /// <param name="ip">IP地址</param>
    /// <returns>实体对象</returns>
    public static DeviceOnline? FindByIP(String? ip)
    {
        if (ip == null) return null;

        return Find(_.IP == ip);
    }

    /// <summary>根据所在网口查找</summary>
    /// <param name="@interface">所在网口</param>
    /// <returns>实体列表</returns>
    public static IList<DeviceOnline> FindAllByInterface(String? @interface)
    {
        if (@interface == null) return [];

        return FindAll(_.Interface == @interface);
    }
    #endregion

    #region 高级查询
    /// <summary>高级查询</summary>
    /// <param name="ip">IP地址。当前活跃IP,IPv4/IPv6。统计时优先从此表按IP查DeviceId</param>
    /// <param name="mac">MAC地址。ARP解析得到,是设备唯一标识。映射第一优先级:MAC精确匹配Device表</param>
    /// <param name="deviceId">关联设备。通过MAC查Device表得到,首次未知=0,后续自动关联</param>
    /// <param name="@interface">所在网口。如eth0/br-lan/wlan0。同IP在不同网口=不同设备,用于多网段隔离</param>
    /// <param name="lastSeen">最后活跃。每分钟更新。LastSeen超过2分钟未更新→设备已下线→触发Offline事件</param>
    /// <param name="isOnline">是否在线。LastSeen在2分钟以内=True。用于仪表盘实时在线数统计和告警</param>
    /// <param name="start">编号开始</param>
    /// <param name="end">编号结束</param>
    /// <param name="key">关键字</param>
    /// <param name="page">分页参数信息。可携带统计和数据权限扩展查询等信息</param>
    /// <returns>实体列表</returns>
    public static IList<DeviceOnline> Search(String? ip, String? mac, Int32 deviceId, String? @interface, DateTime lastSeen, Boolean? isOnline, DateTime start, DateTime end, String key, PageParameter page)
    {
        var exp = new WhereExpression();

        if (!ip.IsNullOrEmpty()) exp &= _.IP == ip;
        if (!mac.IsNullOrEmpty()) exp &= _.Mac == mac;
        if (deviceId >= 0) exp &= _.DeviceId == deviceId;
        if (!@interface.IsNullOrEmpty()) exp &= _.Interface == @interface;
        if (isOnline != null) exp &= _.IsOnline == isOnline;
        exp &= _.Id.Between(start, end, Meta.Factory.Snow);
        if (!key.IsNullOrEmpty()) exp &= SearchWhereByKeys(key);

        return FindAll(exp, page);
    }
    #endregion

    #region 数据清理
    /// <summary>清理指定时间段内的数据</summary>
    /// <param name="start">开始时间。未指定时清理小于指定时间的所有数据</param>
    /// <param name="end">结束时间</param>
    /// <param name="maximumRows">最大删除行数。清理历史数据时,避免一次性删除过多导致数据库IO跟不上,0表示所有</param>
    /// <returns>清理行数</returns>
    public static Int32 DeleteWith(DateTime start, DateTime end, Int32 maximumRows = 0)
    {
        return Delete(_.Id.Between(start, end, Meta.Factory.Snow), maximumRows);
    }
    #endregion

    #region 字段名
    /// <summary>取得设备在线快照字段信息的快捷方式</summary>
    public partial class _
    {
        /// <summary>编号。雪花ID,保留历史快照</summary>
        public static readonly Field Id = FindByName("Id");

        /// <summary>IP地址。当前活跃IP,IPv4/IPv6。统计时优先从此表按IP查DeviceId</summary>
        public static readonly Field IP = FindByName("IP");

        /// <summary>MAC地址。ARP解析得到,是设备唯一标识。映射第一优先级:MAC精确匹配Device表</summary>
        public static readonly Field Mac = FindByName("Mac");

        /// <summary>主机名。DHCP/mDNS上报,如'XiaoMing-PC'。用于人工识别设备</summary>
        public static readonly Field HostName = FindByName("HostName");

        /// <summary>关联设备。通过MAC查Device表得到,首次未知=0,后续自动关联</summary>
        public static readonly Field DeviceId = FindByName("DeviceId");

        /// <summary>所在网口。如eth0/br-lan/wlan0。同IP在不同网口=不同设备,用于多网段隔离</summary>
        public static readonly Field Interface = FindByName("Interface");

        /// <summary>DHCP租约过期。过期后IP可能被回收分配给其他设备,是IP漂移的预警信号</summary>
        public static readonly Field LeaseExpire = FindByName("LeaseExpire");

        /// <summary>前一MAC。IP漂移时的旧MAC,审计关键:本次MAC≠上次MAC→IP已换设备→触发DeviceHistory事件</summary>
        public static readonly Field PrevMac = FindByName("PrevMac");

        /// <summary>前一设备ID。IP漂移时旧设备关联。事后统计可按PrevDeviceId修正历史数据</summary>
        public static readonly Field PrevDeviceId = FindByName("PrevDeviceId");

        /// <summary>MAC变更时间。IP漂移发生的精确时刻,用于精确定位漂移窗口</summary>
        public static readonly Field MacChangedTime = FindByName("MacChangedTime");

        /// <summary>首次出现。本次会话首次在ARP表中出现的时间,即上线时刻</summary>
        public static readonly Field FirstSeen = FindByName("FirstSeen");

        /// <summary>最后活跃。每分钟更新。LastSeen超过2分钟未更新→设备已下线→触发Offline事件</summary>
        public static readonly Field LastSeen = FindByName("LastSeen");

        /// <summary>本日在线秒数。每分钟+60,用于快速展示今日在线时长,无需查DeviceHistory</summary>
        public static readonly Field OnlineSeconds = FindByName("OnlineSeconds");

        /// <summary>是否在线。LastSeen在2分钟以内=True。用于仪表盘实时在线数统计和告警</summary>
        public static readonly Field IsOnline = FindByName("IsOnline");

        /// <summary>本日累计接收字节。从iptables计数器累加。异常暴增→大流量下载或视频播放</summary>
        public static readonly Field RxBytes = FindByName("RxBytes");

        /// <summary>本日累计发送字节。上行>下行→P2P上传或直播推流,需关注是否异常</summary>
        public static readonly Field TxBytes = FindByName("TxBytes");

        /// <summary>创建时间</summary>
        public static readonly Field CreateTime = FindByName("CreateTime");

        /// <summary>更新时间。每次采集同步时更新</summary>
        public static readonly Field UpdateTime = FindByName("UpdateTime");

        static Field FindByName(String name) => Meta.Table.FindByName(name)!;
    }

    /// <summary>取得设备在线快照字段名称的快捷方式</summary>
    public partial class __
    {
        /// <summary>编号。雪花ID,保留历史快照</summary>
        public const String Id = "Id";

        /// <summary>IP地址。当前活跃IP,IPv4/IPv6。统计时优先从此表按IP查DeviceId</summary>
        public const String IP = "IP";

        /// <summary>MAC地址。ARP解析得到,是设备唯一标识。映射第一优先级:MAC精确匹配Device表</summary>
        public const String Mac = "Mac";

        /// <summary>主机名。DHCP/mDNS上报,如'XiaoMing-PC'。用于人工识别设备</summary>
        public const String HostName = "HostName";

        /// <summary>关联设备。通过MAC查Device表得到,首次未知=0,后续自动关联</summary>
        public const String DeviceId = "DeviceId";

        /// <summary>所在网口。如eth0/br-lan/wlan0。同IP在不同网口=不同设备,用于多网段隔离</summary>
        public const String Interface = "Interface";

        /// <summary>DHCP租约过期。过期后IP可能被回收分配给其他设备,是IP漂移的预警信号</summary>
        public const String LeaseExpire = "LeaseExpire";

        /// <summary>前一MAC。IP漂移时的旧MAC,审计关键:本次MAC≠上次MAC→IP已换设备→触发DeviceHistory事件</summary>
        public const String PrevMac = "PrevMac";

        /// <summary>前一设备ID。IP漂移时旧设备关联。事后统计可按PrevDeviceId修正历史数据</summary>
        public const String PrevDeviceId = "PrevDeviceId";

        /// <summary>MAC变更时间。IP漂移发生的精确时刻,用于精确定位漂移窗口</summary>
        public const String MacChangedTime = "MacChangedTime";

        /// <summary>首次出现。本次会话首次在ARP表中出现的时间,即上线时刻</summary>
        public const String FirstSeen = "FirstSeen";

        /// <summary>最后活跃。每分钟更新。LastSeen超过2分钟未更新→设备已下线→触发Offline事件</summary>
        public const String LastSeen = "LastSeen";

        /// <summary>本日在线秒数。每分钟+60,用于快速展示今日在线时长,无需查DeviceHistory</summary>
        public const String OnlineSeconds = "OnlineSeconds";

        /// <summary>是否在线。LastSeen在2分钟以内=True。用于仪表盘实时在线数统计和告警</summary>
        public const String IsOnline = "IsOnline";

        /// <summary>本日累计接收字节。从iptables计数器累加。异常暴增→大流量下载或视频播放</summary>
        public const String RxBytes = "RxBytes";

        /// <summary>本日累计发送字节。上行>下行→P2P上传或直播推流,需关注是否异常</summary>
        public const String TxBytes = "TxBytes";

        /// <summary>创建时间</summary>
        public const String CreateTime = "CreateTime";

        /// <summary>更新时间。每次采集同步时更新</summary>
        public const String UpdateTime = "UpdateTime";
    }
    #endregion
}