1
0
mirror of synced 2025-03-01 16:11:04 +01:00

Create Challenge/Compete | Accept/Reject Challenge | Participate in Compete

This commit is contained in:
ptmaster 2024-09-16 20:04:01 +08:00
parent 9bb363e1b8
commit aa9b398628
20 changed files with 1321 additions and 101 deletions

View File

@ -0,0 +1,798 @@
// <auto-generated />
using System;
using GameDatabase.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace GameDatabase.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20240915182025_Add ChallengeCompetition")]
partial class AddChallengeCompetition
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.3");
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<bool>("IsWin")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty");
b.ToTable("AiScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<int>("SectionIndex")
.HasColumnType("INTEGER");
b.Property<int>("Crown")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<bool>("IsWin")
.HasColumnType("INTEGER");
b.Property<uint>("MissCount")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<uint>("Score")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
b.ToTable("AiSectionScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
{
b.Property<string>("AccessCode")
.HasColumnType("TEXT");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.HasKey("AccessCode");
b.HasIndex("Baid");
b.ToTable("Card", (string)null);
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteBestDatum", b =>
{
b.Property<uint>("CompId")
.HasColumnType("INTEGER");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
.HasColumnType("INTEGER");
b.Property<uint>("Crown")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<uint>("HitCount")
.HasColumnType("INTEGER");
b.Property<uint>("MissCount")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<uint>("Score")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRank")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRate")
.HasColumnType("INTEGER");
b.Property<bool>("Skipped")
.HasColumnType("INTEGER");
b.HasKey("CompId", "Baid", "SongId");
b.HasIndex("Baid");
b.HasIndex("CompId", "SongId");
b.ToTable("ChallengeCompeteBestData");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteDatum", b =>
{
b.Property<uint>("CompId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<string>("CompeteDescribe")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("CompeteMode")
.HasColumnType("INTEGER");
b.Property<string>("CompeteName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("CompeteTarget")
.HasColumnType("INTEGER");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime");
b.Property<DateTime>("ExpireTime")
.HasColumnType("datetime");
b.Property<uint>("MaxParticipant")
.HasColumnType("INTEGER");
b.Property<bool>("OnlyPlayOnce")
.HasColumnType("INTEGER");
b.Property<uint>("RequireTitle")
.HasColumnType("INTEGER");
b.Property<uint>("Share")
.HasColumnType("INTEGER");
b.Property<uint>("State")
.HasColumnType("INTEGER");
b.HasKey("CompId");
b.HasIndex("Baid")
.IsUnique();
b.ToTable("ChallengeCompeteData");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteParticipantDatum", b =>
{
b.Property<uint>("CompId")
.HasColumnType("INTEGER");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<bool>("IsActive")
.HasColumnType("INTEGER");
b.HasKey("CompId", "Baid");
b.HasIndex("Baid");
b.ToTable("ChallengeCompeteParticipantData");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteSongDatum", b =>
{
b.Property<uint>("CompId")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<bool?>("IsInverseOn")
.HasColumnType("INTEGER");
b.Property<bool?>("IsVanishOn")
.HasColumnType("INTEGER");
b.Property<int?>("RandomType")
.HasColumnType("INTEGER");
b.Property<uint?>("Speed")
.HasColumnType("INTEGER");
b.HasKey("CompId", "SongId");
b.ToTable("ChallengeCompeteSongData");
});
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Salt")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Baid");
b.ToTable("Credential", (string)null);
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
b.Property<int>("DanType")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(1);
b.Property<uint>("ArrivalSongCount")
.HasColumnType("INTEGER");
b.Property<uint>("ClearState")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(0u);
b.Property<uint>("ComboCountTotal")
.HasColumnType("INTEGER");
b.Property<uint>("SoulGaugeTotal")
.HasColumnType("INTEGER");
b.HasKey("Baid", "DanId", "DanType");
b.ToTable("DanScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
b.Property<int>("DanType")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(1);
b.Property<uint>("SongNumber")
.HasColumnType("INTEGER");
b.Property<uint>("BadCount")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<uint>("HighScore")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<uint>("PlayScore")
.HasColumnType("INTEGER");
b.Property<uint>("TotalHitCount")
.HasColumnType("INTEGER");
b.HasKey("Baid", "DanId", "DanType", "SongNumber");
b.ToTable("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<uint>("BestCrown")
.HasColumnType("INTEGER");
b.Property<uint>("BestRate")
.HasColumnType("INTEGER");
b.Property<uint>("BestScore")
.HasColumnType("INTEGER");
b.Property<uint>("BestScoreRank")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty");
b.ToTable("SongBestData");
});
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
.HasColumnType("INTEGER");
b.Property<uint>("Crown")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<uint>("HitCount")
.HasColumnType("INTEGER");
b.Property<uint>("MissCount")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<DateTime>("PlayTime")
.HasColumnType("datetime");
b.Property<uint>("Score")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRank")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRate")
.HasColumnType("INTEGER");
b.Property<bool>("Skipped")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("SongNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Baid");
b.ToTable("SongPlayData");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<int>("Id")
.HasColumnType("INTEGER");
b.Property<int>("Count")
.HasColumnType("INTEGER");
b.HasKey("Baid", "Id");
b.ToTable("Tokens");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Property<uint>("Baid")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<uint>("AchievementDisplayDifficulty")
.HasColumnType("INTEGER");
b.Property<int>("AiWinCount")
.HasColumnType("INTEGER");
b.Property<uint>("ColorBody")
.HasColumnType("INTEGER");
b.Property<uint>("ColorFace")
.HasColumnType("INTEGER");
b.Property<uint>("ColorLimb")
.HasColumnType("INTEGER");
b.Property<string>("CostumeData")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("CostumeFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("CurrentBody")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentFace")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentHead")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentKigurumi")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentPuchi")
.HasColumnType("INTEGER");
b.Property<string>("DifficultyPlayedArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("DifficultyPlayedCourse")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultyPlayedSort")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultyPlayedStar")
.HasColumnType("INTEGER");
b.Property<string>("DifficultySettingArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("DifficultySettingCourse")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultySettingSort")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultySettingStar")
.HasColumnType("INTEGER");
b.Property<bool>("DisplayAchievement")
.HasColumnType("INTEGER");
b.Property<bool>("DisplayDan")
.HasColumnType("INTEGER");
b.Property<string>("FavoriteSongsArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("GenericInfoFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsAdmin")
.HasColumnType("INTEGER");
b.Property<bool>("IsSkipOn")
.HasColumnType("INTEGER");
b.Property<bool>("IsVoiceOn")
.HasColumnType("INTEGER");
b.Property<DateTime>("LastPlayDatetime")
.HasColumnType("datetime");
b.Property<uint>("LastPlayMode")
.HasColumnType("INTEGER");
b.Property<string>("MyDonName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("MyDonNameLanguage")
.HasColumnType("INTEGER");
b.Property<int>("NotesPosition")
.HasColumnType("INTEGER");
b.Property<short>("OptionSetting")
.HasColumnType("INTEGER");
b.Property<uint>("SelectedToneId")
.HasColumnType("INTEGER");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("TitleFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("TitlePlateId")
.HasColumnType("INTEGER");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedBody")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedFace")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedHead")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedKigurumi")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedPuchi")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedSongIdList")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Baid");
b.ToTable("UserData");
});
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.AiScoreDatum", "Parent")
.WithMany("AiSectionScoreData")
.HasForeignKey("Baid", "SongId", "Difficulty")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Parent");
});
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteBestDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "UserData")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("GameDatabase.Entities.ChallengeCompeteSongDatum", "ChallengeCompeteSongData")
.WithMany("BestScores")
.HasForeignKey("CompId", "SongId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ChallengeCompeteSongData");
b.Navigation("UserData");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Holder")
.WithOne()
.HasForeignKey("GameDatabase.Entities.ChallengeCompeteDatum", "Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Holder");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteParticipantDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "UserData")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("GameDatabase.Entities.ChallengeCompeteDatum", "ChallengeCompeteData")
.WithMany("Participants")
.HasForeignKey("CompId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ChallengeCompeteData");
b.Navigation("UserData");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteSongDatum", b =>
{
b.HasOne("GameDatabase.Entities.ChallengeCompeteDatum", "ChallengeCompeteData")
.WithMany("Songs")
.HasForeignKey("CompId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ChallengeCompeteData");
});
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.DanScoreDatum", "Parent")
.WithMany("DanStageScoreData")
.HasForeignKey("Baid", "DanId", "DanType")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Parent");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Datum")
.WithMany("Tokens")
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Datum");
});
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Navigation("AiSectionScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteDatum", b =>
{
b.Navigation("Participants");
b.Navigation("Songs");
});
modelBuilder.Entity("GameDatabase.Entities.ChallengeCompeteSongDatum", b =>
{
b.Navigation("BestScores");
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Navigation("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Navigation("Tokens");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace GameDatabase.Migrations
{
/// <inheritdoc />
public partial class AddChallengeCompetion : Migration
public partial class AddChallengeCompetition : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
@ -33,6 +33,12 @@ namespace GameDatabase.Migrations
constraints: table =>
{
table.PrimaryKey("PK_ChallengeCompeteData", x => x.CompId);
table.ForeignKey(
name: "FK_ChallengeCompeteData_UserData_Baid",
column: x => x.Baid,
principalTable: "UserData",
principalColumn: "Baid",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
@ -130,6 +136,12 @@ namespace GameDatabase.Migrations
table: "ChallengeCompeteBestData",
columns: new[] { "CompId", "SongId" });
migrationBuilder.CreateIndex(
name: "IX_ChallengeCompeteData_Baid",
table: "ChallengeCompeteData",
column: "Baid",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ChallengeCompeteParticipantData_Baid",
table: "ChallengeCompeteParticipantData",

View File

@ -11,8 +11,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace GameDatabase.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20240911133119_AddChallengeCompetion")]
partial class AddChallengeCompetion
[Migration("20240915191732_Update ChallengeCompetition")]
partial class UpdateChallengeCompetition
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)

View File

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace GameDatabase.Migrations
{
/// <inheritdoc />
public partial class UpdateChallengeCompetition : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_ChallengeCompeteData_UserData_Baid",
table: "ChallengeCompeteData");
migrationBuilder.DropIndex(
name: "IX_ChallengeCompeteData_Baid",
table: "ChallengeCompeteData");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_ChallengeCompeteData_Baid",
table: "ChallengeCompeteData",
column: "Baid",
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_ChallengeCompeteData_UserData_Baid",
table: "ChallengeCompeteData",
column: "Baid",
principalTable: "UserData",
principalColumn: "Baid",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@ -17,6 +17,7 @@ public class ChallengeCompetition
public bool OnlyPlayOnce { get; set; } = false;
public ShareType Share { get; set; } = ShareType.EveryOne;
public CompeteTargetType CompeteTarget { get; set; } = CompeteTargetType.EveryOne;
public UserAppearance? Holder { get; set; } = new();
public List<ChallengeCompetitionSong> Songs { get; set; } = new();
public List<ChallengeCompetitionParticipant> Participants { get; set; } = new();
}

View File

@ -0,0 +1,18 @@
namespace SharedProject.Models;
public class ChallengeCompetitionHolderInfo
{
public uint Baid { get; set; }
public string MyDonName { get; set; } = string.Empty;
public uint MyDonNameLanguage { get; set; }
public string Title { get; set; } = string.Empty;
public uint TitlePlateId { get; set; }
public uint ColorBody { get; set; }
public uint ColorFace { get; set; }
public uint ColorLimb { get; set; }
public uint CurrentKigurumi { get; set; }
public uint CurrentHead { get; set; }
public uint CurrentBody { get; set; }
public uint CurrentFace { get; set; }
public uint CurrentPuchi { get; set; }
}

View File

@ -5,4 +5,5 @@ public class ChallengeCompetitionParticipant
public uint CompId { get; set; }
public uint Baid { get; set; }
public bool IsActive { get; set; }
public UserAppearance? UserInfo { get; set; } = new();
}

View File

@ -1,14 +1,19 @@
using SharedProject.Enums;
using System.Text.Json.Serialization;
namespace SharedProject.Models;
public class PlaySetting
{
[JsonPropertyName("speed")]
public uint Speed { get; set; }
[JsonPropertyName("isVanishOn")]
public bool IsVanishOn { get; set; }
[JsonPropertyName("isInverseOn")]
public bool IsInverseOn { get; set; }
[JsonPropertyName("randomType")]
public RandomType RandomType { get; set; }
}

View File

@ -1,12 +1,18 @@
namespace SharedProject.Models;
using System.Text.Json.Serialization;
namespace SharedProject.Models;
public class User
{
[JsonPropertyName("baid")]
public uint Baid { get; set; }
[JsonPropertyName("accessCodes")]
public List<string> AccessCodes { get; set; } = new();
[JsonPropertyName("isAdmin")]
public bool IsAdmin { get; set; }
[JsonPropertyName("userSetting")]
public UserSetting UserSetting { get; set; } = new();
}

View File

@ -1,68 +1,100 @@
using SharedProject.Enums;
using System.Text.Json.Serialization;
namespace SharedProject.Models;
public class UserSetting
{
[JsonPropertyName("baid")]
public uint Baid { get; set; }
[JsonPropertyName("toneId")]
public uint ToneId { get; set; }
[JsonPropertyName("isDisplayAchievement")]
public bool IsDisplayAchievement { get; set; }
[JsonPropertyName("isDisplayDanOnNamePlate")]
public bool IsDisplayDanOnNamePlate { get; set; }
[JsonPropertyName("difficultySettingCourse")]
public uint DifficultySettingCourse { get; set; }
[JsonPropertyName("difficultySettingStar")]
public uint DifficultySettingStar { get; set; }
[JsonPropertyName("difficultySettingSort")]
public uint DifficultySettingSort { get; set; }
[JsonPropertyName("isVoiceOn")]
public bool IsVoiceOn { get; set; }
[JsonPropertyName("isSkipOn")]
public bool IsSkipOn { get; set; }
[JsonPropertyName("achievementDisplayDifficulty")]
public Difficulty AchievementDisplayDifficulty { get; set; }
[JsonPropertyName("playSetting")]
public PlaySetting PlaySetting { get; set; } = new();
[JsonPropertyName("notesPosition")]
public int NotesPosition { get; set; }
[JsonPropertyName("myDonName")]
public string MyDonName { get; set; } = string.Empty;
[JsonPropertyName("myDonNameLanguage")]
public uint MyDonNameLanguage { get; set; }
[JsonPropertyName("title")]
public string Title { get; set; } = string.Empty;
[JsonPropertyName("titlePlateId")]
public uint TitlePlateId { get; set; }
[JsonPropertyName("kigurumi")]
public uint Kigurumi { get; set; }
[JsonPropertyName("head")]
public uint Head { get; set; }
[JsonPropertyName("body")]
public uint Body { get; set; }
[JsonPropertyName("face")]
public uint Face { get; set; }
[JsonPropertyName("puchi")]
public uint Puchi { get; set; }
[JsonPropertyName("unlockedKigurumi")]
public List<uint> UnlockedKigurumi { get; set; } = new();
[JsonPropertyName("unlockedHead")]
public List<uint> UnlockedHead { get; set; } = new();
[JsonPropertyName("unlockedBody")]
public List<uint> UnlockedBody { get; set; } = new();
[JsonPropertyName("unlockedFace")]
public List<uint> UnlockedFace { get; set; } = new();
[JsonPropertyName("unlockedPuchi")]
public List<uint> UnlockedPuchi { get; set; } = new();
[JsonPropertyName("unlockedTitle")]
public List<uint> UnlockedTitle { get; set; } = new();
[JsonPropertyName("faceColor")]
public uint FaceColor { get; set; }
[JsonPropertyName("bodyColor")]
public uint BodyColor { get; set; }
[JsonPropertyName("limbColor")]
public uint LimbColor { get; set; }
[JsonPropertyName("lastPlayDateTime")]
public DateTime LastPlayDateTime { get; set; }
}

View File

@ -92,7 +92,7 @@ public class ChallengeCompeteManageController(IChallengeCompeteService challenge
await challengeCompeteService.CreateCompete(0, challengeCompeteInfo);
return NoContent();
return Ok();
}
[HttpPost("{baid}/createCompete")]
@ -102,7 +102,7 @@ public class ChallengeCompeteManageController(IChallengeCompeteService challenge
Logger.LogInformation("CreateCompete : {Request}", JsonFormatter.JsonSerialize(challengeCompeteInfo));
await challengeCompeteService.CreateCompete(baid, challengeCompeteInfo);
return NoContent();
return Ok();
}
[HttpPost("{baid}/createChallenge/{targetBaid}")]
@ -112,13 +112,14 @@ public class ChallengeCompeteManageController(IChallengeCompeteService challenge
Logger.LogInformation("CreateChallenge : {Request}", JsonFormatter.JsonSerialize(challengeCompeteInfo));
await challengeCompeteService.CreateChallenge(baid, targetBaid, challengeCompeteInfo);
return NoContent();
return Ok();
}
[HttpGet("{baid}/joinCompete/{compId}")]
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
public async Task<ActionResult<bool>> JoinCompete(uint baid, uint compId)
{
Logger.LogInformation($"JoinCompete {baid} {compId}");
bool result = await challengeCompeteService.ParticipateCompete(compId, baid);
return Ok(result);
@ -128,6 +129,7 @@ public class ChallengeCompeteManageController(IChallengeCompeteService challenge
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
public async Task<ActionResult<bool>> AcceptChallenge(uint baid, uint compId)
{
Logger.LogInformation($"AcceptChallenge {baid} {compId}");
bool result = await challengeCompeteService.AnswerChallenge(compId, baid, true);
return Ok(result);
@ -137,6 +139,7 @@ public class ChallengeCompeteManageController(IChallengeCompeteService challenge
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
public async Task<ActionResult<bool>> RejectChallenge(uint baid, uint compId)
{
Logger.LogInformation($"RejectChallenge {baid} {compId}");
bool result = await challengeCompeteService.AnswerChallenge(compId, baid, false);
return Ok(result);

View File

@ -88,4 +88,17 @@ public class UsersController(IUserDatumService userDatumService, IAuthService au
return result ? NoContent() : NotFound();
}
[HttpGet("{baid}/AllUserDict")]
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
public async Task<IActionResult> AllUserDict(uint baid)
{
Dictionary<uint, User> data = await userDatumService.GetAllUserDict();
if (baid != 0)
{
data.Remove(baid);
}
return Ok(data);
}
}

View File

@ -3,7 +3,6 @@ using GameDatabase.Context;
using SharedProject.Models;
using SharedProject.Models.Responses;
using SharedProject.Utils;
using TaikoLocalServer.Services.Interfaces;
using Throw;
namespace TaikoLocalServer.Services;
@ -174,7 +173,8 @@ public class ChallengeCompeteService : IChallengeCompeteService
public async Task<bool> ParticipateCompete(uint compId, uint baid)
{
var challengeCompete = await context.ChallengeCompeteData.FindAsync(compId);
var challengeCompete = await context.ChallengeCompeteData
.Include(c => c.Participants).Where(c => c.CompId == compId).FirstOrDefaultAsync();
challengeCompete.ThrowIfNull($"Challenge not found for CompId {compId}!");
if (challengeCompete.MaxParticipant <= challengeCompete.Participants.Count()) return false;
@ -247,16 +247,15 @@ public class ChallengeCompeteService : IChallengeCompeteService
public async Task<bool> AnswerChallenge(uint compId, uint baid, bool accept)
{
var challengeCompete = await context.ChallengeCompeteData.FindAsync(compId);
var challengeCompete = await context.ChallengeCompeteData
.Include(c => c.Participants).Where(c => c.CompId == compId).FirstOrDefaultAsync();
challengeCompete.ThrowIfNull($"Challenge not found for CompId {compId}!");
if (challengeCompete.Baid == baid) return false;
bool hasTarget = false;
foreach (var participant in challengeCompete.Participants)
if (!challengeCompete.Participants.Any(p => p.Baid == baid))
{
if (participant.Baid == baid) hasTarget = true;
return false;
}
if (!hasTarget) return false;
if (accept)
{
@ -341,6 +340,14 @@ public class ChallengeCompeteService : IChallengeCompeteService
public async Task<ChallengeCompetition> FillData(ChallengeCompetition challenge)
{
UserDatum? holder = await userDatumService.GetFirstUserDatumOrNull(challenge.Baid);
challenge.Holder = convert(holder);
foreach (var participant in challenge.Participants)
{
if (participant == null) continue;
UserDatum? user = await userDatumService.GetFirstUserDatumOrNull(participant.Baid);
participant.UserInfo = convert(user);
}
foreach (var song in challenge.Songs)
{
if (song == null) continue;
@ -348,26 +355,31 @@ public class ChallengeCompeteService : IChallengeCompeteService
foreach (var score in song.BestScores)
{
UserDatum? user = await userDatumService.GetFirstUserDatumOrNull(score.Baid);
if (user == null) continue;
score.UserAppearance = new UserAppearance
{
Baid = score.Baid,
MyDonName = user.MyDonName,
MyDonNameLanguage = user.MyDonNameLanguage,
Title = user.Title,
TitlePlateId = user.TitlePlateId,
Kigurumi = user.CurrentKigurumi,
Head = user.CurrentHead,
Body = user.CurrentBody,
Face = user.CurrentFace,
Puchi = user.CurrentPuchi,
FaceColor = user.ColorFace,
BodyColor = user.ColorBody,
LimbColor = user.ColorLimb,
};
score.UserAppearance = convert(user);
}
}
return challenge;
}
private UserAppearance? convert(UserDatum? user)
{
if (user == null) return null;
return new UserAppearance
{
Baid = user.Baid,
MyDonName = user.MyDonName,
MyDonNameLanguage = user.MyDonNameLanguage,
Title = user.Title,
TitlePlateId = user.TitlePlateId,
Kigurumi = user.CurrentKigurumi,
Head = user.CurrentHead,
Body = user.CurrentBody,
Face = user.CurrentFace,
Puchi = user.CurrentPuchi,
FaceColor = user.ColorFace,
BodyColor = user.ColorBody,
LimbColor = user.ColorLimb,
};
}
}

View File

@ -1,9 +1,13 @@
namespace TaikoLocalServer.Services.Interfaces;
using SharedProject.Models;
namespace TaikoLocalServer.Services.Interfaces;
public interface IUserDatumService
{
public Task<List<UserDatum>> GetAllUserDatum();
public Task<Dictionary<uint, User>> GetAllUserDict();
public Task<UserDatum?> GetFirstUserDatumOrNull(uint baid);
public Task UpdateUserDatum(UserDatum userDatum);

View File

@ -1,5 +1,7 @@
using GameDatabase.Context;
using Throw;
using SharedProject.Models;
using MudExtensions;
namespace TaikoLocalServer.Services;
@ -9,6 +11,46 @@ public class UserDatumService(TaikoDbContext context) : IUserDatumService
{
return await context.UserData.Include(d => d.Tokens).ToListAsync();
}
public async Task<Dictionary<uint, User>> GetAllUserDict()
{
List<UserDatum> listUser = await GetAllUserDatum();
Dictionary<uint, User> dict = new Dictionary<uint, User>();
foreach (var user in listUser)
{
dict.Add(user.Baid, new()
{
Baid = user.Baid,
IsAdmin = false,
UserSetting = new()
{
Baid = user.Baid,
ToneId = user.SelectedToneId,
IsDisplayAchievement = user.DisplayAchievement,
IsDisplayDanOnNamePlate = user.DisplayDan,
DifficultySettingCourse = user.DifficultySettingCourse,
DifficultySettingStar = user.DifficultyPlayedStar,
DifficultySettingSort = user.DifficultyPlayedSort,
IsVoiceOn = user.IsVoiceOn,
IsSkipOn = user.IsSkipOn,
AchievementDisplayDifficulty = user.AchievementDisplayDifficulty,
MyDonName = user.MyDonName,
MyDonNameLanguage = user.MyDonNameLanguage,
Title = user.Title,
TitlePlateId = user.TitlePlateId,
Kigurumi = user.CurrentKigurumi,
Head = user.CurrentHead,
Body = user.CurrentBody,
Face = user.CurrentFace,
Puchi = user.CurrentPuchi,
FaceColor = user.ColorFace,
BodyColor = user.ColorFace,
LimbColor = user.ColorLimb
}
});
}
return dict;
}
public async Task<UserDatum?> GetFirstUserDatumOrNull(uint baid)
{

View File

@ -6,12 +6,28 @@
<MudCard>
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@ChallengeCompetition.CompeteName</MudText>
<MudText Typo="Typo.caption" Style="display: block">@Localizer["Comp ID"]:@ChallengeCompetition.CompId</MudText>
<MudText Typo="Typo.caption" Style="display: block">@Localizer["Describe"]:@ChallengeCompetition.CompeteDescribe</MudText>
@if (ChallengeCompetition.CompeteMode == CompeteModeType.Chanllenge)
{
@if (ChallengeCompetition?.Baid != Baid)
{
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@Localizer["From"] @ChallengeCompetition?.Holder?.MyDonName</MudText>
}
else
{
var participant = ChallengeCompetition?.Participants?.Find(p => p.Baid != Baid);
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@Localizer["To"] @participant?.UserInfo?.MyDonName</MudText>
}
}
else
{
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@ChallengeCompetition?.CompeteName</MudText>
}
<MudText Typo="Typo.caption" Style="display: block">@Localizer["Comp ID"]:@ChallengeCompetition?.CompId</MudText>
<MudText Typo="Typo.caption" Style="display: block">@Localizer["Describe"]:@ChallengeCompetition?.CompeteDescribe</MudText>
</CardHeaderContent>
<CardHeaderActions>
@if (false && SelfHoldedChallengeCompetiton())
@if (false && ChallengeCompetition?.Baid == Baid || Baid == 0)
{
<MudIconButton Icon="@Icons.Material.Filled.Settings" Color="Color.Default" />
}
@ -34,17 +50,51 @@
OnClick=@(_ => AnswerChallenge(true))>@Localizer["Information"]</MudButton>
@if (ChallengeCompetition.CompeteMode == CompeteModeType.Chanllenge)
{
<MudButtonGroup Color="Color.Primary" Variant="Variant.Filled">
<MudButton Disabled=@ChallengeNeedAnswer()
OnClick=@(_ => AnswerChallenge(true))>@Localizer["Accept"]</MudButton>
<MudButton Disabled=@ChallengeNeedAnswer()
OnClick=@(_ => AnswerChallenge(false))>@Localizer["Reject"]</MudButton>
</MudButtonGroup>
@if (Baid == 0 || ChallengeCompetition?.Baid == Baid || ChallengeCompetition?.State != CompeteState.Waiting)
{
switch (ChallengeCompetition?.State)
{
case CompeteState.Waiting:
<MudText Typo="Typo.body1" Style="padding: 6px 8px 6px 8px;" Color="Color.Primary">@Localizer["Waiting"]</MudText>
break;
case CompeteState.Normal:
<MudText Typo="Typo.body1" Style="padding: 6px 8px 6px 8px;" Color="Color.Success">@Localizer["Accepted"]</MudText>
break;
case CompeteState.Rejected:
<MudText Typo="Typo.body1" Style="padding: 6px 8px 6px 8px;" Color="Color.Error">@Localizer["Rejected"]</MudText>
break;
}
}
else
{
<MudButtonGroup Color="Color.Primary" Variant="Variant.Filled">
<MudButton Disabled="@(Baid == 0 || (ChallengeCompetition?.State == CompeteState.Waiting && ChallengeCompetition?.Baid == Baid))"
OnClick=@(_ => AnswerChallenge(true))>@Localizer["Accept"]</MudButton>
<MudButton Disabled="@(Baid == 0 || (ChallengeCompetition?.State == CompeteState.Waiting && ChallengeCompetition?.Baid == Baid))"
OnClick=@(_ => AnswerChallenge(false))>@Localizer["Reject"]</MudButton>
</MudButtonGroup>
}
}
else
else if (ChallengeCompetition.CompeteMode == CompeteModeType.Compete || ChallengeCompetition.CompeteMode == CompeteModeType.OfficialCompete)
{
<MudButton Disabled=@CanParticipateChallengeCompetition()
OnClick=@(_ => AnswerChallenge(true))>@Localizer["Participate"]</MudButton>
if (Baid != 0)
{
if (ChallengeCompetition.Participants.Any(p => p.Baid == Baid))
{
<MudText Typo="Typo.body1" Style="padding: 6px 8px 6px 8px;" Color="Color.Success">@Localizer["Participated"]</MudText>
}
else
{
if (ChallengeCompetition.MaxParticipant <= ChallengeCompetition.Participants.Count)
{
<MudText Typo="Typo.body1" Style="padding: 6px 8px 6px 8px;" Color="Color.Warning">@Localizer["Fullfilled"]</MudText>
}
else
{
<MudButton OnClick="AnswerCompete">@Localizer["Participate"]</MudButton>
}
}
}
}
</MudStack>
</MudCardActions>
@ -53,7 +103,8 @@
@code {
[Parameter] public ChallengeCompetition? ChallengeCompetition { get; set; }
[Parameter] public uint Baid { get; set; }
[Parameter] public int Baid { get; set; }
[Parameter] public EventCallback<ChallengeCompetition> Refresh { get; set; }
private bool SelfHoldedChallengeCompetiton()
{
@ -62,7 +113,7 @@
private bool ChallengeNeedAnswer()
{
return ChallengeCompetition?.State == CompeteState.Waiting && !SelfHoldedChallengeCompetiton();
return Baid != 0 && ChallengeCompetition?.State == CompeteState.Waiting && ChallengeCompetition?.Baid != Baid;
}
private bool ParticipatedChallengeCompetition()
@ -78,23 +129,33 @@
private async Task AnswerChallenge(bool accept)
{
if (ChallengeCompetition == null || ChallengeCompetition.State != CompeteState.Waiting) return;
var request = new AnswerChallengeRequest
{
CompId = ChallengeCompetition.CompId,
Baid = Baid,
Accept = accept
};
var response = await Client.PostAsJsonAsync("api/ChallengeCompetitionManage/AnswerChallenge", request);
var url = accept ? $"api/ChallengeCompeteManage/{Baid}/acceptChallenge/{ChallengeCompetition.CompId}" : $"api/ChallengeCompeteManage/{Baid}/rejectChallenge/{ChallengeCompetition.CompId}";
var response = await Client.GetAsync(url);
if (!response.IsSuccessStatusCode)
{
await DialogService.ShowMessageBox(
Localizer["Error"],
Localizer["Unknown Error"],
Localizer["Request Error"],
Localizer["Dialog OK"], null, null, new DialogOptions { DisableBackdropClick = true });
return;
}
await Refresh.InvokeAsync(ChallengeCompetition);
ChallengeCompetition.State = accept ? CompeteState.Normal : CompeteState.Rejected;
}
private async Task AnswerCompete()
{
if (ChallengeCompetition == null) return;
var response = await Client.GetAsync($"api/ChallengeCompeteManage/{Baid}/joinCompete/{ChallengeCompetition.CompId}");
if (!response.IsSuccessStatusCode)
{
await DialogService.ShowMessageBox(
Localizer["Error"],
Localizer["Request Error"],
Localizer["Dialog OK"], null, null, new DialogOptions { DisableBackdropClick = true });
return;
}
await Refresh.InvokeAsync(ChallengeCompetition);
}
}

View File

@ -65,7 +65,7 @@
foreach (var challengeCompetition in response.List)
{
<MudItem xs="12" md="6" lg="4" xl="3">
<ChallengeCompe ChallengeCompetition="challengeCompetition" Baid="(uint)Baid" />
<ChallengeCompe ChallengeCompetition="challengeCompetition" Baid="Baid" Refresh="UpdateCompete" />
</MudItem>
}
}
@ -105,8 +105,6 @@
[Parameter]
public int Mode { get; set; }
private ChallengeCompetitionResponse? response = new();
private CancellationTokenSource? cts;
private int TotalPages { get; set; } = 0;
@ -127,6 +125,17 @@
isLoading = false;
}
private async Task UpdateCompete(ChallengeCompetition cc)
{
await GetUsersData();
var updated = response?.List.Find(c => c.CompId == cc.CompId);
if (updated != null)
{
cc.CompeteMode = updated.CompeteMode;
cc.Participants = updated.Participants;
}
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
@ -182,13 +191,19 @@
await Debounce(GetUsersData, 500); // 500 milliseconds delay
}
private Task OpenDialogAsync(int mode, int maxSongs)
private async Task OpenDialogAsync(int mode, int maxSongs)
{
var options = new DialogOptions { CloseOnEscapeKey = true };
var parameters = new DialogParameters();
parameters.Add("Mode", mode);
parameters.Add("MaxSongs", maxSongs);
parameters.Add("Baid", Baid);
return DialogService.ShowAsync<AddChallengeCompetitionDialog>(Localizer["Create"], parameters, options);
var dialogRet = await DialogService.ShowAsync<AddChallengeCompetitionDialog>(Localizer["Create"], parameters, options);
if (dialogRet != null)
{
bool result = await dialogRet.GetReturnValueAsync<bool>();
if (result == true) await GetUsersData();
}
}
}

View File

@ -34,9 +34,16 @@
<MudStack>
@if (Mode == 2 || Mode == 3)
{
<MudTextField Value="@Name" Label="@Localizer["Name"]"/>
<MudTextField @bind-Value="Info.Name" Label="@Localizer["Name"]" MaxLength="16"/>
}
<MudTextField @bind-Value="Info.Desc" Label="@((Mode == 1 ? Localizer["Challenge"] : "") + Localizer["Describe"])" />
@if (Mode == 1)
{
<MudStack Row="true">
<MudTextField @bind-Value="TargetUserName" Label="@Localizer["Challenge Target"]"/>
<MudButton StartIcon="@Icons.Material.Filled.EmojiPeople" OnClick="@(_ => SelTarget())">@Localizer["Select"]</MudButton>
</MudStack>
}
<MudTextField Value="@Desc" Label="@Localizer["Describe"]" />
@for (int i = 0; i < Info.challengeCompeteSongs.Count; i ++)
{
var song_idx = i;
@ -44,7 +51,7 @@
var song = Info.challengeCompeteSongs[song_idx];
<MudStack Spacing="2">
<MudStack StretchItems="StretchItems.Start" Row="true">
<MudField Value="@song.SongId" Label="@song_label" Variant="Variant.Outlined" InnerPadding="false">
<MudField Label="@song_label" Variant="Variant.Outlined" InnerPadding="false">
<MudIconButton Icon="@Icons.Material.Filled.Audiotrack" OnClick="@(_ => SelSong(song_idx))" Color="Color.Primary" />
@if (difficulties[song_idx] != Difficulty.None)
@ -64,17 +71,17 @@
<MudCollapse Expanded="_expandeds[song_idx]">
<MudStack Row="true">
<MudSelect @bind-Value="@song.IsVanishOn" Label=@Localizer["Vanish"] AnchorOrigin="Origin.BottomCenter">
<MudSelect @bind-Value="song.IsVanishOn" Label=@Localizer["Vanish"] AnchorOrigin="Origin.BottomCenter">
<MudSelectItem Value="@(-1)">@Localizer["Any"]</MudSelectItem>
<MudSelectItem Value="@(1)">@Localizer["On"]</MudSelectItem>
<MudSelectItem Value="@(0)">@Localizer["Off"]</MudSelectItem>
</MudSelect>
<MudSelect @bind-Value="@song.IsInverseOn" Label=@Localizer["Inverse"] AnchorOrigin="Origin.BottomCenter">
<MudSelect @bind-Value="song.IsInverseOn" Label=@Localizer["Inverse"] AnchorOrigin="Origin.BottomCenter">
<MudSelectItem Value="@(-1)">@Localizer["Any"]</MudSelectItem>
<MudSelectItem Value="@(1)">@Localizer["On"]</MudSelectItem>
<MudSelectItem Value="@(0)">@Localizer["Off"]</MudSelectItem>
</MudSelect>
<MudSelect @bind-Value="@song.Speed" Label=@Localizer["Speed"] AnchorOrigin="Origin.BottomCenter">
<MudSelect @bind-Value="song.Speed" Label=@Localizer["Speed"] AnchorOrigin="Origin.BottomCenter">
<MudSelectItem Value="@(-1)">@Localizer["Any"]</MudSelectItem>
@for (uint idx = 0; idx < SpeedStrings.Length; idx++)
{
@ -82,7 +89,7 @@
<MudSelectItem Value="@((int)speed_idx)">@SpeedStrings[speed_idx]</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value="@song.RandomType" Label=@Localizer["Random"] AnchorOrigin="Origin.BottomCenter">
<MudSelect @bind-Value="song.RandomType" Label=@Localizer["Random"] AnchorOrigin="Origin.BottomCenter">
<MudSelectItem Value="@(-1)">@Localizer["Any"]</MudSelectItem>
@foreach (var item in Enum.GetValues<RandomType>())
{
@ -98,14 +105,17 @@
{
<MudIconButton Icon="@Icons.Material.Filled.Add" Variant="Variant.Filled" Color="Color.Primary" OnClick="AddSong" Size="Size.Medium" />
}
<MudNumericField HideSpinButtons="true" @bind-Value="@ParticipantCount" Label="@Localizer["Max Participant"]" Variant="Variant.Text" Min="1" Max="MaxParticipant" />
<MudNumericField HideSpinButtons="true" @bind-Value="@LastFor" Label="@Localizer["Last For (Days)"]" Variant="Variant.Text" Min="1" Max="MaxDays" />
<MudSwitch @bind-Value="@OnlyPlayOnce" Color="Color.Primary">@Localizer["Only Play Once"]</MudSwitch>
@if (Mode != 1)
{
<MudNumericField HideSpinButtons="true" @bind-Value="ParticipantCount" Label="@Localizer["Max Participant"]" Variant="Variant.Text" Min="1" Max="MaxParticipant" />
}
<MudNumericField HideSpinButtons="true" @bind-Value="LastFor" Label="@Localizer["Last For (Days)"]" Variant="Variant.Text" Min="1" Max="MaxDays" />
<MudSwitch @bind-Value="OnlyPlayOnce" Color="Color.Primary">@Localizer["Only Play Once"]</MudSwitch>
</MudStack>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">@Localizer["Cancel"]</MudButton>
<MudButton Color="Color.Surface" OnClick="CreateChallengeCompetition">@Localizer["Create"]</MudButton>
<MudButton Color="Color.Surface" OnClick="Create">@Localizer["Create"]</MudButton>
</DialogActions>
</MudDialog>
@ -116,6 +126,9 @@
[Parameter]
public int Mode { get; set; } = 0;
[Parameter]
public int Baid { get; set; } = 0;
[Parameter]
public int MaxSongs { get; set; } = 1;
@ -135,9 +148,9 @@
"2.0", "2.5", "3.0", "3.5", "4.0"
};
private string Name = string.Empty;
private uint TargetBaid = 0;
private string Desc = string.Empty;
private string TargetUserName = string.Empty;
private bool[] _expandeds = new bool[0];
@ -206,23 +219,33 @@
}
}
private async Task SelTarget()
{
var options = new DialogOptions { CloseOnEscapeKey = true };
var parameters = new DialogParameters();
parameters.Add("Exclude", Baid);
var reference = await DialogService.ShowAsync<ChooseUserDialog>(Localizer["Select User"], parameters, options);
var user = await reference.GetReturnValueAsync<User>();
if (user != null)
{
TargetUserName = user.UserSetting.MyDonName;
TargetBaid = user.Baid;
}
}
private void Cancel() => MudDialog.Cancel();
private async Task CreateChallengeCompetition()
private async Task Create()
{
var options = new DialogOptions { CloseOnEscapeKey = true };
Info.Name = Name;
Info.Desc = Desc;
for (int i = 0; i < Info.challengeCompeteSongs.Count; i ++)
{
if (difficulties[i] == Difficulty.None)
{
await DialogService.ShowMessageBox(
Localizer["Error"],
(MarkupString)
(string)Localizer["Must Select Song Error"],
Localizer["Dialog OK"], null, null, options);
await ShowError(Localizer["Must Select Song Error"]);
return;
}
@ -234,18 +257,52 @@
Info.CompeteMode = (CompeteModeType)Mode;
Info.OnlyPlayOnce = OnlyPlayOnce;
var resp = await Client.PostAsJsonAsync($"api/ChallengeCompeteManage/createOfficialCompete", Info);
if (resp.StatusCode != HttpStatusCode.OK)
if (Mode == 1)
{
await DialogService.ShowMessageBox(
Localizer["Error"],
(MarkupString)
(string)Localizer["Create Compete Error"],
Localizer["Dialog OK"], null, null, options);
return;
if (TargetBaid == 0)
{
await ShowError(Localizer["Must Select Challenge Target Error"]);
return;
}
var resp = await Client.PostAsJsonAsync($"api/ChallengeCompeteManage/{Baid}/createChallenge/{TargetBaid}", Info);
if (resp.StatusCode != HttpStatusCode.OK)
{
await ShowError(Localizer["Create Compete Error"]);
return;
}
}
else if (Mode == 2)
{
var resp = await Client.PostAsJsonAsync($"api/ChallengeCompeteManage/{Baid}/createCompete", Info);
if (resp.StatusCode != HttpStatusCode.OK)
{
await ShowError(Localizer["Create Compete Error"]);
return;
}
}
else if (Mode == 3)
{
var resp = await Client.PostAsJsonAsync($"api/ChallengeCompeteManage/createOfficialCompete", Info);
if (resp.StatusCode != HttpStatusCode.OK)
{
await ShowError(Localizer["Create Compete Error"]);
return;
}
}
MudDialog.Close(DialogResult.Ok(1));
MudDialog.Close(DialogResult.Ok(true));
}
private async Task ShowError(string errorWord)
{
var options = new DialogOptions { CloseOnEscapeKey = true };
await DialogService.ShowMessageBox(
Localizer["Error"],
(MarkupString)
(string)errorWord,
Localizer["Dialog OK"],
null, null, options
);
}
private void OnExpandCollapseClick(int i)

View File

@ -91,8 +91,6 @@
private string Search { get; set; } = string.Empty;
private string GenreFilter { get; set; } = string.Empty;
private string searchString = string.Empty;
protected override async Task OnInitializedAsync()

View File

@ -0,0 +1,102 @@
@using Blazored.LocalStorage
@using TaikoWebUI.Utilities;
@inject IJSRuntime Js
@inject ILocalStorageService LocalStorage
@inject HttpClient HttpClient
<MudDialog Style="width: 1200px">
<DialogContent>
<MudTable Items="userDict.Values" Filter="@FilterUser" Height="40vh" Hover="true">
<ColGroup>
<col style="width: 50px;" />
<col />
</ColGroup>
<ToolBarContent>
<MudTextField @bind-Value="Search"
Placeholder="@Localizer["Search by Name"]"
Variant="Variant.Outlined"
Clearable="true"
Immediate="true"
Margin="Margin.Dense"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium" />
</ToolBarContent>
<HeaderContent>
<MudTh>
<MudTableSortLabel T="User" SortBy="context => context.Baid">
@Localizer["User ID"]
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel T="User" SortBy="context => context.UserSetting.MyDonName">
@Localizer["Users"]
</MudTableSortLabel>
</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd Style="width: 100px">@context.Baid</MudTd>
<MudTd>
<MudButton StartIcon="@Icons.Material.Filled.EmojiPeople" OnClick="@(_ => Select(context))">@context.UserSetting.MyDonName</MudButton>
</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager RowsPerPageString=@Localizer["Rows Per Page:"] />
</PagerContent>
</MudTable>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">
@Localizer["Cancel"]
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; } = null!;
[Parameter] public int Exclude { get; set; } = 0;
private Dictionary<uint, User> userDict = new();
private string Search { get; set; } = string.Empty;
private string searchString = string.Empty;
protected override async Task OnInitializedAsync()
{
base.OnInitialized();
Dictionary<uint, User>? dict = await HttpClient.GetFromJsonAsync<Dictionary<uint, User>>($"api/Users/{Exclude}/AllUserDict");
dict.ThrowIfNull();
userDict = dict;
}
private bool FilterUser(User user)
{
var stringsToCheck = new List<string>
{
user.Baid + "",
user.UserSetting.MyDonName
};
if (!string.IsNullOrEmpty(Search) && !stringsToCheck.Any(s => s.Contains(Search, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
return true;
}
private void Select(User user)
{
MudDialog.Close(DialogResult.Ok(user));
}
private void Cancel()
{
MudDialog.Cancel();
}
}