1
0
mirror of synced 2024-11-23 22:41:01 +01:00

ChallengeCompetition Fix&Improve

This commit is contained in:
ptmaster 2024-09-17 03:07:13 +08:00
parent 984361dcbb
commit d5533248d7
7 changed files with 145 additions and 54 deletions

View File

@ -49,6 +49,18 @@ public class ChallengeCompeteManageController(IChallengeCompeteService challenge
return Ok(response);
}
[HttpGet("comp/{compId}")]
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
public async Task<ActionResult<ChallengeCompetitionResponse>> GetChallengeCompe(uint compId)
{
var data = await challengeCompeteService.GetFirstOrDefaultCompete(compId);
if (data == null) return BadRequest(new { Message = $"Compete(CompId={compId}) is Not Exist!"});
var challengeCompetition = Mappers.ChallengeCompeMappers.MapData(data);
challengeCompetition = await challengeCompeteService.FillData(challengeCompetition);
return Ok(challengeCompetition);
}
[HttpGet("test/{mode}")]
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
public ActionResult<List<ChallengeCompeteDatum>> testCreateCompete(uint mode)

View File

@ -4,6 +4,7 @@ using SharedProject.Models;
using SharedProject.Models.Responses;
using SharedProject.Utils;
using Throw;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
namespace TaikoLocalServer.Services;
@ -125,6 +126,14 @@ public class ChallengeCompeteService : IChallengeCompeteService
};
}
public Task<ChallengeCompeteDatum?> GetFirstOrDefaultCompete(uint compId)
{
return context.ChallengeCompeteData
.Include(e => e.Songs).ThenInclude(e => e.BestScores).Include(e => e.Participants)
.Where(c => c.CompId == compId)
.FirstOrDefaultAsync();
}
public async Task CreateCompete(uint baid, ChallengeCompeteCreateInfo challengeCompeteInfo)
{
ChallengeCompeteDatum challengeCompeteData = new()

View File

@ -13,6 +13,8 @@ public interface IChallengeCompeteService
public Task<ChallengeCompetitionResponse> GetChallengeCompetePage(CompeteModeType mode, uint baid, bool inProgress, int page, int limit, string? search);
public Task<ChallengeCompeteDatum> GetFirstOrDefaultCompete(uint compId);
public Task CreateCompete(uint baid, ChallengeCompeteCreateInfo challengeCompeteInfo);
public Task<bool> ParticipateCompete(uint compId, uint baid);

View File

@ -1,30 +1,38 @@
@inject IDialogService DialogService;
@using Blazored.LocalStorage
@inject HttpClient Client
@inject IDialogService DialogService;
@inject IGameDataService GameDataService
@inject ILocalStorageService LocalStorage
@if (ChallengeCompetition != null)
{
<MudCard>
<MudCardHeader>
<CardHeaderContent>
@if (ChallengeCompetition.CompeteMode == CompeteModeType.Chanllenge)
{
if (Baid == 0)
<MudStack Row="true" Spacing="1">
@if (ChallengeCompetition.CompeteMode == CompeteModeType.Chanllenge)
{
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@formatChallengeTitle(Localizer["FullChallengeTitle"])</MudText>
}
else if (ChallengeCompetition?.Baid != Baid)
{
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@formatChallengeTitle(Localizer["ReceiverChallengeTitle"])</MudText>
if (Baid == 0)
{
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@formatChallengeTitle(Localizer["FullChallengeTitle"])</MudText>
}
else if (ChallengeCompetition?.Baid != Baid)
{
<MudIcon Icon="@Icons.Material.Filled.MoveToInbox" Color="Color.Secondary" Style="margin-top: 4px;" />
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@formatChallengeTitle(Localizer["ReceiverChallengeTitle"])</MudText>
}
else
{
<MudIcon Icon="@Icons.Material.Filled.ForwardToInbox" Color="Color.Primary" Style="margin-top: 4px;" />
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@formatChallengeTitle(Localizer["CreatorChallengeTitle"])</MudText>
}
}
else
{
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@formatChallengeTitle(Localizer["CreatorChallengeTitle"])</MudText>
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@ChallengeCompetition?.CompeteName</MudText>
}
}
else
{
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@ChallengeCompetition?.CompeteName</MudText>
}
</MudStack>
<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>
@ -42,7 +50,9 @@
foreach (var song in ChallengeCompetition.Songs)
{
<div>
<MudButton Variant="Variant.Text" StartIcon=@Icons.Material.Filled.Audiotrack>@song.MusicDetail?.SongName</MudButton>
<MudButton Variant="Variant.Text" StartIcon=@Icons.Material.Filled.Audiotrack>
@GameDataService.GetMusicNameBySongId(MusicDetailDictionary, song.MusicDetail.SongId, SongNameLanguage)@(song.BestScores.Any(bs => bs.Baid == Baid) ? (" (" + Localizer["Played"] + ")") : "")
</MudButton>
</div>
}
}
@ -110,6 +120,25 @@
[Parameter] public ChallengeCompetition? ChallengeCompetition { get; set; }
[Parameter] public int Baid { get; set; }
[Parameter] public EventCallback<ChallengeCompetition> Refresh { get; set; }
[Parameter] public Dictionary<uint, MusicDetail>? MusicDetailDictionary { get; set; } = null;
[Parameter] public string? SongNameLanguage { get; set; } = null;
protected override async Task OnInitializedAsync()
{
base.OnInitialized();
if (SongNameLanguage == null) SongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
if (MusicDetailDictionary == null) MusicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
}
private string GetSongInfo(ChallengeCompetitionSong song)
{
var songName = GameDataService.GetMusicNameBySongId(MusicDetailDictionary, song.MusicDetail.SongId, SongNameLanguage);
if (song.BestScores.Any(bs => bs.Baid == Baid))
{
return songName + " (" + Localizer["Played"] + ")";
}
return songName;
}
private bool SelfHoldedChallengeCompetiton()
{

View File

@ -1,8 +1,12 @@
@inject HttpClient Client
@using Blazored.LocalStorage
@inject HttpClient Client
@inject AuthService AuthService
@inject IDialogService DialogService;
@inject IGameDataService GameDataService
@inject ILocalStorageService LocalStorage
@inject NavigationManager NavigationManager
@inject BreadcrumbsStateContainer BreadcrumbsStateContainer
@inject IDialogService DialogService;
@using TaikoWebUI.Components;
@using TaikoWebUI.Pages.Dialogs
@ -65,7 +69,11 @@
foreach (var challengeCompetition in response.List)
{
<MudItem xs="12" md="6" lg="4" xl="3">
<ChallengeCompe ChallengeCompetition="challengeCompetition" Baid="Baid" Refresh="UpdateCompete" />
<ChallengeCompe ChallengeCompetition="challengeCompetition"
MusicDetailDictionary="MusicDetailDictionary"
SongNameLanguage="SongNameLanguage"
Baid="Baid"
Refresh="UpdateCompete" />
</MudItem>
}
}
@ -105,6 +113,12 @@
[Parameter]
public int Mode { get; set; }
[Parameter]
public Dictionary<uint, MusicDetail>? MusicDetailDictionary { get; set; } = null;
[Parameter]
public string? SongNameLanguage { get; set; } = null;
private ChallengeCompetitionResponse? response = new();
private CancellationTokenSource? cts;
private int TotalPages { get; set; } = 0;
@ -114,7 +128,7 @@
private string? searchTerm = null;
private bool inProgress = false;
private async Task GetUsersData()
private async Task GetChallengeCompetitionData()
{
isLoading = true;
@ -127,7 +141,7 @@
private async Task UpdateCompete(ChallengeCompetition cc)
{
await GetUsersData();
await GetChallengeCompetitionData();
var updated = response?.List.Find(c => c.CompId == cc.CompId);
if (updated != null)
{
@ -139,6 +153,9 @@
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
if (SongNameLanguage == null) SongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
if (MusicDetailDictionary == null) MusicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
{
await AuthService.LoginWithAuthToken();
@ -146,18 +163,29 @@
if (AuthService.IsAdmin || !AuthService.LoginRequired)
{
await GetUsersData();
await GetChallengeCompetitionData();
}
BreadcrumbsStateContainer.breadcrumbs.Clear();
BreadcrumbsStateContainer.breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
if (Mode == 1)
{
BreadcrumbsStateContainer.breadcrumbs.Add(new BreadcrumbItem(Localizer["Challenge"], href: $"/ChallengeCompe/{Baid}/Challenge"));
}
else if (Mode == 2)
{
BreadcrumbsStateContainer.breadcrumbs.Add(new BreadcrumbItem(Localizer["Competition"], href: $"/ChallengeCompe/{Baid}/Competition"));
}
else if (Mode == 3)
{
BreadcrumbsStateContainer.breadcrumbs.Add(new BreadcrumbItem(Localizer["Official Competition"], href: $"/ChallengeCompe/{Baid}/OfficialCompetition"));
}
BreadcrumbsStateContainer.NotifyStateChanged();
}
private async Task OnPageChange(int page)
{
currentPage = page;
await GetUsersData();
await GetChallengeCompetitionData();
}
private async Task Debounce(Func<Task> action, int delayInMilliseconds)
@ -188,7 +216,7 @@
currentPage = 1;
// Debounce the GetUsersData method
await Debounce(GetUsersData, 500); // 500 milliseconds delay
await Debounce(GetChallengeCompetitionData, 500); // 500 milliseconds delay
}
private async Task OpenDialogAsync(int mode, int maxSongs, int maxDays = 30, int maxParticipant = 20)
@ -205,7 +233,7 @@
if (dialogRet != null)
{
var result = await dialogRet.GetReturnValueAsync<bool?>();
if (result != null && result == true) await GetUsersData();
if (result != null && result == true) await GetChallengeCompetitionData();
}
}
}

View File

@ -1,9 +1,12 @@
@using System.Net
@using TaikoWebUI.Utilities;
@using Blazored.LocalStorage
@using TaikoWebUI.Utilities
@inject HttpClient Client
@inject ISnackbar Snackbar
@inject IDialogService DialogService;
@inject IDialogService DialogService
@inject IGameDataService GameDataService
@inject ILocalStorageService LocalStorage
<MudDialog Style="width: 700px">
<TitleContent>
@ -36,7 +39,7 @@
{
<MudTextField ShrinkLabel @bind-Value="Info.Name" Label="@Localizer["Name"]" Counter="20" MaxLength="20" />
}
<MudTextField @bind-Value="Info.Desc" Label="@((Mode == 1 ? Localizer["Challenge"] : "") + Localizer["Describe"])" />
<MudTextField ShrinkLabel @bind-Value="Info.Desc" Label="@((Mode == 1 ? Localizer["Challenge"] : "") + " " + Localizer["Describe"])" />
@if (Mode == 1)
{
<MudStack Row="true">
@ -59,9 +62,10 @@
Difficulty difficulty = difficulties[song_idx];
<MudImage Src="@ScoreUtils.GetDifficultyIcon(difficulty)" Alt="@ScoreUtils.GetDifficultyTitle(difficulty)" Width="24" Height="48" Style="padding: 12px 0px 12px 0px; margin-right: 8px; vertical-align: middle;" />
}
<span style="vertical-align: middle; font-family: Nijiiro, sans-serif;">@(musicDetails[song_idx].SongId == 0 ? Localizer["No Select"] : musicDetails[song_idx].SongName)</span>
<MudButton StartIcon="@Icons.Material.Filled.Star" OnClick="@(_ => SelSong(song_idx))">@levels[song_idx]</MudButton>
<span style="vertical-align: middle; font-family: Nijiiro, sans-serif;">@(musicDetails[song_idx].SongId == 0 ? Localizer["No Select"] : GameDataService.GetMusicNameBySongId(MusicDetailDictionary, musicDetails[song_idx].SongId, SongNameLanguage))</span>
@if (levels[song_idx] > 0) {
<MudButton StartIcon="@Icons.Material.Filled.Star" OnClick="@(_ => SelSong(song_idx))">@levels[song_idx]</MudButton>
}
</MudField>
<MudIconButton Icon="@Icons.Material.Filled.Settings" Variant="Variant.Text" Color="Color.Primary" OnClick="(_ => OnExpandCollapseClick(song_idx))" />
@if (Info.challengeCompeteSongs.Count > 1)
@ -69,20 +73,20 @@
<MudIconButton Icon="@Icons.Material.Filled.Delete" Variant="Variant.Text" Color="Color.Error" OnClick="(_ => DelSong(song_idx))" />
}
</MudStack>
<MudCollapse Expanded="_expandeds[song_idx]">
<MudStack Row="true">
<MudSelect @bind-Value="song.IsVanishOn" Label=@Localizer["Vanish"] AnchorOrigin="Origin.BottomCenter">
<MudStack StretchItems="StretchItems.All" Row="true">
<MudSelect @bind-Value="song.IsVanishOn" Label=@Localizer["Vanish"] AnchorOrigin="Origin.BottomCenter" Style="width: 25%;">
<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" Style="width: 25%;">
<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" Style="width: 25%;">
<MudSelectItem Value="@(-1)">@Localizer["Any"]</MudSelectItem>
@for (uint idx = 0; idx < SpeedStrings.Length; idx++)
{
@ -90,7 +94,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" Style="width: 25%;">
<MudSelectItem Value="@(-1)">@Localizer["Any"]</MudSelectItem>
@foreach (var item in Enum.GetValues<RandomType>())
{
@ -142,6 +146,10 @@
[Parameter]
public ChallengeCompeteCreateInfo Info { get; set; } = new();
private Dictionary<uint, MusicDetail> MusicDetailDictionary = new();
private string? SongNameLanguage;
private static readonly string[] SpeedStrings =
{
"1.0", "1.1", "1.2", "1.3", "1.4",
@ -168,8 +176,9 @@
private bool OnlyPlayOnce = false;
protected override void OnInitialized()
protected override async Task OnInitializedAsync()
{
base.OnInitialized();
_expandeds = new bool[MaxSongs];
musicDetails = new MusicDetail[MaxSongs];
difficulties = new Difficulty[MaxSongs];
@ -181,6 +190,8 @@
levels[i] = 0;
}
Info.challengeCompeteSongs.Add(new());
SongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
MusicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
}
private void AddSong()
@ -192,7 +203,8 @@
{
var options = new DialogOptions { CloseOnEscapeKey = true };
var parameters = new DialogParameters();
parameters.Add("SelectedSong", musicDetails[i]);
parameters.Add("MusicDetailDictionary", MusicDetailDictionary);
parameters.Add("SongNameLanguage", SongNameLanguage);
var reference = await DialogService.ShowAsync<ChooseSongDialog>(Localizer["Select Song"], parameters, options);
if (reference != null)

View File

@ -7,7 +7,7 @@
<MudDialog Style="width: 1200px">
<DialogContent>
<MudTable Items="musicDetailDictionary.Values" Filter="@FilterSongs" @bind-SelectedItem="@SelectedSong" Height="40vh" Hover="true">
<MudTable Items="MusicDetailDictionary.Values" Filter="@FilterSongs" Height="40vh" Hover="true">
<ColGroup>
<col style="width: 50px;" />
<col />
@ -25,7 +25,7 @@
</ToolBarContent>
<HeaderContent>
<MudTh>
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicNameBySongId(musicDetailDictionary, context.SongId, SongNameLanguage)">
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicNameBySongId(MusicDetailDictionary, context.SongId, SongNameLanguage)">
@Localizer["Song Title"]
</MudTableSortLabel>
</MudTh>
@ -34,7 +34,7 @@
@if (difficulty is not Difficulty.None)
{
<MudTh>
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicStarLevel(musicDetailDictionary, context.SongId, difficulty)">
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicStarLevel(MusicDetailDictionary, context.SongId, difficulty)">
<img src="@ScoreUtils.GetDifficultyIcon(difficulty)" alt="@ScoreUtils.GetDifficultyTitle(difficulty)" style="@Constants.ICON_STYLE" />
</MudTableSortLabel>
</MudTh>
@ -44,18 +44,18 @@
<RowTemplate>
<MudTd Style="width:400px">
<MudText Typo="Typo.body2" Style="font-weight:bold">
@GameDataService.GetMusicNameBySongId(musicDetailDictionary, context.SongId, SongNameLanguage)
@GameDataService.GetMusicNameBySongId(MusicDetailDictionary, context.SongId, SongNameLanguage)
</MudText>
</MudTd>
@foreach (var difficulty in Enum.GetValues<Difficulty>())
{
@if (difficulty is not Difficulty.None)
{
var starLevel = GameDataService.GetMusicStarLevel(musicDetailDictionary, context.SongId, difficulty);
var starLevel = GameDataService.GetMusicStarLevel(MusicDetailDictionary, context.SongId, difficulty);
<MudTd>
@if (starLevel > 0)
{
<MudButton StartIcon="@Icons.Material.Filled.Star" OnClick="@(_ => Select(context, difficulty))">@starLevel</MudButton>
<MudButton StartIcon="@Icons.Material.Filled.Star" OnClick="@(_ => Select(context, difficulty, starLevel))">@starLevel</MudButton>
}
else
{
@ -83,11 +83,9 @@
[CascadingParameter] MudDialogInstance MudDialog { get; set; } = null!;
[Parameter] public MusicDetail SelectedSong { get; set; } = new();
[Parameter] public Dictionary<uint, MusicDetail>? MusicDetailDictionary { get; set; } = null;
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
private string? SongNameLanguage;
[Parameter] public string? SongNameLanguage { get; set; } = null;
private string Search { get; set; } = string.Empty;
@ -96,8 +94,8 @@
protected override async Task OnInitializedAsync()
{
base.OnInitialized();
SongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
if (SongNameLanguage == null) SongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
if (MusicDetailDictionary == null) MusicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
}
@ -119,12 +117,13 @@
return true;
}
private void Select(MusicDetail musicDetail, Difficulty difficulty)
private void Select(MusicDetail musicDetail, Difficulty difficulty, int level)
{
MudDialog.Close(DialogResult.Ok(new SongInfo()
{
MusicDetail = musicDetail,
Difficulty = difficulty
Difficulty = difficulty,
Level = level,
}));
}