From b5d9e21f3740512cf84b4502345a6df6e406288d Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Mon, 28 Jul 2025 11:35:47 +0800
Subject: [PATCH] =?UTF-8?q?improve:=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?=
=?UTF-8?q?=E5=88=86=E7=BA=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/DeviceIdentifier.cs | 428 ++++++++++++++++++++-----
Ink Canvas/MainWindow.xaml | 1 -
Ink Canvas/MainWindow.xaml.cs | 21 +-
3 files changed, 348 insertions(+), 102 deletions(-)
diff --git a/Ink Canvas/Helpers/DeviceIdentifier.cs b/Ink Canvas/Helpers/DeviceIdentifier.cs
index e1040389..5802522c 100644
--- a/Ink Canvas/Helpers/DeviceIdentifier.cs
+++ b/Ink Canvas/Helpers/DeviceIdentifier.cs
@@ -447,7 +447,7 @@ namespace Ink_Canvas.Helpers
}
///
- /// 使用频率统计数据结构
+ /// 使用频率统计数据结构(优化至秒级精度)
///
private class UsageStats
{
@@ -460,10 +460,20 @@ namespace Ink_Canvas.Helpers
[JsonProperty("launchCount")]
public int LaunchCount { get; set; }
+ // 新的秒级精度字段
+ [JsonProperty("totalUsageSeconds")]
+ public long TotalUsageSeconds { get; set; }
+
+ [JsonProperty("averageSessionSeconds")]
+ public double AverageSessionSeconds { get; set; }
+
+ // 保留旧字段以保持向后兼容性(已弃用)
[JsonProperty("totalUsageMinutes")]
+ [Obsolete("已弃用,请使用 TotalUsageSeconds")]
public long TotalUsageMinutes { get; set; }
[JsonProperty("averageSessionMinutes")]
+ [Obsolete("已弃用,请使用 AverageSessionSeconds")]
public double AverageSessionMinutes { get; set; }
[JsonProperty("lastUpdateCheck")]
@@ -481,12 +491,12 @@ namespace Ink_Canvas.Helpers
[JsonProperty("lastModified")]
public DateTime LastModified { get; set; }
- // 每周统计数据
+ // 每周统计数据(秒级精度)
[JsonProperty("weeklyLaunchCount")]
public int WeeklyLaunchCount { get; set; }
- [JsonProperty("weeklyUsageMinutes")]
- public long WeeklyUsageMinutes { get; set; }
+ [JsonProperty("weeklyUsageSeconds")]
+ public long WeeklyUsageSeconds { get; set; }
[JsonProperty("weekStartDate")]
public DateTime WeekStartDate { get; set; }
@@ -494,11 +504,58 @@ namespace Ink_Canvas.Helpers
[JsonProperty("lastWeekLaunchCount")]
public int LastWeekLaunchCount { get; set; }
+ [JsonProperty("lastWeekUsageSeconds")]
+ public long LastWeekUsageSeconds { get; set; }
+
+ // 保留旧字段以保持向后兼容性(已弃用)
+ [JsonProperty("weeklyUsageMinutes")]
+ [Obsolete("已弃用,请使用 WeeklyUsageSeconds")]
+ public long WeeklyUsageMinutes { get; set; }
+
[JsonProperty("lastWeekUsageMinutes")]
+ [Obsolete("已弃用,请使用 LastWeekUsageSeconds")]
public long LastWeekUsageMinutes { get; set; }
///
- /// 检查并重置每周统计数据
+ /// 数据迁移:从分钟精度迁移到秒级精度
+ ///
+ public void MigrateToSecondsPrecision()
+ {
+ try
+ {
+ // 如果新字段为空但旧字段有数据,进行迁移
+ if (TotalUsageSeconds == 0 && TotalUsageMinutes > 0)
+ {
+ TotalUsageSeconds = TotalUsageMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移总使用时长: {TotalUsageMinutes}分钟 -> {TotalUsageSeconds}秒");
+ }
+
+ if (AverageSessionSeconds == 0 && AverageSessionMinutes > 0)
+ {
+ AverageSessionSeconds = AverageSessionMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移平均会话时长: {AverageSessionMinutes}分钟 -> {AverageSessionSeconds}秒");
+ }
+
+ if (WeeklyUsageSeconds == 0 && WeeklyUsageMinutes > 0)
+ {
+ WeeklyUsageSeconds = WeeklyUsageMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移每周使用时长: {WeeklyUsageMinutes}分钟 -> {WeeklyUsageSeconds}秒");
+ }
+
+ if (LastWeekUsageSeconds == 0 && LastWeekUsageMinutes > 0)
+ {
+ LastWeekUsageSeconds = LastWeekUsageMinutes * 60;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 迁移上周使用时长: {LastWeekUsageMinutes}分钟 -> {LastWeekUsageSeconds}秒");
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 数据迁移失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 检查并重置每周统计数据(秒级精度)
///
public void CheckAndResetWeeklyStats()
{
@@ -510,14 +567,18 @@ namespace Ink_Canvas.Helpers
{
// 保存上周数据
LastWeekLaunchCount = WeeklyLaunchCount;
- LastWeekUsageMinutes = WeeklyUsageMinutes;
+ LastWeekUsageSeconds = WeeklyUsageSeconds;
+
+ // 同时更新旧字段以保持兼容性
+ LastWeekUsageMinutes = LastWeekUsageSeconds / 60;
// 重置本周数据
WeeklyLaunchCount = 0;
+ WeeklyUsageSeconds = 0;
WeeklyUsageMinutes = 0;
WeekStartDate = currentWeekStart;
- LogHelper.WriteLogToFile($"DeviceIdentifier | 每周统计重置 - 上周启动: {LastWeekLaunchCount}次, 上周使用: {LastWeekUsageMinutes}分钟");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 每周统计重置 - 上周启动: {LastWeekLaunchCount}次, 上周使用: {FormatDuration(LastWeekUsageSeconds)}");
}
}
@@ -541,20 +602,25 @@ namespace Ink_Canvas.Helpers
}
///
- /// 记录本周的使用时长
+ /// 记录本周的使用时长(秒级精度)
///
- public void RecordWeeklyUsage(long minutes)
+ public void RecordWeeklyUsage(long seconds)
{
CheckAndResetWeeklyStats();
- WeeklyUsageMinutes += minutes;
+ WeeklyUsageSeconds += seconds;
+ // 同时更新旧字段以保持兼容性
+ WeeklyUsageMinutes = WeeklyUsageSeconds / 60;
}
+
+
///
- /// 计算数据哈希值用于完整性验证
+ /// 计算数据哈希值用于完整性验证(秒级精度)
///
public void UpdateDataHash()
{
- var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageMinutes}|{DataIntegrityKey}";
+ // 使用秒级精度数据计算哈希
+ var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageSeconds}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageSeconds}|{DataIntegrityKey}";
using (var sha256 = SHA256.Create())
{
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(dataString));
@@ -564,17 +630,30 @@ namespace Ink_Canvas.Helpers
}
///
- /// 验证数据完整性
+ /// 验证数据完整性(秒级精度)
///
public bool VerifyDataIntegrity()
{
try
{
- var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageMinutes}|{DataIntegrityKey}";
+ // 首先尝试使用秒级精度验证
+ var dataString = $"{DeviceId}|{LaunchCount}|{TotalUsageSeconds}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageSeconds}|{DataIntegrityKey}";
using (var sha256 = SHA256.Create())
{
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(dataString));
var expectedHash = Convert.ToBase64String(hashBytes);
+ if (DataHash == expectedHash)
+ {
+ return true;
+ }
+ }
+
+ // 如果秒级精度验证失败,尝试使用旧的分钟精度验证(向后兼容)
+ var oldDataString = $"{DeviceId}|{LaunchCount}|{TotalUsageMinutes}|{LastLaunchTime:yyyyMMddHHmmss}|{WeeklyLaunchCount}|{WeeklyUsageMinutes}|{DataIntegrityKey}";
+ using (var sha256 = SHA256.Create())
+ {
+ var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(oldDataString));
+ var expectedHash = Convert.ToBase64String(hashBytes);
return DataHash == expectedHash;
}
}
@@ -585,6 +664,37 @@ namespace Ink_Canvas.Helpers
}
}
+ ///
+ /// 格式化时长显示(秒级精度)
+ ///
+ /// 总秒数
+ /// 格式化的时长字符串
+ public static string FormatDuration(long totalSeconds)
+ {
+ if (totalSeconds < 60)
+ {
+ return $"{totalSeconds}秒";
+ }
+ else if (totalSeconds < 3600)
+ {
+ var minutes = totalSeconds / 60;
+ var seconds = totalSeconds % 60;
+ return seconds > 0 ? $"{minutes}分{seconds}秒" : $"{minutes}分钟";
+ }
+ else
+ {
+ var hours = totalSeconds / 3600;
+ var minutes = (totalSeconds % 3600) / 60;
+ var seconds = totalSeconds % 60;
+
+ var result = $"{hours}小时";
+ if (minutes > 0) result += $"{minutes}分";
+ if (seconds > 0) result += $"{seconds}秒";
+
+ return result;
+ }
+ }
+
///
/// 更新推送优先级枚举
///
@@ -640,7 +750,7 @@ namespace Ink_Canvas.Helpers
}
///
- /// 记录应用退出(计算使用时长)
+ /// 记录应用退出(计算使用时长 - 秒级精度)
///
public static void RecordAppExit()
{
@@ -650,21 +760,31 @@ namespace Ink_Canvas.Helpers
{
var stats = LoadUsageStats();
- // 计算本次会话时长
- long sessionMinutes = 0;
+ // 执行数据迁移(如果需要)
+ stats.MigrateToSecondsPrecision();
+
+ // 计算本次会话时长(秒级精度)
+ long sessionSeconds = 0;
if (stats.LastLaunchTime != DateTime.MinValue)
{
var sessionDuration = DateTime.Now - stats.LastLaunchTime;
- sessionMinutes = (long)sessionDuration.TotalMinutes;
- stats.TotalUsageMinutes += sessionMinutes;
+ sessionSeconds = (long)sessionDuration.TotalSeconds;
- // 记录每周使用时长
- stats.RecordWeeklyUsage(sessionMinutes);
+ // 更新秒级精度数据
+ stats.TotalUsageSeconds += sessionSeconds;
- // 更新平均会话时长
+ // 同时更新旧字段以保持兼容性
+ stats.TotalUsageMinutes = stats.TotalUsageSeconds / 60;
+
+ // 记录每周使用时长(秒级精度)
+ stats.RecordWeeklyUsage(sessionSeconds);
+
+ // 更新平均会话时长(秒级精度)
if (stats.LaunchCount > 0)
{
- stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ stats.AverageSessionSeconds = (double)stats.TotalUsageSeconds / stats.LaunchCount;
+ // 同时更新旧字段以保持兼容性
+ stats.AverageSessionMinutes = stats.AverageSessionSeconds / 60;
}
}
@@ -676,7 +796,9 @@ namespace Ink_Canvas.Helpers
SaveUsageStats(stats);
- LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用退出 - 本次会话: {sessionMinutes}分钟, 总时长: {stats.TotalUsageMinutes}分钟, 本周时长: {stats.WeeklyUsageMinutes}分钟");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 记录应用退出 - 本次会话: {FormatDuration(sessionSeconds)}, " +
+ $"总时长: {FormatDuration(stats.TotalUsageSeconds)}, " +
+ $"本周时长: {FormatDuration(stats.WeeklyUsageSeconds)}");
}
}
catch (Exception ex)
@@ -699,16 +821,28 @@ namespace Ink_Canvas.Helpers
// 计算最近活跃度
var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
- // 使用真实的每周数据
+ // 使用真实的每周数据(秒级精度)
var currentWeekLaunches = stats.WeeklyLaunchCount;
- var currentWeekMinutes = stats.WeeklyUsageMinutes;
+ var currentWeekSeconds = stats.WeeklyUsageSeconds;
+
+ // 如果秒级数据为空但分钟数据存在,进行转换
+ if (currentWeekSeconds == 0 && stats.WeeklyUsageMinutes > 0)
+ {
+ currentWeekSeconds = stats.WeeklyUsageMinutes * 60;
+ }
// 如果本周数据不足,参考上周数据
var weeklyLaunches = currentWeekLaunches > 0 ? currentWeekLaunches : stats.LastWeekLaunchCount;
- var weeklyMinutes = currentWeekMinutes > 0 ? currentWeekMinutes : stats.LastWeekUsageMinutes;
+ var weeklySeconds = currentWeekSeconds > 0 ? currentWeekSeconds : stats.LastWeekUsageSeconds;
+
+ // 如果秒级数据仍为空,使用分钟数据转换
+ if (weeklySeconds == 0 && stats.LastWeekUsageMinutes > 0)
+ {
+ weeklySeconds = stats.LastWeekUsageMinutes * 60;
+ }
// 综合评分系统(0-100分)
- var frequencyScore = CalculateFrequencyScoreWithWeeklyData(stats, daysSinceLastUse, weeklyLaunches, weeklyMinutes);
+ var frequencyScore = CalculateFrequencyScoreWithWeeklyData(stats, daysSinceLastUse, weeklyLaunches, weeklySeconds);
// 根据综合评分确定频率分类和更新优先级
if (frequencyScore >= 80)
@@ -728,7 +862,7 @@ namespace Ink_Canvas.Helpers
}
LogHelper.WriteLogToFile($"DeviceIdentifier | 使用频率计算 - 评分: {frequencyScore}, 频率: {stats.UsageFrequency}, " +
- $"优先级: {stats.UpdatePriority}, 本周启动: {currentWeekLaunches}次, 本周时长: {currentWeekMinutes}分钟");
+ $"优先级: {stats.UpdatePriority}, 本周启动: {currentWeekLaunches}次, 本周时长: {FormatDuration(currentWeekSeconds)}");
}
catch (Exception ex)
{
@@ -740,16 +874,16 @@ namespace Ink_Canvas.Helpers
}
///
- /// 基于每周真实数据计算综合频率评分(0-100分)
+ /// 基于每周真实数据计算综合频率评分(0-100分,秒级精度)
/// 评分标准:≥80分=高频用户,40-79分=中频用户,<40分=低频用户
///
/// 使用统计数据
/// 距离最后使用的天数
/// 每周启动次数
- /// 每周使用时长
+ /// 每周使用时长(秒)
/// 综合评分(0-100分)
private static int CalculateFrequencyScoreWithWeeklyData(UsageStats stats, double daysSinceLastUse,
- long weeklyLaunches, long weeklyMinutes)
+ long weeklyLaunches, long weeklySeconds)
{
var score = 0;
@@ -766,16 +900,17 @@ namespace Ink_Canvas.Helpers
else if (weeklyLaunches >= 3) score += 15; // 3-4次:中频使用
else if (weeklyLaunches >= 1) score += 10; // 1-2次:低频使用
- // 每周使用时长评分(20分)- 基于真实的每周使用时长
- if (weeklyMinutes >= 600) score += 20; // 10小时以上:重度使用
- else if (weeklyMinutes >= 300) score += 15; // 5-10小时:中重度使用
- else if (weeklyMinutes >= 120) score += 10; // 2-5小时:中度使用
- else if (weeklyMinutes >= 60) score += 5; // 1-2小时:轻度使用
+ // 每周使用时长评分(20分)- 基于真实的每周使用时长(秒级精度)
+ if (weeklySeconds >= 36000) score += 20; // 10小时以上:重度使用
+ else if (weeklySeconds >= 18000) score += 15; // 5-10小时:中重度使用
+ else if (weeklySeconds >= 7200) score += 10; // 2-5小时:中度使用
+ else if (weeklySeconds >= 3600) score += 5; // 1-2小时:轻度使用
- // 历史使用深度评分(10分)- 反映用户的长期使用习惯
- if (stats.TotalUsageMinutes >= 3000) score += 10; // 50小时以上:资深用户
- else if (stats.TotalUsageMinutes >= 1200) score += 7; // 20-50小时:中等用户
- else if (stats.TotalUsageMinutes >= 300) score += 4; // 5-20小时:新手用户
+ // 历史使用深度评分(10分)- 反映用户的长期使用习惯(秒级精度)
+ var totalSeconds = stats.TotalUsageSeconds > 0 ? stats.TotalUsageSeconds : stats.TotalUsageMinutes * 60;
+ if (totalSeconds >= 180000) score += 10; // 50小时以上:资深用户
+ else if (totalSeconds >= 72000) score += 7; // 20-50小时:中等用户
+ else if (totalSeconds >= 18000) score += 4; // 5-20小时:新手用户
return Math.Min(100, score);
}
@@ -817,14 +952,14 @@ namespace Ink_Canvas.Helpers
}
///
- /// 获取使用统计信息
+ /// 获取使用统计信息(秒级精度)
///
- public static (int launchCount, long totalMinutes, double avgSession, UpdatePriority priority) GetUsageStats()
+ public static (int launchCount, long totalSeconds, double avgSessionSeconds, UpdatePriority priority) GetUsageStats()
{
try
{
var stats = LoadUsageStats();
- return (stats.LaunchCount, stats.TotalUsageMinutes, stats.AverageSessionMinutes, stats.UpdatePriority);
+ return (stats.LaunchCount, stats.TotalUsageSeconds, stats.AverageSessionSeconds, stats.UpdatePriority);
}
catch (Exception ex)
{
@@ -834,7 +969,27 @@ namespace Ink_Canvas.Helpers
}
///
- /// 加载使用统计 - 支持多重备份恢复和智能反篡改(强化版本)
+ /// 获取使用统计信息(兼容性方法 - 分钟精度)
+ ///
+ [Obsolete("请使用 GetUsageStats() 获取秒级精度数据")]
+ public static (int launchCount, long totalMinutes, double avgSessionMinutes, UpdatePriority priority) GetUsageStatsInMinutes()
+ {
+ try
+ {
+ var stats = LoadUsageStats();
+ var totalMinutes = stats.TotalUsageSeconds / 60;
+ var avgMinutes = stats.AverageSessionSeconds / 60;
+ return (stats.LaunchCount, totalMinutes, avgMinutes, stats.UpdatePriority);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 获取使用统计失败: {ex.Message}", LogHelper.LogType.Error);
+ return (0, 0, 0, UpdatePriority.Medium);
+ }
+ }
+
+ ///
+ /// 加载使用统计 - 支持多重备份恢复和智能反篡改
///
private static UsageStats LoadUsageStats()
{
@@ -851,6 +1006,9 @@ namespace Ink_Canvas.Helpers
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 使用最可信数据源恢复使用统计: {bestData.Source}");
+ // 执行数据迁移(如果需要)
+ bestData.Stats.MigrateToSecondsPrecision();
+
// 确保备份同步
SaveUsageStatsToAllLocations(bestData.Stats);
return bestData.Stats;
@@ -864,6 +1022,10 @@ namespace Ink_Canvas.Helpers
if (partiallyRecoveredData != null)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 从部分损坏数据中恢复使用统计");
+
+ // 执行数据迁移(如果需要)
+ partiallyRecoveredData.MigrateToSecondsPrecision();
+
SaveUsageStatsToAllLocations(partiallyRecoveredData);
return partiallyRecoveredData;
}
@@ -873,14 +1035,16 @@ namespace Ink_Canvas.Helpers
LogHelper.WriteLogToFile($"DeviceIdentifier | 加载使用统计失败: {ex.Message}", LogHelper.LogType.Error);
}
- // 返回新的统计对象
+ // 返回新的统计对象(秒级精度)
var newStats = new UsageStats
{
DeviceId = DeviceId,
LastLaunchTime = DateTime.Now,
LaunchCount = 0,
- TotalUsageMinutes = 0,
- AverageSessionMinutes = 0,
+ TotalUsageSeconds = 0,
+ AverageSessionSeconds = 0,
+ TotalUsageMinutes = 0, // 保持兼容性
+ AverageSessionMinutes = 0, // 保持兼容性
LastUpdateCheck = DateTime.MinValue,
UpdatePriority = UpdatePriority.Medium,
UsageFrequency = UsageFrequency.Medium
@@ -1129,8 +1293,9 @@ namespace Ink_Canvas.Helpers
UsageFrequency = UsageFrequency.Medium
};
- // 使用多数投票或最大值策略恢复关键数据
+ // 使用多数投票或最大值策略恢复关键数据(秒级精度)
var launchCounts = dataSources.Where(d => d.Stats.LaunchCount > 0).Select(d => d.Stats.LaunchCount).ToList();
+ var usageSeconds = dataSources.Where(d => d.Stats.TotalUsageSeconds > 0).Select(d => d.Stats.TotalUsageSeconds).ToList();
var usageMinutes = dataSources.Where(d => d.Stats.TotalUsageMinutes > 0).Select(d => d.Stats.TotalUsageMinutes).ToList();
if (launchCounts.Count > 0)
@@ -1138,15 +1303,23 @@ namespace Ink_Canvas.Helpers
recoveredStats.LaunchCount = (int)launchCounts.Average(); // 使用平均值
}
- if (usageMinutes.Count > 0)
+ // 优先使用秒级数据,如果没有则使用分钟数据转换
+ if (usageSeconds.Count > 0)
+ {
+ recoveredStats.TotalUsageSeconds = (long)usageSeconds.Average(); // 使用平均值
+ recoveredStats.TotalUsageMinutes = recoveredStats.TotalUsageSeconds / 60; // 兼容性
+ }
+ else if (usageMinutes.Count > 0)
{
recoveredStats.TotalUsageMinutes = (long)usageMinutes.Average(); // 使用平均值
+ recoveredStats.TotalUsageSeconds = recoveredStats.TotalUsageMinutes * 60; // 转换为秒
}
- // 重新计算平均会话时长
+ // 重新计算平均会话时长(秒级精度)
if (recoveredStats.LaunchCount > 0)
{
- recoveredStats.AverageSessionMinutes = (double)recoveredStats.TotalUsageMinutes / recoveredStats.LaunchCount;
+ recoveredStats.AverageSessionSeconds = (double)recoveredStats.TotalUsageSeconds / recoveredStats.LaunchCount;
+ recoveredStats.AverageSessionMinutes = recoveredStats.AverageSessionSeconds / 60; // 兼容性
}
// 重新计算使用频率
@@ -1155,7 +1328,7 @@ namespace Ink_Canvas.Helpers
// 更新数据完整性哈希
recoveredStats.UpdateDataHash();
- LogHelper.WriteLogToFile($"DeviceIdentifier | 部分数据恢复完成 - 启动次数: {recoveredStats.LaunchCount}, 使用时长: {recoveredStats.TotalUsageMinutes}分钟");
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 部分数据恢复完成 - 启动次数: {recoveredStats.LaunchCount}, 使用时长: {FormatDuration(recoveredStats.TotalUsageSeconds)}");
return recoveredStats;
}
catch (Exception ex)
@@ -1178,19 +1351,32 @@ namespace Ink_Canvas.Helpers
{
var deviceId = key.GetValue("DeviceId") as string;
var launchCount = key.GetValue("LaunchCount");
+
+ // 秒级精度数据
+ var totalSeconds = key.GetValue("TotalUsageSeconds");
+ var avgSessionSeconds = key.GetValue("AverageSessionSeconds");
+
+ // 兼容性:分钟精度数据
var totalMinutes = key.GetValue("TotalUsageMinutes");
+ var avgSessionMinutes = key.GetValue("AverageSessionMinutes");
+
var lastLaunch = key.GetValue("LastLaunchTime") as string;
var priority = key.GetValue("UpdatePriority");
var frequency = key.GetValue("UsageFrequency");
var dataHash = key.GetValue("DataHash") as string;
var lastUpdate = key.GetValue("LastUpdate") as string;
- // 每周统计数据
+ // 每周统计数据(秒级精度)
var weeklyLaunchCount = key.GetValue("WeeklyLaunchCount");
+ var weeklyUsageSeconds = key.GetValue("WeeklyUsageSeconds");
+ var lastWeekUsageSeconds = key.GetValue("LastWeekUsageSeconds");
+
+ // 兼容性:分钟精度数据
var weeklyUsageMinutes = key.GetValue("WeeklyUsageMinutes");
+ var lastWeekUsageMinutes = key.GetValue("LastWeekUsageMinutes");
+
var weekStartDate = key.GetValue("WeekStartDate") as string;
var lastWeekLaunchCount = key.GetValue("LastWeekLaunchCount");
- var lastWeekUsageMinutes = key.GetValue("LastWeekUsageMinutes");
if (!string.IsNullOrEmpty(deviceId) && launchCount != null)
{
@@ -1198,26 +1384,42 @@ namespace Ink_Canvas.Helpers
{
DeviceId = deviceId,
LaunchCount = Convert.ToInt32(launchCount),
+
+ // 秒级精度数据
+ TotalUsageSeconds = totalSeconds != null ? Convert.ToInt64(totalSeconds) : 0,
+ AverageSessionSeconds = avgSessionSeconds != null ? Convert.ToDouble(avgSessionSeconds) : 0,
+
+ // 兼容性:分钟精度数据
TotalUsageMinutes = totalMinutes != null ? Convert.ToInt64(totalMinutes) : 0,
+ AverageSessionMinutes = avgSessionMinutes != null ? Convert.ToDouble(avgSessionMinutes) : 0,
+
LastLaunchTime = DateTime.TryParse(lastLaunch, out var dt) ? dt : DateTime.Now,
UpdatePriority = priority != null ? (UpdatePriority)Convert.ToInt32(priority) : UpdatePriority.Medium,
UsageFrequency = frequency != null ? (UsageFrequency)Convert.ToInt32(frequency) : UsageFrequency.Medium,
DataHash = dataHash,
- AverageSessionMinutes = 0,
LastUpdateCheck = DateTime.MinValue,
- // 每周统计数据
+ // 每周统计数据(秒级精度)
WeeklyLaunchCount = weeklyLaunchCount != null ? Convert.ToInt32(weeklyLaunchCount) : 0,
+ WeeklyUsageSeconds = weeklyUsageSeconds != null ? Convert.ToInt64(weeklyUsageSeconds) : 0,
+ LastWeekUsageSeconds = lastWeekUsageSeconds != null ? Convert.ToInt64(lastWeekUsageSeconds) : 0,
+
+ // 兼容性:分钟精度数据
WeeklyUsageMinutes = weeklyUsageMinutes != null ? Convert.ToInt64(weeklyUsageMinutes) : 0,
+ LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0,
+
WeekStartDate = DateTime.TryParse(weekStartDate, out var wsd) ? wsd : DateTime.MinValue,
- LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0,
- LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0
+ LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0
};
+ // 执行数据迁移(如果需要)
+ stats.MigrateToSecondsPrecision();
+
// 重新计算平均会话时长
- if (stats.LaunchCount > 0)
+ if (stats.LaunchCount > 0 && stats.AverageSessionSeconds == 0)
{
- stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ stats.AverageSessionSeconds = (double)stats.TotalUsageSeconds / stats.LaunchCount;
+ stats.AverageSessionMinutes = stats.AverageSessionSeconds / 60;
}
var dataSource = new DataSourceInfo
@@ -1260,46 +1462,75 @@ namespace Ink_Canvas.Helpers
if (key != null)
{
var launchCount = key.GetValue("LC");
+
+ // 秒级精度数据
+ var totalSeconds = key.GetValue("TUS");
+ var avgSessionSeconds = key.GetValue("ASS");
+
+ // 兼容性:分钟精度数据
var totalMinutes = key.GetValue("TUM");
+ var avgSessionMinutes = key.GetValue("ASM");
+
var lastLaunchBinary = key.GetValue("LLT");
var priority = key.GetValue("UP");
var frequency = key.GetValue("UF");
var dataHash = key.GetValue("DH") as string;
var lastUpdateBinary = key.GetValue("LU");
- // 每周统计数据
+ // 每周统计数据(秒级精度)
var weeklyLaunchCount = key.GetValue("WLC");
+ var weeklyUsageSeconds = key.GetValue("WUS");
+ var lastWeekUsageSeconds = key.GetValue("LWUS");
+
+ // 兼容性:分钟精度数据
var weeklyUsageMinutes = key.GetValue("WUM");
- var weekStartDateBinary = key.GetValue("WSD");
- var lastWeekLaunchCount = key.GetValue("LWLC");
var lastWeekUsageMinutes = key.GetValue("LWUM");
- if (launchCount != null && totalMinutes != null)
+ var weekStartDateBinary = key.GetValue("WSD");
+ var lastWeekLaunchCount = key.GetValue("LWLC");
+
+ if (launchCount != null && (totalSeconds != null || totalMinutes != null))
{
var stats = new UsageStats
{
DeviceId = DeviceId,
LaunchCount = Convert.ToInt32(launchCount),
- TotalUsageMinutes = Convert.ToInt64(totalMinutes),
+
+ // 秒级精度数据
+ TotalUsageSeconds = totalSeconds != null ? Convert.ToInt64(totalSeconds) : 0,
+ AverageSessionSeconds = avgSessionSeconds != null ? Convert.ToDouble(avgSessionSeconds) : 0,
+
+ // 兼容性:分钟精度数据
+ TotalUsageMinutes = totalMinutes != null ? Convert.ToInt64(totalMinutes) : 0,
+ AverageSessionMinutes = avgSessionMinutes != null ? Convert.ToDouble(avgSessionMinutes) : 0,
+
LastLaunchTime = lastLaunchBinary != null ? DateTime.FromBinary(Convert.ToInt64(lastLaunchBinary)) : DateTime.Now,
UpdatePriority = priority != null ? (UpdatePriority)Convert.ToInt32(priority) : UpdatePriority.Medium,
UsageFrequency = frequency != null ? (UsageFrequency)Convert.ToInt32(frequency) : UsageFrequency.Medium,
DataHash = dataHash,
- AverageSessionMinutes = 0,
LastUpdateCheck = DateTime.MinValue,
- // 每周统计数据
+ // 每周统计数据(秒级精度)
WeeklyLaunchCount = weeklyLaunchCount != null ? Convert.ToInt32(weeklyLaunchCount) : 0,
+ WeeklyUsageSeconds = weeklyUsageSeconds != null ? Convert.ToInt64(weeklyUsageSeconds) : 0,
+ LastWeekUsageSeconds = lastWeekUsageSeconds != null ? Convert.ToInt64(lastWeekUsageSeconds) : 0,
+
+ // 兼容性:分钟精度数据
WeeklyUsageMinutes = weeklyUsageMinutes != null ? Convert.ToInt64(weeklyUsageMinutes) : 0,
+ LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0,
+
WeekStartDate = weekStartDateBinary != null ? DateTime.FromBinary(Convert.ToInt64(weekStartDateBinary)) : DateTime.MinValue,
- LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0,
- LastWeekUsageMinutes = lastWeekUsageMinutes != null ? Convert.ToInt64(lastWeekUsageMinutes) : 0
+ LastWeekLaunchCount = lastWeekLaunchCount != null ? Convert.ToInt32(lastWeekLaunchCount) : 0
};
+ // 执行数据迁移(如果需要)
+ stats.MigrateToSecondsPrecision();
+
// 重新计算平均会话时长
- if (stats.LaunchCount > 0)
+ if (stats.LaunchCount > 0 && stats.AverageSessionSeconds == 0)
{
- stats.AverageSessionMinutes = (double)stats.TotalUsageMinutes / stats.LaunchCount;
+ stats.AverageSessionSeconds = (double)stats.TotalUsageSeconds / stats.LaunchCount;
+ stats.AverageSessionMinutes = stats.AverageSessionSeconds / 60;
}
var dataSource = new DataSourceInfo
@@ -1497,21 +1728,35 @@ namespace Ink_Canvas.Helpers
{
key.SetValue("DeviceId", stats.DeviceId);
key.SetValue("LaunchCount", stats.LaunchCount);
+
+ // 秒级精度数据
+ key.SetValue("TotalUsageSeconds", stats.TotalUsageSeconds);
+ key.SetValue("AverageSessionSeconds", stats.AverageSessionSeconds);
+
+ // 兼容性:分钟精度数据
key.SetValue("TotalUsageMinutes", stats.TotalUsageMinutes);
+ key.SetValue("AverageSessionMinutes", stats.AverageSessionMinutes);
+
key.SetValue("LastLaunchTime", stats.LastLaunchTime.ToString("yyyy-MM-dd HH:mm:ss"));
key.SetValue("UpdatePriority", (int)stats.UpdatePriority);
key.SetValue("UsageFrequency", (int)stats.UsageFrequency);
key.SetValue("DataHash", stats.DataHash ?? "");
key.SetValue("LastUpdate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
- // 每周统计数据
+ // 每周统计数据(秒级精度)
key.SetValue("WeeklyLaunchCount", stats.WeeklyLaunchCount);
+ key.SetValue("WeeklyUsageSeconds", stats.WeeklyUsageSeconds);
+ key.SetValue("LastWeekUsageSeconds", stats.LastWeekUsageSeconds);
+
+ // 兼容性:分钟精度数据
key.SetValue("WeeklyUsageMinutes", stats.WeeklyUsageMinutes);
- key.SetValue("WeekStartDate", stats.WeekStartDate.ToString("yyyy-MM-dd"));
- key.SetValue("LastWeekLaunchCount", stats.LastWeekLaunchCount);
key.SetValue("LastWeekUsageMinutes", stats.LastWeekUsageMinutes);
- LogHelper.WriteLogToFile($"DeviceIdentifier | 使用统计已保存到主注册表 - 总启动: {stats.LaunchCount}次, 本周启动: {stats.WeeklyLaunchCount}次, 总时长: {stats.TotalUsageMinutes}分钟, 本周时长: {stats.WeeklyUsageMinutes}分钟");
+ key.SetValue("WeekStartDate", stats.WeekStartDate.ToString("yyyy-MM-dd"));
+ key.SetValue("LastWeekLaunchCount", stats.LastWeekLaunchCount);
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 使用统计已保存到主注册表 - 总启动: {stats.LaunchCount}次, 本周启动: {stats.WeeklyLaunchCount}次, " +
+ $"总时长: {FormatDuration(stats.TotalUsageSeconds)}, 本周时长: {FormatDuration(stats.WeeklyUsageSeconds)}");
}
else
{
@@ -1548,21 +1793,34 @@ namespace Ink_Canvas.Helpers
{
if (key != null)
{
- // 使用编码的键名来隐藏数据
+ // 使用编码的键名来隐藏数据(秒级精度)
key.SetValue("LC", stats.LaunchCount); // LaunchCount
+
+ // 秒级精度数据
+ key.SetValue("TUS", stats.TotalUsageSeconds); // TotalUsageSeconds
+ key.SetValue("ASS", stats.AverageSessionSeconds); // AverageSessionSeconds
+
+ // 兼容性:分钟精度数据
key.SetValue("TUM", stats.TotalUsageMinutes); // TotalUsageMinutes
+ key.SetValue("ASM", stats.AverageSessionMinutes); // AverageSessionMinutes
+
key.SetValue("LLT", stats.LastLaunchTime.ToBinary()); // LastLaunchTime
key.SetValue("UP", (int)stats.UpdatePriority); // UpdatePriority
key.SetValue("UF", (int)stats.UsageFrequency); // UsageFrequency
key.SetValue("DH", stats.DataHash ?? ""); // DataHash
key.SetValue("LU", DateTime.Now.ToBinary()); // LastUpdate
- // 每周统计数据
+ // 每周统计数据(秒级精度)
key.SetValue("WLC", stats.WeeklyLaunchCount); // WeeklyLaunchCount
+ key.SetValue("WUS", stats.WeeklyUsageSeconds); // WeeklyUsageSeconds
+ key.SetValue("LWUS", stats.LastWeekUsageSeconds); // LastWeekUsageSeconds
+
+ // 兼容性:分钟精度数据
key.SetValue("WUM", stats.WeeklyUsageMinutes); // WeeklyUsageMinutes
+ key.SetValue("LWUM", stats.LastWeekUsageMinutes); // LastWeekUsageMinutes
+
key.SetValue("WSD", stats.WeekStartDate.ToBinary()); // WeekStartDate
key.SetValue("LWLC", stats.LastWeekLaunchCount); // LastWeekLaunchCount
- key.SetValue("LWUM", stats.LastWeekUsageMinutes); // LastWeekUsageMinutes
successCount++;
LogHelper.WriteLogToFile($"DeviceIdentifier | 成功保存到备用注册表位置: {path}");
@@ -2013,15 +2271,15 @@ namespace Ink_Canvas.Helpers
{
try
{
- var (launchCount, totalMinutes, avgSession, priority) = GetUsageStats();
+ var (launchCount, totalSeconds, avgSessionSeconds, priority) = GetUsageStats();
var frequency = GetUsageFrequency();
var stats = LoadUsageStats();
var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
return $"设备ID: {DeviceId}\n" +
$"启动次数: {launchCount}\n" +
- $"总使用时长: {totalMinutes}分钟 ({totalMinutes / 60.0:F1}小时)\n" +
- $"平均会话时长: {avgSession:F1}分钟\n" +
+ $"总使用时长: {FormatDuration(totalSeconds)}\n" +
+ $"平均会话时长: {FormatDuration((long)avgSessionSeconds)}\n" +
$"使用频率: {frequency}\n" +
$"更新优先级: {priority}\n" +
$"最后使用: {daysSinceLastUse:F1}天前\n" +
@@ -2209,11 +2467,11 @@ namespace Ink_Canvas.Helpers
{
summary.AppendLine($"数据完整性: {(stats.VerifyDataIntegrity() ? "✓" : "✗")}");
summary.AppendLine($"总启动次数: {stats.LaunchCount}");
- summary.AppendLine($"总使用时长: {stats.TotalUsageMinutes}分钟 ({stats.TotalUsageMinutes / 60.0:F1}小时)");
+ summary.AppendLine($"总使用时长: {FormatDuration(stats.TotalUsageSeconds)}");
summary.AppendLine($"本周启动次数: {stats.WeeklyLaunchCount}");
- summary.AppendLine($"本周使用时长: {stats.WeeklyUsageMinutes}分钟 ({stats.WeeklyUsageMinutes / 60.0:F1}小时)");
+ summary.AppendLine($"本周使用时长: {FormatDuration(stats.WeeklyUsageSeconds)}");
summary.AppendLine($"上周启动次数: {stats.LastWeekLaunchCount}");
- summary.AppendLine($"上周使用时长: {stats.LastWeekUsageMinutes}分钟 ({stats.LastWeekUsageMinutes / 60.0:F1}小时)");
+ summary.AppendLine($"上周使用时长: {FormatDuration(stats.LastWeekUsageSeconds)}");
summary.AppendLine($"本周开始日期: {(stats.WeekStartDate != DateTime.MinValue ? stats.WeekStartDate.ToString("yyyy-MM-dd") : "未设置")}");
summary.AppendLine($"使用频率: {stats.UsageFrequency}");
summary.AppendLine($"更新优先级: {stats.UpdatePriority}");
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index ca788761..081c9693 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -5793,7 +5793,6 @@
-