mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
add wiki weapon page
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
[*.cs]
|
||||
charset = utf-8-bom
|
||||
|
||||
[*.cs]
|
||||
|
||||
# SA1101: Prefix local calls with this
|
||||
dotnet_diagnostic.SA1101.severity = none
|
||||
@@ -76,31 +78,31 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_diagnostic.SA1629.severity = none
|
||||
dotnet_diagnostic.SA1642.severity = none
|
||||
@@ -185,29 +187,29 @@ dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.类型.required_modifiers =
|
||||
dotnet_naming_symbols.类型.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.非字段成员.required_modifiers =
|
||||
dotnet_naming_symbols.非字段成员.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.以_i_开始.required_prefix = I
|
||||
dotnet_naming_style.以_i_开始.required_suffix =
|
||||
dotnet_naming_style.以_i_开始.word_separator =
|
||||
dotnet_naming_style.以_i_开始.required_suffix =
|
||||
dotnet_naming_style.以_i_开始.word_separator =
|
||||
dotnet_naming_style.以_i_开始.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||
|
||||
@@ -26,7 +26,6 @@ public class HttpClientGenerator : ISourceGenerator
|
||||
|
||||
private const string PrimaryHttpMessageHandlerAttributeName = "Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient.PrimaryHttpMessageHandlerAttribute";
|
||||
private const string DynamicSecretAttributeName = "Snap.Hutao.Web.Hoyolab.DynamicSecret.UseDynamicSecretAttribute";
|
||||
private const string IgnoreSetCookieAttributeName = "Snap.Hutao.Web.Hoyolab.Annotation.IgnoreSetCookieAttribute";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
@@ -54,7 +53,6 @@ public class HttpClientGenerator : ISourceGenerator
|
||||
// This class is generated by Snap.Hutao.SourceGeneration
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using System.Net.Http;
|
||||
|
||||
@@ -83,10 +81,7 @@ internal static partial class IocHttpClientConfiguration
|
||||
|
||||
foreach (INamedTypeSymbol classSymbol in receiver.Classes)
|
||||
{
|
||||
lineBuilder
|
||||
.Clear()
|
||||
.Append("\r\n");
|
||||
|
||||
lineBuilder.Clear().Append(Environment.NewLine);
|
||||
lineBuilder.Append(@" services.AddHttpClient<");
|
||||
lineBuilder.Append($"{classSymbol.ToDisplayString()}>(");
|
||||
|
||||
@@ -139,11 +134,6 @@ internal static partial class IocHttpClientConfiguration
|
||||
lineBuilder.Append(".AddHttpMessageHandler<DynamicSecretHandler>()");
|
||||
}
|
||||
|
||||
if (classSymbol.GetAttributes().Any(attr => attr.AttributeClass!.ToDisplayString() == IgnoreSetCookieAttributeName))
|
||||
{
|
||||
lineBuilder.Append(".AddHttpMessageHandler<IgnoreSetCookieHandler>()");
|
||||
}
|
||||
|
||||
lineBuilder.Append(";");
|
||||
|
||||
lines.Add(lineBuilder.ToString());
|
||||
|
||||
@@ -41,8 +41,10 @@
|
||||
<shmmc:AvatarSideIconConverter x:Key="AvatarSideIconConverter"/>
|
||||
<shmmc:DescParamDescriptor x:Key="DescParamDescriptor"/>
|
||||
<shmmc:ElementNameIconConverter x:Key="ElementNameIconConverter"/>
|
||||
<shmmc:EquipIconConverter x:Key="EquipIconConverter"/>
|
||||
<shmmc:GachaAvatarImgConverter x:Key="GachaAvatarImgConverter"/>
|
||||
<shmmc:GachaAvatarIconConverter x:Key="GachaAvatarIconConverter"/>
|
||||
<shmmc:GachaEquipIconConverter x:Key="GachaEquipIconConverter"/>
|
||||
<shmmc:ItemIconConverter x:Key="ItemIconConverter"/>
|
||||
<shmmc:PropertyInfoDescriptor x:Key="PropertyDescriptor"/>
|
||||
<shmmc:QualityColorConverter x:Key="QualityColorConverter"/>
|
||||
|
||||
@@ -10,8 +10,11 @@ namespace Snap.Hutao.Context.Database;
|
||||
/// <summary>
|
||||
/// 应用程序数据库上下文
|
||||
/// </summary>
|
||||
public class AppDbContext : DbContext
|
||||
public sealed class AppDbContext : DbContext
|
||||
{
|
||||
private readonly Guid contextId;
|
||||
private readonly ILogger<AppDbContext>? logger;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的应用程序数据库上下文
|
||||
/// </summary>
|
||||
@@ -21,6 +24,19 @@ public class AppDbContext : DbContext
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的应用程序数据库上下文
|
||||
/// </summary>
|
||||
/// <param name="options">选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public AppDbContext(DbContextOptions<AppDbContext> options, ILogger<AppDbContext> logger)
|
||||
: this(options)
|
||||
{
|
||||
contextId = Guid.NewGuid();
|
||||
this.logger = logger;
|
||||
logger.LogInformation("AppDbContext[{id}] created.", contextId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置
|
||||
/// </summary>
|
||||
@@ -66,6 +82,11 @@ public class AppDbContext : DbContext
|
||||
/// </summary>
|
||||
public DbSet<DailyNoteEntry> DailyNotes { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 对象缓存
|
||||
/// </summary>
|
||||
public DbSet<ObjectCacheEntry> ObjectCache { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个临时的应用程序数据库上下文
|
||||
/// </summary>
|
||||
@@ -76,6 +97,13 @@ public class AppDbContext : DbContext
|
||||
return new(new DbContextOptionsBuilder<AppDbContext>().UseSqlite(sqlConnectionString).Options);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
logger?.LogInformation("AppDbContext[{id}] disposed.", contextId);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
@@ -236,10 +237,11 @@ public class ImageCache : IImageCache
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (message.StatusCode == HttpStatusCode.TooManyRequests)
|
||||
{
|
||||
retryCount++;
|
||||
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? RetryCountToDelay[retryCount];
|
||||
logger.LogInformation("Retry after {delay}.", delay);
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
25
src/Snap.Hutao/Snap.Hutao/Extension/LoggerExtension.cs
Normal file
25
src/Snap.Hutao/Snap.Hutao/Extension/LoggerExtension.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Extension;
|
||||
|
||||
/// <summary>
|
||||
/// 日志器扩展
|
||||
/// </summary>
|
||||
[SuppressMessage("", "CA2254")]
|
||||
public static class LoggerExtension
|
||||
{
|
||||
/// <inheritdoc cref="LoggerExtensions.LogInformation(ILogger, string?, object?[])"/>
|
||||
public static T LogInformation<T>(this ILogger logger, string message, params object?[] param)
|
||||
{
|
||||
logger.LogInformation(message, param);
|
||||
return default!;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="LoggerExtensions.LogWarning(ILogger, string?, object?[])"/>
|
||||
public static T LogWarning<T>(this ILogger logger, string message, params object?[] param)
|
||||
{
|
||||
logger.LogWarning(message, param);
|
||||
return default!;
|
||||
}
|
||||
}
|
||||
@@ -46,4 +46,4 @@ public static class StringBuilderExtensions
|
||||
{
|
||||
return condition ? sb.Append(trueValue) : sb.Append(falseValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
311
src/Snap.Hutao/Snap.Hutao/Migrations/20221128115346_ObjectCache.Designer.cs
generated
Normal file
311
src/Snap.Hutao/Snap.Hutao/Migrations/20221128115346_ObjectCache.Designer.cs
generated
Normal file
@@ -0,0 +1,311 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Snap.Hutao.Context.Database;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Snap.Hutao.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20221128115346_ObjectCache")]
|
||||
partial class ObjectCache
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.0");
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ArchiveId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Current")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("Time")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ArchiveId");
|
||||
|
||||
b.ToTable("achievements");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("achievement_archives");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Info")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("avatar_infos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DailyNote")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("DailyTaskNotify")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("DailyTaskNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ExpeditionNotify")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ExpeditionNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("HomeCoinNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("HomeCoinNotifyThreshold")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ResinNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ResinNotifyThreshold")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ShowInHomeWidget")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("TransformerNotify")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("TransformerNotifySuppressed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("daily_notes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("gacha_archives");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ArchiveId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("GachaType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("QueryType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("Time")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.HasIndex("ArchiveId");
|
||||
|
||||
b.ToTable("gacha_items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AttachUid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("MihoyoSDK")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("game_accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("ExpireTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("object_cache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||
{
|
||||
b.Property<Guid>("InnerId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Aid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CookieToken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSelected")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Ltoken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Mid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Stoken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("InnerId");
|
||||
|
||||
b.ToTable("users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.AchievementArchive", "Archive")
|
||||
.WithMany()
|
||||
.HasForeignKey("ArchiveId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Archive");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||
{
|
||||
b.HasOne("Snap.Hutao.Model.Entity.GachaArchive", "Archive")
|
||||
.WithMany()
|
||||
.HasForeignKey("ArchiveId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Archive");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Snap.Hutao.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ObjectCache : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "object_cache",
|
||||
columns: table => new
|
||||
{
|
||||
Key = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ExpireTime = table.Column<DateTimeOffset>(type: "TEXT", nullable: false),
|
||||
Value = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_object_cache", x => x.Key);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "object_cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,22 @@ namespace Snap.Hutao.Migrations
|
||||
b.ToTable("game_accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset>("ExpireTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("object_cache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
|
||||
@@ -41,6 +41,14 @@ public class TypedWishSummary : WishBase
|
||||
/// </summary>
|
||||
public int LastOrangePull { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 据上个五星抽数格式化
|
||||
/// </summary>
|
||||
public string LastOrangePullFormatted
|
||||
{
|
||||
get => $"已垫 {LastOrangePull} 抽";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 五星保底阈值
|
||||
/// </summary>
|
||||
@@ -51,6 +59,14 @@ public class TypedWishSummary : WishBase
|
||||
/// </summary>
|
||||
public int LastPurplePull { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 据上个四星抽数格式化
|
||||
/// </summary>
|
||||
public string LastPurplePullFormatted
|
||||
{
|
||||
get => $"已垫 {LastPurplePull} 抽";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 四星保底阈值
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Hutao;
|
||||
@@ -9,18 +8,8 @@ namespace Snap.Hutao.Model.Binding.Hutao;
|
||||
/// <summary>
|
||||
/// 角色搭配
|
||||
/// </summary>
|
||||
public class ComplexAvatarCollocation : ComplexAvatar
|
||||
public class ComplexAvatarCollocation
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的角色搭配
|
||||
/// </summary>
|
||||
/// <param name="avatar">角色</param>
|
||||
/// <param name="rate">比率</param>
|
||||
public ComplexAvatarCollocation(Avatar avatar)
|
||||
: base(avatar, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Model.Binding.Hutao;
|
||||
|
||||
/// <summary>
|
||||
/// 武器搭配
|
||||
/// </summary>
|
||||
public class ComplexWeaponCollocation
|
||||
{
|
||||
/// <summary>
|
||||
/// 武器Id
|
||||
/// </summary>
|
||||
public WeaponId WeaponId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色
|
||||
/// </summary>
|
||||
public List<ComplexAvatar> Avatars { get; set; } = default!;
|
||||
}
|
||||
@@ -76,10 +76,7 @@ public class User : ObservableObject
|
||||
public Cookie? Stoken
|
||||
{
|
||||
get => inner.Stoken;
|
||||
set
|
||||
{
|
||||
inner.Stoken = value;
|
||||
}
|
||||
set => inner.Stoken = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,8 +93,14 @@ public class User : ObservableObject
|
||||
internal static async Task<User?> ResumeAsync(EntityUser inner, CancellationToken token = default)
|
||||
{
|
||||
User user = new(inner);
|
||||
bool successful = await user.InitializeCoreAsync(token).ConfigureAwait(false);
|
||||
return successful ? user : null;
|
||||
bool isOk = await user.InitializeCoreAsync(token).ConfigureAwait(false);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
user.UserInfo = new UserInfo() { Nickname = "网络异常" };
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
30
src/Snap.Hutao/Snap.Hutao/Model/Entity/ObjectCacheEntry.cs
Normal file
30
src/Snap.Hutao/Snap.Hutao/Model/Entity/ObjectCacheEntry.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Snap.Hutao.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库对象缓存
|
||||
/// </summary>
|
||||
[Table("object_cache")]
|
||||
public class ObjectCacheEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
[Key]
|
||||
public string Key { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间
|
||||
/// </summary>
|
||||
public DateTimeOffset ExpireTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 值字符串
|
||||
/// </summary>
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
@@ -92,4 +92,4 @@ public class SettingEntry
|
||||
/// 值
|
||||
/// </summary>
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -27,4 +27,4 @@ internal class EquipIconConverter : ValueConverterBase<string, Uri>
|
||||
{
|
||||
return IconNameToUri(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Control;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
|
||||
/// <summary>
|
||||
/// 武器祈愿图片转换器
|
||||
/// </summary>
|
||||
internal class GachaEquipIconConverter : ValueConverterBase<string, Uri>
|
||||
{
|
||||
private const string BaseUrl = "https://static.snapgenshin.com/GachaEquipIcon/UI_Gacha_{0}.png";
|
||||
|
||||
/// <summary>
|
||||
/// 名称转Uri
|
||||
/// </summary>
|
||||
/// <param name="name">名称</param>
|
||||
/// <returns>链接</returns>
|
||||
public static Uri IconNameToUri(string name)
|
||||
{
|
||||
name = name["UI_".Length..];
|
||||
return new Uri(string.Format(BaseUrl, name));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Uri Convert(string from)
|
||||
{
|
||||
return IconNameToUri(from);
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,5 @@ public class AffixInfo
|
||||
/// 各个等级的描述
|
||||
/// 0-4
|
||||
/// </summary>
|
||||
public List<LevelDescription<int>> Descriptions { get; set; } = default!;
|
||||
public List<LevelDescription> Descriptions { get; set; } = default!;
|
||||
}
|
||||
@@ -7,12 +7,18 @@ namespace Snap.Hutao.Model.Metadata.Weapon;
|
||||
/// 等级与描述
|
||||
/// </summary>
|
||||
/// <typeparam name="TLevel">等级的类型</typeparam>
|
||||
public class LevelDescription<TLevel>
|
||||
public class LevelDescription
|
||||
{
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
public TLevel Level { get; set; } = default!;
|
||||
public int Level { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 格式化的等级
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string LevelFormatted { get => $"精炼 {Level + 1} 阶"; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Snap.Hutao.Model.Binding.Gacha;
|
||||
using Snap.Hutao.Model.Binding.Gacha.Abstraction;
|
||||
using Snap.Hutao.Model.Binding.Hutao;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
@@ -60,6 +61,12 @@ public class Weapon : IStatisticsItemSource, ISummaryItemSource, INameQuality
|
||||
/// </summary>
|
||||
public AffixInfo? Affix { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// [非元数据] 搭配数据
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplexWeaponCollocation? Collocation { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[JsonIgnore]
|
||||
public ItemQuality Quality
|
||||
|
||||
@@ -21,7 +21,6 @@ internal class IdentityConverter<TWrapper> : JsonConverter<TWrapper>
|
||||
/// <inheritdoc/>
|
||||
public override void Write(Utf8JsonWriter writer, TWrapper value, JsonSerializerOptions options)
|
||||
{
|
||||
|
||||
writer.WriteNumberValue(CastTo<int>.From(value));
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.2.5.0" />
|
||||
Version="1.2.6.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 479 KiB |
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Model.Binding.Hutao;
|
||||
using Snap.Hutao.Model.Metadata;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
@@ -17,20 +18,24 @@ namespace Snap.Hutao.Service.Hutao;
|
||||
[Injection(InjectAs.Singleton, typeof(IHutaoCache))]
|
||||
internal class HutaoCache : IHutaoCache
|
||||
{
|
||||
private readonly IHutaoService hutaoService;
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IServiceScopeFactory scopeFactory;
|
||||
|
||||
private Dictionary<AvatarId, Avatar>? idAvatarExtendedMap;
|
||||
|
||||
private bool isDatabaseViewModelInitialized;
|
||||
private bool isWikiAvatarViewModelInitiaized;
|
||||
private bool isWikiWeaponViewModelInitiaized;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的胡桃 API 缓存
|
||||
/// </summary>
|
||||
/// <param name="hutaoService">胡桃服务</param>
|
||||
/// <param name="metadataService">元数据服务</param>
|
||||
public HutaoCache(IHutaoService hutaoService, IMetadataService metadataService)
|
||||
/// <param name="scopeFactory">范围工厂</param>
|
||||
public HutaoCache(IMetadataService metadataService, IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
this.hutaoService = hutaoService;
|
||||
this.metadataService = metadataService;
|
||||
this.scopeFactory = scopeFactory;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -51,9 +56,17 @@ internal class HutaoCache : IHutaoCache
|
||||
/// <inheritdoc/>
|
||||
public List<ComplexAvatarCollocation>? AvatarCollocations { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<ComplexWeaponCollocation>? WeaponCollocations { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> InitializeForDatabaseViewModelAsync()
|
||||
{
|
||||
if (isDatabaseViewModelInitialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
Dictionary<AvatarId, Avatar> idAvatarMap = await GetIdAvatarMapExtendedAsync().ConfigureAwait(false);
|
||||
@@ -72,6 +85,7 @@ internal class HutaoCache : IHutaoCache
|
||||
ovewviewTask)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
isDatabaseViewModelInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -81,25 +95,65 @@ internal class HutaoCache : IHutaoCache
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> InitializeForWikiAvatarViewModelAsync()
|
||||
{
|
||||
if (isWikiAvatarViewModelInitiaized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
Dictionary<AvatarId, Avatar> idAvatarMap = await GetIdAvatarMapExtendedAsync().ConfigureAwait(false);
|
||||
Dictionary<WeaponId, Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
|
||||
Dictionary<EquipAffixId, Model.Metadata.Reliquary.ReliquarySet> idReliquarySetMap = await metadataService.GetEquipAffixIdToReliquarySetMapAsync().ConfigureAwait(false);
|
||||
|
||||
// AvatarCollocation
|
||||
List<AvatarCollocation> avatarCollocationsRaw = await hutaoService.GetAvatarCollocationsAsync().ConfigureAwait(false);
|
||||
AvatarCollocations = avatarCollocationsRaw.Select(co =>
|
||||
List<AvatarCollocation> avatarCollocationsRaw;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
return new ComplexAvatarCollocation(idAvatarMap[co.AvatarId])
|
||||
{
|
||||
AvatarId = co.AvatarId,
|
||||
Avatars = co.Avatars.Select(a => new ComplexAvatar(idAvatarMap[a.Item], a.Rate)).ToList(),
|
||||
Weapons = co.Weapons.Select(w => new ComplexWeapon(idWeaponMap[w.Item], w.Rate)).ToList(),
|
||||
ReliquarySets = co.Reliquaries.Select(r => new ComplexReliquarySet(r, idReliquarySetMap)).ToList(),
|
||||
};
|
||||
IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoService>();
|
||||
avatarCollocationsRaw = await hutaoService.GetAvatarCollocationsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
AvatarCollocations = avatarCollocationsRaw.Select(co => new ComplexAvatarCollocation()
|
||||
{
|
||||
AvatarId = co.AvatarId,
|
||||
Avatars = co.Avatars.Select(a => new ComplexAvatar(idAvatarMap[a.Item], a.Rate)).ToList(),
|
||||
Weapons = co.Weapons.Select(w => new ComplexWeapon(idWeaponMap[w.Item], w.Rate)).ToList(),
|
||||
ReliquarySets = co.Reliquaries.Select(r => new ComplexReliquarySet(r, idReliquarySetMap)).ToList(),
|
||||
}).ToList();
|
||||
|
||||
isWikiAvatarViewModelInitiaized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> InitializeForWikiWeaponViewModelAsync()
|
||||
{
|
||||
if (isWikiWeaponViewModelInitiaized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
Dictionary<AvatarId, Avatar> idAvatarMap = await GetIdAvatarMapExtendedAsync().ConfigureAwait(false);
|
||||
|
||||
List<WeaponCollocation> weaponCollocationsRaw;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoService>();
|
||||
weaponCollocationsRaw = await hutaoService.GetWeaponCollocationsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
WeaponCollocations = weaponCollocationsRaw.Select(co => new ComplexWeaponCollocation()
|
||||
{
|
||||
WeaponId = co.WeaponId,
|
||||
Avatars = co.Avatars.Select(a => new ComplexAvatar(idAvatarMap[a.Item], a.Rate)).ToList(),
|
||||
}).ToList();
|
||||
|
||||
isWikiWeaponViewModelInitiaized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -123,7 +177,13 @@ internal class HutaoCache : IHutaoCache
|
||||
|
||||
private async Task AvatarAppearanceRankAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
|
||||
{
|
||||
List<AvatarAppearanceRank> avatarAppearanceRanksRaw = await hutaoService.GetAvatarAppearanceRanksAsync().ConfigureAwait(false);
|
||||
List<AvatarAppearanceRank> avatarAppearanceRanksRaw;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoService>();
|
||||
avatarAppearanceRanksRaw = await hutaoService.GetAvatarAppearanceRanksAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
AvatarAppearanceRanks = avatarAppearanceRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new ComplexAvatarRank
|
||||
{
|
||||
Floor = $"第 {rank.Floor} 层",
|
||||
@@ -133,7 +193,13 @@ internal class HutaoCache : IHutaoCache
|
||||
|
||||
private async Task AvatarUsageRanksAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
|
||||
{
|
||||
List<AvatarUsageRank> avatarUsageRanksRaw = await hutaoService.GetAvatarUsageRanksAsync().ConfigureAwait(false);
|
||||
List<AvatarUsageRank> avatarUsageRanksRaw;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoService>();
|
||||
avatarUsageRanksRaw = await hutaoService.GetAvatarUsageRanksAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
AvatarUsageRanks = avatarUsageRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new ComplexAvatarRank
|
||||
{
|
||||
Floor = $"第 {rank.Floor} 层",
|
||||
@@ -143,7 +209,13 @@ internal class HutaoCache : IHutaoCache
|
||||
|
||||
private async Task AvatarConstellationInfosAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
|
||||
{
|
||||
List<AvatarConstellationInfo> avatarConstellationInfosRaw = await hutaoService.GetAvatarConstellationInfosAsync().ConfigureAwait(false);
|
||||
List<AvatarConstellationInfo> avatarConstellationInfosRaw;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoService>();
|
||||
avatarConstellationInfosRaw = await hutaoService.GetAvatarConstellationInfosAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
AvatarConstellationInfos = avatarConstellationInfosRaw.OrderBy(i => i.HoldingRate).Select(info =>
|
||||
{
|
||||
return new ComplexAvatarConstellationInfo(idAvatarMap[info.AvatarId], info.HoldingRate, info.Constellations.Select(x => x.Rate));
|
||||
@@ -152,12 +224,22 @@ internal class HutaoCache : IHutaoCache
|
||||
|
||||
private async Task TeamAppearancesAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
|
||||
{
|
||||
List<TeamAppearance> teamAppearancesRaw = await hutaoService.GetTeamAppearancesAsync().ConfigureAwait(false);
|
||||
List<TeamAppearance> teamAppearancesRaw;
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoService>();
|
||||
teamAppearancesRaw = await hutaoService.GetTeamAppearancesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
TeamAppearances = teamAppearancesRaw.OrderByDescending(t => t.Floor).Select(team => new ComplexTeamRank(team, idAvatarMap)).ToList();
|
||||
}
|
||||
|
||||
private async Task OverviewAsync()
|
||||
{
|
||||
Overview = await hutaoService.GetOverviewAsync().ConfigureAwait(false);
|
||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||
{
|
||||
IHutaoService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoService>();
|
||||
Overview = await hutaoService.GetOverviewAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Snap.Hutao.Context.Database;
|
||||
using Snap.Hutao.Core.Database;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hutao;
|
||||
using Snap.Hutao.Web.Hutao.Model;
|
||||
|
||||
@@ -10,21 +13,27 @@ namespace Snap.Hutao.Service.Hutao;
|
||||
/// <summary>
|
||||
/// 胡桃 API 服务
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient, typeof(IHutaoService))]
|
||||
[Injection(InjectAs.Scoped, typeof(IHutaoService))]
|
||||
internal class HutaoService : IHutaoService
|
||||
{
|
||||
private readonly HomaClient homaClient;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly AppDbContext appDbContext;
|
||||
private readonly JsonSerializerOptions options;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的胡桃 API 服务
|
||||
/// </summary>
|
||||
/// <param name="homaClient">胡桃 API 客户端</param>
|
||||
/// <param name="memoryCache">内存缓存</param>
|
||||
public HutaoService(HomaClient homaClient, IMemoryCache memoryCache)
|
||||
/// <param name="appDbContext">数据库上下文</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
public HutaoService(HomaClient homaClient, IMemoryCache memoryCache, AppDbContext appDbContext, JsonSerializerOptions options)
|
||||
{
|
||||
this.homaClient = homaClient;
|
||||
this.memoryCache = memoryCache;
|
||||
this.appDbContext = appDbContext;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -57,6 +66,12 @@ internal class HutaoService : IHutaoService
|
||||
return FromCacheOrWebAsync(nameof(AvatarCollocation), homaClient.GetAvatarCollocationsAsync);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<List<WeaponCollocation>> GetWeaponCollocationsAsync()
|
||||
{
|
||||
return FromCacheOrWebAsync(nameof(WeaponCollocation), homaClient.GetWeaponCollocationsAsync);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<List<TeamAppearance>> GetTeamAppearancesAsync()
|
||||
{
|
||||
@@ -71,7 +86,27 @@ internal class HutaoService : IHutaoService
|
||||
return (T)cache!;
|
||||
}
|
||||
|
||||
if (appDbContext.ObjectCache.SingleOrDefault(e => e.Key == key) is ObjectCacheEntry entry)
|
||||
{
|
||||
if (entry.ExpireTime > DateTimeOffset.Now)
|
||||
{
|
||||
T value = JsonSerializer.Deserialize<T>(entry.Value!, options)!;
|
||||
return memoryCache.Set(key, value, TimeSpan.FromMinutes(30));
|
||||
}
|
||||
else
|
||||
{
|
||||
appDbContext.ObjectCache.RemoveAndSave(entry);
|
||||
}
|
||||
}
|
||||
|
||||
T web = await taskFunc(default).ConfigureAwait(false);
|
||||
appDbContext.ObjectCache.AddAndSave(new()
|
||||
{
|
||||
Key = key,
|
||||
ExpireTime = DateTimeOffset.Now.AddHours(4),
|
||||
Value = JsonSerializer.Serialize(web, options),
|
||||
});
|
||||
|
||||
return memoryCache.Set(key, web, TimeSpan.FromMinutes(30));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,15 +41,26 @@ internal interface IHutaoCache
|
||||
/// </summary>
|
||||
List<ComplexAvatarCollocation>? AvatarCollocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 武器搭配
|
||||
/// </summary>
|
||||
List<ComplexWeaponCollocation>? WeaponCollocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 为数据库视图模型初始化
|
||||
/// </summary>
|
||||
/// <returns>任务</returns>
|
||||
/// <returns>是否初始化完成</returns>
|
||||
ValueTask<bool> InitializeForDatabaseViewModelAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 为Wiki角色视图模型初始化
|
||||
/// </summary>
|
||||
/// <returns>任务</returns>
|
||||
/// <returns>是否初始化完成</returns>
|
||||
ValueTask<bool> InitializeForWikiAvatarViewModelAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 为Wiki武器视图模型初始化
|
||||
/// </summary>
|
||||
/// <returns>是否初始化完成</returns>
|
||||
ValueTask<bool> InitializeForWikiWeaponViewModelAsync();
|
||||
}
|
||||
@@ -45,4 +45,10 @@ internal interface IHutaoService
|
||||
/// </summary>
|
||||
/// <returns>队伍上场</returns>
|
||||
ValueTask<List<TeamAppearance>> GetTeamAppearancesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取武器搭配
|
||||
/// </summary>
|
||||
/// <returns>武器搭配</returns>
|
||||
ValueTask<List<WeaponCollocation>> GetWeaponCollocationsAsync();
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.Xaml.Interactivity;
|
||||
using Snap.Hutao.Control.Behavior;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Service;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<None Remove="Resource\Icon\UI_BtnIcon_ActivityEntry.png" />
|
||||
<None Remove="Resource\Icon\UI_BtnIcon_Gacha.png" />
|
||||
<None Remove="Resource\Icon\UI_ChapterIcon_Hutao.png" />
|
||||
<None Remove="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
||||
<None Remove="Resource\Icon\UI_GuideIcon_PlayMethod.png" />
|
||||
<None Remove="Resource\Icon\UI_Icon_Achievement.png" />
|
||||
<None Remove="Resource\Icon\UI_Icon_BoostUp.png" />
|
||||
@@ -66,6 +67,7 @@
|
||||
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
|
||||
<None Remove="View\Dialog\AvatarInfoQueryDialog.xaml" />
|
||||
<None Remove="View\Dialog\DailyNoteNotificationDialog.xaml" />
|
||||
<None Remove="View\Dialog\DailyNoteVerificationDialog.xaml" />
|
||||
<None Remove="View\Dialog\GachaLogImportDialog.xaml" />
|
||||
<None Remove="View\Dialog\GachaLogRefreshProgressDialog.xaml" />
|
||||
<None Remove="View\Dialog\GachaLogUrlDialog.xaml" />
|
||||
@@ -86,6 +88,7 @@
|
||||
<None Remove="View\Page\LoginMihoyoUserPage.xaml" />
|
||||
<None Remove="View\Page\SettingPage.xaml" />
|
||||
<None Remove="View\Page\WikiAvatarPage.xaml" />
|
||||
<None Remove="View\Page\WikiWeaponPage.xaml" />
|
||||
<None Remove="View\TitleView.xaml" />
|
||||
<None Remove="View\UserView.xaml" />
|
||||
</ItemGroup>
|
||||
@@ -110,6 +113,7 @@
|
||||
<Content Include="Resource\Icon\UI_BtnIcon_ActivityEntry.png" />
|
||||
<Content Include="Resource\Icon\UI_BtnIcon_Gacha.png" />
|
||||
<Content Include="Resource\Icon\UI_ChapterIcon_Hutao.png" />
|
||||
<Content Include="Resource\Icon\UI_GachaShowPanel_Bg_Weapon.png" />
|
||||
<Content Include="Resource\Icon\UI_GuideIcon_PlayMethod.png" />
|
||||
<Content Include="Resource\Icon\UI_Icon_Achievement.png" />
|
||||
<Content Include="Resource\Icon\UI_Icon_BoostUp.png" />
|
||||
@@ -170,6 +174,16 @@
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Page\WikiWeaponPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\DailyNoteVerificationDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\SignInWebViewDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
||||
Background="{StaticResource CardBackgroundFillColorDefault}">
|
||||
<StackPanel>
|
||||
<StackPanel Name="BackgroundStack">
|
||||
<ContentPresenter
|
||||
Name="ContentHost"/>
|
||||
<TextBlock
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Snap.Hutao.Control;
|
||||
|
||||
namespace Snap.Hutao.View.Control;
|
||||
@@ -15,7 +16,8 @@ namespace Snap.Hutao.View.Control;
|
||||
public sealed partial class BottomTextControl : ContentControl
|
||||
{
|
||||
private static readonly DependencyProperty TextProperty = Property<BottomTextControl>.Depend(nameof(Text), string.Empty, OnTextChanged);
|
||||
private static readonly DependencyProperty TopContentProperty = Property<BottomTextControl>.Depend<UIElement>(nameof(TopContent), default!, OnContentChanged2);
|
||||
private static readonly DependencyProperty TopContentProperty = Property<BottomTextControl>.Depend<UIElement>(nameof(TopContent), default!, OnContentChanged);
|
||||
private static readonly DependencyProperty FillProperty = Property<BottomTextControl>.Depend(nameof(Fill), default(Brush), OnFillChanged);
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的底部带有文本的控件
|
||||
@@ -43,13 +45,27 @@ public sealed partial class BottomTextControl : ContentControl
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
private static void OnTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs dp)
|
||||
/// <summary>
|
||||
/// 填充
|
||||
/// </summary>
|
||||
public Brush Fill
|
||||
{
|
||||
((BottomTextControl)sender).TextHost.Text = (string)dp.NewValue;
|
||||
get => (Brush)GetValue(FillProperty);
|
||||
set => SetValue(FillProperty, value);
|
||||
}
|
||||
|
||||
private static void OnContentChanged2(DependencyObject sender, DependencyPropertyChangedEventArgs dp)
|
||||
private static void OnTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
((BottomTextControl)sender).ContentHost.Content = dp.NewValue;
|
||||
((BottomTextControl)sender).TextHost.Text = (string)args.NewValue;
|
||||
}
|
||||
|
||||
private static void OnContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
((BottomTextControl)sender).ContentHost.Content = args.NewValue;
|
||||
}
|
||||
|
||||
private static void OnFillChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
((BottomTextControl)sender).BackgroundStack.Background = (Brush)args.NewValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||
xmlns:shcp="using:Snap.Hutao.Control.Panel"
|
||||
xmlns:shmbg="using:Snap.Hutao.Model.Binding.Gacha"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Converter"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance shmbg:TypedWishSummary}">
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
<SolidColorBrush x:Key="PurpleBrush" Color="#FFA156E0"/>
|
||||
<SolidColorBrush x:Key="OrangeBrush" Color="#FFBC6932"/>
|
||||
|
||||
<cwuconv:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
<shvc:BoolToVisibilityRevertConverter x:Key="BoolToVisibilityRevertConverter"/>
|
||||
<DataTemplate x:Key="OrangeListTemplate" x:DataType="shmbg:SummaryItem">
|
||||
<Grid Margin="0,4,4,0" Background="Transparent" >
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -67,47 +65,31 @@
|
||||
|
||||
<DataTemplate x:Key="OrangeGridTemplate" x:DataType="shmbg:SummaryItem">
|
||||
<Grid Width="40" Margin="0,4,4,0">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock Text="{Binding TimeFormatted}"/>
|
||||
</ToolTipService.ToolTip>
|
||||
<StackPanel>
|
||||
<shci:CachedImage
|
||||
<Border
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
||||
Background="{StaticResource CardBackgroundFillColorDefault}"
|
||||
ToolTipService.ToolTip="{Binding TimeFormatted}">
|
||||
<StackPanel>
|
||||
<shvc:ItemIcon
|
||||
Icon="{Binding Icon}"
|
||||
Quality="QUALITY_ORANGE"
|
||||
Height="40" Width="40"/>
|
||||
<!--<shci:CachedImage
|
||||
Source="{Binding Icon}"
|
||||
Height="40" Width="40"/>
|
||||
<TextBlock
|
||||
Text="{Binding LastPull}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
HorizontalAlignment="Center"
|
||||
TextWrapping="NoWrap">
|
||||
<TextBlock.Foreground>
|
||||
<SolidColorBrush Color="{Binding Color}"/>
|
||||
</TextBlock.Foreground>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!--<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="0,0,8,0"
|
||||
Foreground="#FF0063FF"
|
||||
Text="保底"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{Binding IsGuarentee,Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
<TextBlock
|
||||
Margin="0,0,8,0"
|
||||
Text="UP"
|
||||
Foreground="#FFFFA400"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{Binding IsUp,Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
|
||||
<TextBlock
|
||||
Width="20"
|
||||
TextAlignment="Center"
|
||||
Text="{Binding LastPull}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource BodyTextBlockStyle}"/>
|
||||
</StackPanel>-->
|
||||
Height="40" Width="40"/>-->
|
||||
<TextBlock
|
||||
Text="{Binding LastPull}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
HorizontalAlignment="Center"
|
||||
TextWrapping="NoWrap">
|
||||
<TextBlock.Foreground>
|
||||
<SolidColorBrush Color="{Binding Color}"/>
|
||||
</TextBlock.Foreground>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -157,61 +139,110 @@
|
||||
<TextBlock Margin="12,0,0,12" Text="抽" VerticalAlignment="Bottom"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid ColumnSpacing="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressBar
|
||||
<Border
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
Value="{Binding LastOrangePull}"
|
||||
Maximum="{Binding GuarenteeOrangeThreshold}"
|
||||
Foreground="{StaticResource OrangeBrush}"/>
|
||||
<TextBlock
|
||||
Width="20"
|
||||
TextAlignment="Center"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
||||
Background="{StaticResource CardBackgroundFillColorDefault}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Margin="4"
|
||||
Height="40"
|
||||
Width="40"
|
||||
Grid.Column="0"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuarenteeOrangeThreshold}"
|
||||
Value="{Binding LastOrangePull}"
|
||||
Foreground="{StaticResource OrangeBrush}"
|
||||
Background="{StaticResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
<TextBlock
|
||||
Margin="0,0,0,2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{Binding LastOrangePull}"
|
||||
Foreground="{StaticResource OrangeBrush}"/>
|
||||
<TextBlock
|
||||
Margin="0,0,0,2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="五星"
|
||||
Foreground="{StaticResource OrangeBrush}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastOrangePull}"
|
||||
Foreground="{StaticResource OrangeBrush}"/>
|
||||
<ProgressBar
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Value="{Binding LastPurplePull}"
|
||||
Maximum="{Binding GuarenteePurpleThreshold}"
|
||||
Foreground="{StaticResource PurpleBrush}"/>
|
||||
<TextBlock
|
||||
Width="20"
|
||||
TextAlignment="Center"
|
||||
Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding LastPurplePull}"
|
||||
Foreground="{StaticResource PurpleBrush}"/>
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
||||
Background="{StaticResource CardBackgroundFillColorDefault}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressRing
|
||||
Margin="4"
|
||||
Height="40"
|
||||
Width="40"
|
||||
Grid.Column="0"
|
||||
IsIndeterminate="False"
|
||||
Maximum="{Binding GuarenteePurpleThreshold}"
|
||||
Value="{Binding LastPurplePull}"
|
||||
Foreground="{StaticResource PurpleBrush}"
|
||||
Background="{StaticResource CardBackgroundFillColorDefaultBrush}"/>
|
||||
<TextBlock
|
||||
Margin="0,0,0,2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{Binding LastPurplePull}"
|
||||
Foreground="{StaticResource PurpleBrush}"/>
|
||||
<TextBlock
|
||||
Margin="0,0,0,2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="四星"
|
||||
Foreground="{StaticResource PurpleBrush}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<TextBlock
|
||||
Opacity="0.6"
|
||||
FontFamily="Consolas"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding FromFormatted}"/>
|
||||
<TextBlock
|
||||
Opacity="0.6"
|
||||
FontFamily="Consolas"
|
||||
Text="-"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource BodyTextBlockStyle}"/>
|
||||
Style="{StaticResource CaptionTextBlockStyle}"/>
|
||||
<TextBlock
|
||||
Opacity="0.6"
|
||||
FontFamily="Consolas"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding ToFormatted}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.DailyNoteVerificationDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Closed="OnContentDialogClosed"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
Title="米游社实时便笺"
|
||||
PrimaryButtonText="完成"
|
||||
DefaultButton="Primary">
|
||||
|
||||
<Grid Loaded="OnGridLoaded">
|
||||
<WebView2 Name="WebView" Height="448" Width="380"/>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Bridge;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// ʵʱ<CAB5><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
public sealed partial class DailyNoteVerificationDialog : ContentDialog
|
||||
{
|
||||
private readonly IServiceScope scope;
|
||||
private readonly User user;
|
||||
private readonly PlayerUid uid;
|
||||
[SuppressMessage("", "IDE0052")]
|
||||
private DailyNoteJsInterface? dailyNoteJsInterface;
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD>ʵʱ<CAB5><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD>Ի<EFBFBD><D4BB><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="window"><3E><><EFBFBD><EFBFBD></param>
|
||||
/// <param name="user"><3E>û<EFBFBD></param>
|
||||
/// <param name="uid">uid</param>
|
||||
public DailyNoteVerificationDialog(Window window, User user, PlayerUid uid)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
this.user = user;
|
||||
this.uid = uid;
|
||||
scope = Ioc.Default.CreateScope();
|
||||
}
|
||||
|
||||
private void OnGridLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
InitializeAsync().SafeForget();
|
||||
}
|
||||
|
||||
private async Task InitializeAsync()
|
||||
{
|
||||
await WebView.EnsureCoreWebView2Async();
|
||||
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
|
||||
|
||||
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
||||
dailyNoteJsInterface = new(coreWebView2, scope.ServiceProvider);
|
||||
|
||||
#if DEBUG
|
||||
coreWebView2.OpenDevToolsWindow();
|
||||
#endif
|
||||
string query = $"?role_id={uid.Value}&server={uid.Region}";
|
||||
coreWebView2.Navigate($"https://webstatic.mihoyo.com/app/community-game-records/index.html?bbs_presentation_style=fullscreen#/ys/daily/{query}");
|
||||
}
|
||||
|
||||
private void OnContentDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args)
|
||||
{
|
||||
dailyNoteJsInterface = null;
|
||||
scope.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,10 @@
|
||||
shvh:NavHelper.NavigateTo="shvp:WikiAvatarPage"
|
||||
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_BagTabIcon_Avatar.png}"/>
|
||||
|
||||
<NavigationViewItem
|
||||
Content="武器资料"
|
||||
shvh:NavHelper.NavigateTo="shvp:WikiWeaponPage"
|
||||
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_BagTabIcon_Weapon.png}"/>
|
||||
</NavigationView.MenuItems>
|
||||
|
||||
<NavigationView.PaneFooter>
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
Text="对当前选中的账号进行签到"/>
|
||||
<TextBlock
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Foreground="Yellow"
|
||||
Foreground="{StaticResource SystemFillColorCautionBrush}"
|
||||
Text="可能需要重启应用以对其他账号签到"/>
|
||||
</StackPanel>
|
||||
</sc:Setting.Description>
|
||||
@@ -199,12 +199,12 @@
|
||||
</sc:Setting>
|
||||
</sc:SettingsGroup>
|
||||
|
||||
<sc:SettingsGroup Header="危险功能" Foreground="#FF800000">
|
||||
<sc:SettingsGroup Header="危险功能" Foreground="{StaticResource SystemFillColorCriticalBrush}">
|
||||
<sc:Setting
|
||||
Icon=""
|
||||
Header="删除所有用户"
|
||||
Description="直接删除用户表的所有记录,用于修复特定的账号冲突问题"
|
||||
Background="#80800000">
|
||||
Background="{StaticResource SystemFillColorCriticalBackgroundBrush}">
|
||||
<sc:Setting.ActionContent>
|
||||
<Button
|
||||
Content="执行"
|
||||
|
||||
285
src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml
Normal file
285
src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml
Normal file
@@ -0,0 +1,285 @@
|
||||
<shc:ScopedPage
|
||||
x:Class="Snap.Hutao.View.Page.WikiWeaponPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:shc="using:Snap.Hutao.Control"
|
||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||
xmlns:shcp="using:Snap.Hutao.Control.Panel"
|
||||
xmlns:shct="using:Snap.Hutao.Control.Text"
|
||||
xmlns:shv="using:Snap.Hutao.ViewModel"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance Type=shv:WikiWeaponViewModel}"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="PropertyDataTemplate">
|
||||
<shvc:DescParamComboBox
|
||||
HorizontalAlignment="Stretch"
|
||||
Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
|
||||
<SplitView
|
||||
IsPaneOpen="True"
|
||||
DisplayMode="Inline"
|
||||
OpenPaneLength="200"
|
||||
PaneBackground="{StaticResource CardBackgroundFillColorSecondary}">
|
||||
<SplitView.Pane>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<CommandBar DefaultLabelPosition="Right">
|
||||
<CommandBar.Content>
|
||||
<shcp:PanelSelector Margin="6,8,0,0" x:Name="ItemsPanelSelector"/>
|
||||
</CommandBar.Content>
|
||||
|
||||
<!--<AppBarButton Label="筛选" Icon="{shcm:FontIcon Glyph=}">
|
||||
<AppBarButton.Flyout>
|
||||
<Flyout Placement="RightEdgeAlignedTop" LightDismissOverlayMode="On">
|
||||
<cwuc:UniformGrid Columns="3" RowSpacing="16">
|
||||
<cwuc:HeaderedItemsControl
|
||||
Header="元素"
|
||||
Padding="0,12,0,0"
|
||||
ItemsSource="{Binding FilterElementInfos}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Value}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</cwuc:HeaderedItemsControl>
|
||||
|
||||
<cwuc:HeaderedItemsControl
|
||||
Header="所属"
|
||||
Padding="0,12,0,0"
|
||||
ItemsSource="{Binding FilterAssociationInfos}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Value.Key}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</cwuc:HeaderedItemsControl>
|
||||
|
||||
<cwuc:HeaderedItemsControl
|
||||
Header="武器"
|
||||
Padding="0,12,0,0"
|
||||
ItemsSource="{Binding FilterWeaponTypeInfos}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Value.Key}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</cwuc:HeaderedItemsControl>
|
||||
|
||||
<cwuc:HeaderedItemsControl
|
||||
Header="星级"
|
||||
Padding="0,12,0,0"
|
||||
ItemsSource="{Binding FilterQualityInfos}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Value.Key}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</cwuc:HeaderedItemsControl>
|
||||
|
||||
<cwuc:HeaderedItemsControl
|
||||
Header="体型"
|
||||
Padding="0,12,0,0"
|
||||
ItemsSource="{Binding FilterBodyInfos}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Value.Key}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</cwuc:HeaderedItemsControl>
|
||||
</cwuc:UniformGrid>
|
||||
</Flyout>
|
||||
</AppBarButton.Flyout>
|
||||
</AppBarButton>-->
|
||||
</CommandBar>
|
||||
<cwuc:SwitchPresenter Grid.Row="1" Value="{Binding ElementName=ItemsPanelSelector,Path=Current}">
|
||||
<cwuc:Case Value="List">
|
||||
<ListView
|
||||
Grid.Row="1"
|
||||
SelectionMode="Single"
|
||||
ItemsSource="{Binding Weapons}"
|
||||
SelectedItem="{Binding Selected,Mode=TwoWay}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shci:CachedImage
|
||||
Grid.Column="0"
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="0,0,12,6"
|
||||
Source="{Binding Icon,Converter={StaticResource EquipIconConverter},Mode=OneWay}"/>
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="1"
|
||||
Margin="12,0,0,0"
|
||||
Text="{Binding Name}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</cwuc:Case>
|
||||
<cwuc:Case Value="Grid">
|
||||
<GridView
|
||||
HorizontalAlignment="Left"
|
||||
HorizontalContentAlignment="Left"
|
||||
Margin="6,6,0,0"
|
||||
SelectionMode="Single"
|
||||
ItemsSource="{Binding Weapons}"
|
||||
SelectedItem="{Binding Selected,Mode=TwoWay}">
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<shci:CachedImage
|
||||
Grid.Column="0"
|
||||
Width="40"
|
||||
Height="40"
|
||||
Margin="0"
|
||||
Source="{Binding Icon,Converter={StaticResource EquipIconConverter},Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
</GridView.ItemTemplate>
|
||||
</GridView>
|
||||
</cwuc:Case>
|
||||
</cwuc:SwitchPresenter>
|
||||
</Grid>
|
||||
</SplitView.Pane>
|
||||
<SplitView.Content>
|
||||
<ScrollViewer>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition MaxWidth="800"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Margin="0,0,20,0">
|
||||
<Border
|
||||
Margin="16,16,0,0"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}">
|
||||
<Border.Background>
|
||||
<ImageBrush ImageSource="ms-appx:///Resource/Icon/UI_GachaShowPanel_Bg_Weapon.png"/>
|
||||
</Border.Background>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<mxi:Interaction.Behaviors>
|
||||
<shcb:AutoHeightBehavior TargetWidth="2048" TargetHeight="1024"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
<ScrollViewer
|
||||
Margin="16"
|
||||
Grid.Column="0">
|
||||
<StackPanel>
|
||||
<shvc:BottomTextControl
|
||||
RequestedTheme="Light"
|
||||
Text="突破前">
|
||||
<shvc:ItemIcon
|
||||
Icon="{Binding Selected.Icon,Converter={StaticResource EquipIconConverter}}"
|
||||
Quality="{Binding Selected.RankLevel}"/>
|
||||
</shvc:BottomTextControl>
|
||||
|
||||
<shvc:BottomTextControl
|
||||
RequestedTheme="Light"
|
||||
Text="突破后"
|
||||
Margin="0,16,0,0">
|
||||
<shvc:ItemIcon
|
||||
Icon="{Binding Selected.AwakenIcon,Converter={StaticResource EquipIconConverter}}"
|
||||
Quality="{Binding Selected.RankLevel}"/>
|
||||
</shvc:BottomTextControl>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="176*"/>
|
||||
<ColumnDefinition Width="848*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shci:CachedImage
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Stretch"
|
||||
Source="{Binding Selected.Icon,Converter={StaticResource GachaEquipIconConverter}}"/>
|
||||
</Grid>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Margin="16"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{Binding Selected.Name}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<TextBlock
|
||||
Margin="16,16,0,0"
|
||||
TextWrapping="Wrap"
|
||||
Text="{Binding Selected.Description}"/>
|
||||
<ContentControl
|
||||
Margin="16,16,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Content="{Binding Selected.Property,Mode=OneWay}"
|
||||
ContentTemplate="{StaticResource PropertyDataTemplate}"/>
|
||||
<TextBlock Text="{Binding Selected.Affix.Name}" Style="{StaticResource BaseTextBlockStyle}" Margin="16,32,0,0"/>
|
||||
<Pivot ItemsSource="{Binding Selected.Affix.Descriptions}">
|
||||
<Pivot.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding LevelFormatted}" Style="{StaticResource CaptionTextBlockStyle}"/>
|
||||
</DataTemplate>
|
||||
</Pivot.HeaderTemplate>
|
||||
<Pivot.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<shct:DescriptionTextBlock
|
||||
Margin="16,16,0,0"
|
||||
Description="{Binding Description}">
|
||||
<shct:DescriptionTextBlock.Resources>
|
||||
<Style TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}">
|
||||
<Setter Property="TextWrapping" Value="Wrap"/>
|
||||
</Style>
|
||||
</shct:DescriptionTextBlock.Resources>
|
||||
</shct:DescriptionTextBlock>
|
||||
</DataTemplate>
|
||||
</Pivot.ItemTemplate>
|
||||
</Pivot>
|
||||
<TextBlock Text="搭配角色" Style="{StaticResource BaseTextBlockStyle}" Margin="16,32,0,0"/>
|
||||
<GridView
|
||||
Margin="16,16,0,0"
|
||||
SelectionMode="None"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ItemsSource="{Binding Selected.Collocation.Avatars}">
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<shvc:BottomTextControl
|
||||
ToolTipService.ToolTip="{Binding Name}"
|
||||
Text="{Binding Rate}">
|
||||
<shvc:ItemIcon
|
||||
Icon="{Binding Icon}"
|
||||
Quality="{Binding Quality}"/>
|
||||
</shvc:BottomTextControl>
|
||||
</DataTemplate>
|
||||
</GridView.ItemTemplate>
|
||||
</GridView>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</SplitView.Content>
|
||||
</SplitView>
|
||||
</shc:ScopedPage>
|
||||
22
src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml.cs
Normal file
22
src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.ViewModel;
|
||||
|
||||
namespace Snap.Hutao.View.Page;
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>
|
||||
/// </summary>
|
||||
public sealed partial class WikiWeaponPage : ScopedPage
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>
|
||||
/// </summary>
|
||||
public WikiWeaponPage()
|
||||
{
|
||||
InitializeWith<WikiWeaponViewModel>();
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
94
src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs
Normal file
94
src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI.UI;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model.Binding.Hutao;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.Service.Hutao;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// 武器资料视图模型
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal class WikiWeaponViewModel : ObservableObject, ISupportCancellation
|
||||
{
|
||||
private readonly List<WeaponId> skippedWeapons = new()
|
||||
{
|
||||
11419, 11420, 11421, // 「一心传」名刀
|
||||
12304, 14306, 15306, 13304, // 石英大剑, 琥珀玥, 黑檀弓, 「旗杆」
|
||||
};
|
||||
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IHutaoCache hutaoCache;
|
||||
|
||||
private AdvancedCollectionView? weapons;
|
||||
private Weapon? selected;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的武器资料视图模型
|
||||
/// </summary>
|
||||
/// <param name="metadataService">元数据服务</param>
|
||||
/// <param name="hutaoCache">胡桃缓存</param>
|
||||
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||
public WikiWeaponViewModel(IMetadataService metadataService, IHutaoCache hutaoCache, IAsyncRelayCommandFactory asyncRelayCommandFactory)
|
||||
{
|
||||
this.metadataService = metadataService;
|
||||
this.hutaoCache = hutaoCache;
|
||||
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CancellationToken CancellationToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色列表
|
||||
/// </summary>
|
||||
public AdvancedCollectionView? Weapons { get => weapons; set => SetProperty(ref weapons, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 选中的角色
|
||||
/// </summary>
|
||||
public Weapon? Selected { get => selected; set => SetProperty(ref selected, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 打开界面命令
|
||||
/// </summary>
|
||||
public ICommand OpenUICommand { get; }
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
List<Weapon> weapons = await metadataService.GetWeaponsAsync().ConfigureAwait(false);
|
||||
List<Weapon> sorted = weapons
|
||||
.Where(weapon => !skippedWeapons.Contains(weapon.Id))
|
||||
.OrderByDescending(weapon => weapon.RankLevel)
|
||||
.ThenBy(weapon => weapon.WeaponType)
|
||||
.ToList();
|
||||
|
||||
await CombineWithWeaponCollocationsAsync(sorted).ConfigureAwait(false);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
|
||||
Weapons = new AdvancedCollectionView(sorted, true);
|
||||
Selected = Weapons.Cast<Weapon>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CombineWithWeaponCollocationsAsync(List<Weapon> weapons)
|
||||
{
|
||||
if (await hutaoCache.InitializeForWikiWeaponViewModelAsync().ConfigureAwait(false))
|
||||
{
|
||||
Dictionary<WeaponId, ComplexWeaponCollocation> idCollocations = hutaoCache.WeaponCollocations!.ToDictionary(a => a.WeaponId);
|
||||
weapons.ForEach(w => w.Collocation = idCollocations.GetValueOrDefault(w.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using Snap.Hutao.Web.Hoyolab;
|
||||
namespace Snap.Hutao.Web;
|
||||
|
||||
/// <summary>
|
||||
/// 米哈游Url端点
|
||||
/// API端点
|
||||
/// </summary>
|
||||
[SuppressMessage("", "SA1201")]
|
||||
[SuppressMessage("", "SA1124")]
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using WinRT;
|
||||
|
||||
namespace Snap.Hutao.Web.Bridge;
|
||||
|
||||
|
||||
22
src/Snap.Hutao/Snap.Hutao/Web/Bridge/DailyNoteJsInterface.cs
Normal file
22
src/Snap.Hutao/Snap.Hutao/Web/Bridge/DailyNoteJsInterface.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
|
||||
namespace Snap.Hutao.Web.Bridge;
|
||||
|
||||
/// <summary>
|
||||
/// 实时便笺页面调用桥
|
||||
/// </summary>
|
||||
public class DailyNoteJsInterface : MiHoYoJSInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的实时便笺页面调用桥
|
||||
/// </summary>
|
||||
/// <param name="webView">webview</param>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
public DailyNoteJsInterface(CoreWebView2 webView, IServiceProvider serviceProvider)
|
||||
: base(webView, serviceProvider)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,15 @@ public class MiHoYoJSInterface
|
||||
[JsMethod("getHTTPRequestHeaders")]
|
||||
public virtual JsResult<Dictionary<string, string>> GetHttpRequestHeader(JsParam param)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return new()
|
||||
{
|
||||
Data = new Dictionary<string, string>()
|
||||
{
|
||||
{ "x-rpc-client_type", "5" },
|
||||
{ "x-rpc-device_id", Core.CoreEnvironment.HoyolabDeviceId },
|
||||
{ "x-rpc-app_version", Core.CoreEnvironment.HoyolabXrpcVersion },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -138,6 +146,30 @@ public class MiHoYoJSInterface
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取2代动态密钥
|
||||
/// </summary>
|
||||
/// <param name="param">参数</param>
|
||||
/// <returns>响应</returns>
|
||||
[JsMethod("getDS2")]
|
||||
public virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV2(JsParam<DynamicSecrect2Playload> param)
|
||||
{
|
||||
string salt = DynamicSecretHandler.DynamicSecrets[nameof(SaltType.X4)];
|
||||
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
int r = GetRandom();
|
||||
string b = param.Payload.Body;
|
||||
string q = string.Join('&', param.Payload.Query.OrderBy(x => x.Key).Select(x => $"{x.Key}={x.Value}"));
|
||||
string check = Md5Convert.ToHexString($"salt={salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant();
|
||||
|
||||
return new() { Data = new() { ["DS"] = $"{t},{r},{check}", }, };
|
||||
|
||||
static int GetRandom()
|
||||
{
|
||||
int rand = Random.Shared.Next(100000, 200000);
|
||||
return rand == 100000 ? 642367 : rand;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户基本信息
|
||||
/// </summary>
|
||||
@@ -162,6 +194,11 @@ public class MiHoYoJSInterface
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取CookieToken
|
||||
/// </summary>
|
||||
/// <param name="param">参数</param>
|
||||
/// <returns>响应</returns>
|
||||
[JsMethod("getCookieToken")]
|
||||
public virtual async Task<JsResult<Dictionary<string, string>>> GetCookieTokenAsync(JsParam<CookieTokenPayload> param)
|
||||
{
|
||||
@@ -185,10 +222,26 @@ public class MiHoYoJSInterface
|
||||
return new() { Data = new() { [Cookie.COOKIE_TOKEN] = cookieToken! } };
|
||||
}
|
||||
|
||||
[JsMethod("configure_share")]
|
||||
public virtual Task<IJsResult?> ConfigureShare(JsParam param)
|
||||
/// <summary>
|
||||
/// 关闭
|
||||
/// </summary>
|
||||
/// <param name="param">参数</param>
|
||||
/// <returns>响应</returns>
|
||||
[JsMethod("closePage")]
|
||||
public virtual IJsResult? ClosePage(JsParam param)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调整分享设置
|
||||
/// </summary>
|
||||
/// <param name="param">参数</param>
|
||||
/// <returns>响应</returns>
|
||||
[JsMethod("configure_share")]
|
||||
public virtual IJsResult? ConfigureShare(JsParam param)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
[JsMethod("showAlertDialog")]
|
||||
@@ -197,12 +250,6 @@ public class MiHoYoJSInterface
|
||||
return Task.FromException<IJsResult?>(new NotImplementedException());
|
||||
}
|
||||
|
||||
[JsMethod("closePage")]
|
||||
public virtual IJsResult? ClosePage(JsParam param)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[JsMethod("startRealPersonValidation")]
|
||||
public virtual IJsResult? StartRealPersonValidation(JsParam param)
|
||||
{
|
||||
@@ -215,12 +262,6 @@ public class MiHoYoJSInterface
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[JsMethod("getDS2")]
|
||||
public virtual IJsResult? GetDynamicSecrectV2(JsParam param)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[JsMethod("genAuthKey")]
|
||||
public virtual IJsResult? GenAuthKey(JsParam param)
|
||||
{
|
||||
@@ -264,7 +305,7 @@ public class MiHoYoJSInterface
|
||||
}
|
||||
|
||||
[JsMethod("showToast")]
|
||||
public virtual Task<IJsResult?> ShowToast(JsParam param)
|
||||
public virtual IJsResult? ShowToast(JsParam param)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -287,7 +328,7 @@ public class MiHoYoJSInterface
|
||||
.Append(')')
|
||||
.ToString();
|
||||
|
||||
logger?.LogInformation("[ExecuteScript] {js}", js);
|
||||
logger?.LogInformation("[ExecuteScript: {callback}]\n{payload}", callback, payload);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
return await webView.ExecuteScriptAsync(js);
|
||||
@@ -297,24 +338,27 @@ public class MiHoYoJSInterface
|
||||
private async void OnWebMessageReceived(CoreWebView2 webView2, CoreWebView2WebMessageReceivedEventArgs args)
|
||||
{
|
||||
string message = args.TryGetWebMessageAsString();
|
||||
logger?.LogInformation("[OnMessage] {message}", message);
|
||||
|
||||
JsParam param = JsonSerializer.Deserialize<JsParam>(message)!;
|
||||
|
||||
logger.LogInformation("[OnMessage]\nMethod : {method}\nPayload : {payload}\nCallback: {callback}", param.Method, param.Payload, param.Callback);
|
||||
IJsResult? result = param.Method switch
|
||||
{
|
||||
"closePage" => ClosePage(param),
|
||||
"configure_share" => ConfigureShare(param),
|
||||
"eventTrack" => null,
|
||||
"getActionTicket" => await GetActionTicketAsync(param).ConfigureAwait(false),
|
||||
"getHTTPRequestHeaders" => GetHttpRequestHeader(param),
|
||||
"getCookieInfo" => GetCookieInfo(param),
|
||||
"getDS" => GetDynamicSecrectV1(param),
|
||||
"getUserInfo" => GetUserInfo(param),
|
||||
"getCookieToken" => await GetCookieTokenAsync(param).ConfigureAwait(false),
|
||||
"configure_share" => null,
|
||||
"getDS" => GetDynamicSecrectV1(param),
|
||||
"getDS2" => GetDynamicSecrectV2(param),
|
||||
"getHTTPRequestHeaders" => GetHttpRequestHeader(param),
|
||||
"getUserInfo" => GetUserInfo(param),
|
||||
"login" => null,
|
||||
_ => null,
|
||||
_ => logger.LogWarning<IJsResult>("Unhandled Message Type: {method}", param.Method),
|
||||
};
|
||||
|
||||
if (result != null)
|
||||
if (result != null && param.Callback != null)
|
||||
{
|
||||
await ExecuteCallbackScriptAsync(param.Callback, result.ToString(options)).ConfigureAwait(false);
|
||||
}
|
||||
@@ -329,6 +373,8 @@ public class MiHoYoJSInterface
|
||||
{
|
||||
if (new Uri(args.Uri).Host.EndsWith("mihoyo.com"))
|
||||
{
|
||||
// Execute this solve issue: When open same site second time,there might be no bridge init.
|
||||
coreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(InitializeJsInterfaceScript2).AsTask().SafeForget(logger);
|
||||
coreWebView2.ExecuteScriptAsync(InitializeJsInterfaceScript2).AsTask().SafeForget(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,4 @@ public class CookieTokenPayload
|
||||
/// </summary>
|
||||
[JsonPropertyName("forceRefresh")]
|
||||
public bool ForceRefresh { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Bridge.Model;
|
||||
|
||||
/// <summary>
|
||||
/// DS2请求
|
||||
/// </summary>
|
||||
public class DynamicSecrect2Playload
|
||||
{
|
||||
/// <summary>
|
||||
/// q
|
||||
/// </summary>
|
||||
[JsonPropertyName("query")]
|
||||
public Dictionary<string, string> Query { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// b
|
||||
/// </summary>
|
||||
[JsonPropertyName("body")]
|
||||
public string Body { get; set; } = default!;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class JsParam
|
||||
/// 回调的名称,调用 JavaScript:mhyWebBridge 时作为首个参数传入
|
||||
/// </summary>
|
||||
[JsonPropertyName("callback")]
|
||||
public string Callback { get; set; } = default!;
|
||||
public string? Callback { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,14 +52,14 @@ public class JsParam<TPayload>
|
||||
/// 回调的名称,调用 JavaScript:mhyWebBridge 时作为首个参数传入
|
||||
/// </summary>
|
||||
[JsonPropertyName("callback")]
|
||||
public string Callback { get; set; } = string.Empty;
|
||||
public string? Callback { get; set; }
|
||||
|
||||
public static implicit operator JsParam<TPayload>(JsParam jsParam)
|
||||
{
|
||||
return new JsParam<TPayload>()
|
||||
{
|
||||
Method = jsParam.Method,
|
||||
Payload = jsParam.Payload.HasValue ? jsParam.Payload.Value.Deserialize<TPayload>() : default,
|
||||
Payload = jsParam.Payload.HasValue ? jsParam.Payload.Value.Deserialize<TPayload>()! : default!,
|
||||
Callback = jsParam.Callback,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,4 +30,4 @@ public class SignInJsInterface : MiHoYoJSInterface
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Snap.Hutao.Web.Geetest;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Snap.Hutao.Web.Hoyolab.Annotation;
|
||||
/// <summary>
|
||||
/// 指示相关的类忽略Http请求的Set-Cookie头
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple =false, Inherited =false)]
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal class IgnoreSetCookieAttribute : Attribute
|
||||
{
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab;
|
||||
|
||||
/// <summary>
|
||||
/// 忽略 Set-Cookie 头
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal class IgnoreSetCookieHandler : DelegatingHandler
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
HttpResponseMessage message = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
message.Headers.Remove("Set-Cookie");
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Annotation;
|
||||
using Snap.Hutao.Web.Request;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Annotation;
|
||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Auth;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Web.Geetest;
|
||||
using Snap.Hutao.Web.Hoyolab.Annotation;
|
||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Annotation;
|
||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Widget;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Annotation;
|
||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Widget;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -137,6 +137,21 @@ internal class HomaClient
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取武器搭配
|
||||
/// GET /Statistics/Avatar/AvatarCollocation
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>角色/武器/圣遗物搭配</returns>
|
||||
public async Task<List<WeaponCollocation>> GetWeaponCollocationsAsync(CancellationToken token = default)
|
||||
{
|
||||
Response<List<WeaponCollocation>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<List<WeaponCollocation>>>($"{HutaoAPI}/Statistics/Weapon/WeaponCollocation", token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取角色命座信息
|
||||
/// GET /Statistics/Avatar/HoldingRate
|
||||
|
||||
@@ -6,7 +6,7 @@ using Snap.Hutao.Model.Primitive;
|
||||
namespace Snap.Hutao.Web.Hutao.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 角色相关解构
|
||||
/// 角色相关构筑
|
||||
/// </summary>
|
||||
public abstract class AvatarBuild
|
||||
{
|
||||
|
||||
@@ -35,6 +35,6 @@ public class ReliquarySet
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{EquipAffixId}-{Count}";
|
||||
return $"{(int)EquipAffixId}-{Count}";
|
||||
}
|
||||
}
|
||||
|
||||
17
src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/WeaponBuild.cs
Normal file
17
src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/WeaponBuild.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Web.Hutao.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 武器相关构筑
|
||||
/// </summary>
|
||||
public abstract class WeaponBuild
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// </summary>
|
||||
public WeaponId WeaponId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hutao.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 武器搭配
|
||||
/// </summary>
|
||||
public class WeaponCollocation : WeaponBuild
|
||||
{
|
||||
/// <summary>
|
||||
/// 其他角色
|
||||
/// </summary>
|
||||
public List<ItemRate<int, double>> Avatars { get; set; } = default!;
|
||||
}
|
||||
@@ -43,6 +43,11 @@ public enum KnownReturnCode : int
|
||||
/// </summary>
|
||||
RET_NEED_AIGIS = -3101,
|
||||
|
||||
/// <summary>
|
||||
/// 参数不合法
|
||||
/// </summary>
|
||||
InvalidParameter = -3001,
|
||||
|
||||
/// <summary>
|
||||
/// 请在米游社App内打开~
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user