feat(ops): 增加运维面板及诊断导出功能

- 添加运维面板OpsActivity及对应布局,展示设备状态、网络、MQTT、人脸数据等信息
- 实现诊断包导出工具DiagnosticExporter,支持将设备信息和日志导出到U盘
- 新增设备健康信息获取工具DeviceInfoProvider,提供运行时长、内存和存储信息
- 实现运行时日志写入文件FileLoggingTree,支持按天滚动、切分与过期清理
- 增加日志文件管理LogFileManager,支持列出、读取尾部和清理日志文件
- 丰富MQTT管理器MqttManager,记录连接状态、错误、连接次数等详情并支持手动重连
- 为环境切换引入EnvironmentSwitcher,实现基础地址切换和清空本地人脸库后自动重启
- 扩展ArcFace人脸库接口,支持查询最近更新人脸及按userId精确搜索
- MainActivity增加运维面板入口,管理员列表页右上角双击时间触发打开
- 应用启动时种植FileLoggingTree,确保运行日志同时输出至文件和控制台
This commit is contained in:
mazengfei
2026-09-02 17:47:24 +08:00
parent 994bcf5bc2
commit 8bcc5a0289
18 changed files with 1633 additions and 1 deletions
@@ -0,0 +1,50 @@
package com.sw.platecabinet.utils
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import com.sw.platecabinet.ENVIRONMENTS
import java.net.Inet4Address
import java.net.InetAddress
import java.net.NetworkInterface
/**
* 网络状态只读提供器:连通性、本机 IP、业务环境名。
*/
object NetStatusProvider {
/** 连通性摘要(离线/WiFi/蜂窝/以太网/未知) */
fun connectivitySummary(context: Context): String {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
?: return "未知"
val network = cm.activeNetwork ?: return "离线"
val caps = cm.getNetworkCapabilities(network) ?: return "离线"
return when {
!caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) -> "离线(无外网)"
caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> "以太网"
caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> "WiFi"
caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> "蜂窝"
else -> "已连接"
}
}
/** 本机 IPv4 地址(取首个非回环地址,无则返回"未知" */
fun localIpv4(): String {
return try {
val addresses = mutableListOf<InetAddress>()
val interfaces = NetworkInterface.getNetworkInterfaces() ?: return "未知"
for (nif in interfaces) {
val addrs = nif.inetAddresses ?: continue
for (addr in addrs) addresses.add(addr)
}
addresses.firstOrNull { it is Inet4Address && !it.isLoopbackAddress }?.hostAddress ?: "未知"
} catch (e: Exception) {
"未知"
}
}
/** 由 baseUrl 反查预设环境名,未匹配返回"自定义" */
fun envName(baseUrl: String): String {
return ENVIRONMENTS.firstOrNull { it.url == baseUrl }?.name ?: "自定义"
}
}