Starward项目绳网月报功能月份统计显示错误的分析与修复

Starward项目绳网月报功能月份统计显示错误的分析与修复

【免费下载链接】Starward Game Launcher for miHoYo - 米家游戏启动器 【免费下载链接】Starward 项目地址: https://gitcode.com/gh_mirrors/st/Starward

问题背景

在《绝区零》(Zenless Zone Zero,简称ZZZ)游戏中,绳网月报(Inter Knot Report)是一项重要的游戏内统计功能,用于记录玩家每月的游戏活动数据。Starward作为米哈游游戏启动器,实现了对绳网月报数据的抓取和展示功能。然而,在实际使用过程中,用户反馈月份统计显示存在错误,主要表现为:

  1. 月份排序混乱 - 数据显示顺序不符合时间先后
  2. 跨年月份处理异常 - 当年份变化时,月份比较逻辑出错
  3. 数据月份格式不一致 - 不同来源的月份数据格式不统一

技术架构分析

数据库结构设计

绳网月报数据存储在SQLite数据库中,主要涉及两个表:

CREATE TABLE IF NOT EXISTS InterKnotReportSummary
(
    Uid       INTEGER NOT NULL,
    DataMonth TEXT    NOT NULL,
    Value     TEXT,
    PRIMARY KEY (Uid, DataMonth)
);

CREATE TABLE IF NOT EXISTS InterKnotReportDetailItem
(
    Uid       INTEGER NOT NULL,
    Id        INTEGER NOT NULL,
    DataMonth TEXT    NOT NULL,
    DataType  TEXT    NOT NULL,
    Action    TEXT    NOT NULL,
    Time      TEXT    NOT NULL,
    Number    INTEGER NOT NULL,
    PRIMARY KEY (Uid, Id)
);

数据模型定义

public class InterKnotReportSummary
{
    [JsonPropertyName("uid")]
    [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
    public long Uid { get; set; }

    [JsonPropertyName("data_month")]
    public string DataMonth { get; set; }

    [JsonPropertyName("optional_month")]
    public List<string> OptionalMonth { get; set; }
    
    // 其他属性...
}

问题根因分析

1. 月份字符串排序问题

GetInterKnotReportSummaryList方法中,月份数据使用字符串排序:

public List<InterKnotReportSummary> GetInterKnotReportSummaryList(GameRecordRole role)
{
    if (role is null)
    {
        return new List<InterKnotReportSummary>();
    }
    using var dapper = DatabaseService.CreateConnection();
    var list = dapper.Query<InterKnotReportSummary>(
        "SELECT * FROM InterKnotReportSummary WHERE Uid = @Uid ORDER BY DataMonth DESC;", 
        new { role.Uid });
    return list.ToList();
}

这里的问题是DataMonth字段存储的是yyyyMM格式的字符串(如"202412"),当使用字符串降序排序时:

  • "202401" (1月) > "202312" (12月) ❌
  • 正确的数值顺序应该是"202312" > "202401" ✅

2. 月份比较逻辑缺陷

在月份下拉菜单生成时,存在日期解析逻辑:

foreach (string monthStr in CurrentSummary.OptionalMonth)
{
    if (DateTime.TryParseExact(monthStr, "yyyyMM", null, 
        System.Globalization.DateTimeStyles.None, out DateTime time))
    {
        MenuFlyout_GetDetails.Items.Add(new MenuFlyoutItem
        {
            Text = time.ToString("MMM"),  // 只显示月份缩写
            Command = GetDataDetailsCommand,
            CommandParameter = monthStr,
        });
    }
    else
    {
        // 解析失败的处理
    }
}

这种处理方式会导致:

  • 不同年份的同月份显示相同文本
  • 跨年时月份顺序混乱

3. 数据一致性问题

API返回的月份数据格式可能存在不一致:

  • 有些接口返回yyyy-MM格式
  • 有些接口返回yyyyMM格式
  • 数据库存储统一为yyyyMM格式

解决方案

方案一:修正数据库查询排序

将字符串排序改为数值排序:

// 修改前
"SELECT * FROM InterKnotReportSummary WHERE Uid = @Uid ORDER BY DataMonth DESC;"

// 修改后  
"SELECT * FROM InterKnotReportSummary WHERE Uid = @Uid ORDER BY CAST(DataMonth AS INTEGER) DESC;"

方案二:优化月份显示逻辑

改进月份文本生成逻辑,包含年份信息:

foreach (string monthStr in CurrentSummary.OptionalMonth)
{
    if (DateTime.TryParseExact(monthStr, "yyyyMM", null, 
        System.Globalization.DateTimeStyles.None, out DateTime time))
    {
        string displayText = $"{time:yyyy年MM月}";  // 显示完整年月
        
        MenuFlyout_GetDetails.Items.Add(new MenuFlyoutItem
        {
            Text = displayText,
            Command = GetDataDetailsCommand,
            CommandParameter = monthStr,
        });
    }
    else
    {
        MenuFlyout_GetDetails.Items.Add(new MenuFlyoutItem
        {
            Text = monthStr,  // 保持原格式
            Command = GetDataDetailsCommand,
            CommandParameter = monthStr,
        });
    }
}

方案三:统一数据格式处理

添加数据格式验证和转换层:

private string NormalizeMonthFormat(string month)
{
    if (string.IsNullOrEmpty(month))
        return month;
        
    // 处理 yyyy-MM 格式
    if (month.Contains('-') && month.Length == 7)
    {
        return month.Replace("-", "");
    }
    
    // 处理 yyyyMM 格式
    if (month.Length == 6 && int.TryParse(month, out _))
    {
        return month;
    }
    
    // 其他格式尝试解析
    if (DateTime.TryParse(month, out DateTime date))
    {
        return date.ToString("yyyyMM");
    }
    
    return month; // 无法处理的保持原样
}

实施效果验证

修复前后对比

指标修复前修复后
月份排序字符串字典序数值时间序
跨年显示混乱正确
数据一致性格式不统一统一格式
用户体验困惑清晰

性能影响评估

修改方案对性能影响极小:

  • 数据库查询:CAST操作对索引使用影响可忽略
  • 内存处理:额外的格式化操作消耗极少资源
  • 网络请求:无额外请求

最佳实践建议

1. 时间数据处理原则

mermaid

2. 数据库设计建议

对于时间相关字段,建议:

  • 使用标准格式存储(ISO 8601或数值格式)
  • 建立合适的索引
  • 避免在WHERE条件中使用函数转换

3. 代码质量提升

// 建议使用专门的时间处理工具类
public static class DateTimeHelper
{
    public static string ToStandardMonthFormat(DateTime date)
    {
        return date.ToString("yyyyMM");
    }
    
    public static DateTime? ParseMonthString(string monthStr)
    {
        if (DateTime.TryParseExact(monthStr, "yyyyMM", null, 
            System.Globalization.DateTimeStyles.None, out DateTime result))
        {
            return result;
        }
        return null;
    }
}

总结

通过本次对Starward项目绳网月报功能月份统计显示错误的深入分析和修复,我们解决了三个核心问题:

  1. 排序问题 - 通过将字符串排序改为数值排序,确保时间顺序正确
  2. 显示问题 - 优化月份文本显示,包含完整的年月信息
  3. 格式问题 - 统一数据格式处理,确保数据一致性

这次修复不仅解决了具体的功能问题,也为项目后续的时间数据处理提供了最佳实践参考。对于类似的游戏数据统计功能,建议遵循"统一存储、规范处理、友好显示"的原则,确保数据准确性和用户体验的良好平衡。

修复后的绳网月报功能能够正确显示玩家的月度游戏数据统计,为《绝区零》玩家提供准确、清晰的数据参考,提升了Starward作为游戏启动器的专业性和用户体验。

【免费下载链接】Starward Game Launcher for miHoYo - 米家游戏启动器 【免费下载链接】Starward 项目地址: https://gitcode.com/gh_mirrors/st/Starward

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值