Compare commits
4 Commits
c59762a392
...
RestructAs
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0d19ec6bb6 | ||
![]() |
439c8a2421 | ||
![]() |
6a65281850 | ||
![]() |
730b0ba04b |
@@ -1,10 +1,10 @@
|
||||
name: Tech
|
||||
name: TechAct
|
||||
|
||||
on: [push] # 当有新的push事件发生时触发此工作流程
|
||||
|
||||
jobs:
|
||||
explore-gitea-actions:
|
||||
runs-on: Tech
|
||||
runs-on: TechAct
|
||||
steps:
|
||||
- uses: actions/checkout@v4 # 使用actions/checkout来克隆您的仓库代码
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||
|
7
.vscode/launch.json
vendored
Normal file
7
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": []
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -34,9 +36,11 @@ namespace Entities.Contracts
|
||||
|
||||
public enum DifficultyLevel : byte
|
||||
{
|
||||
simple,
|
||||
easy,
|
||||
medium,
|
||||
hard
|
||||
hard,
|
||||
veryHard
|
||||
}
|
||||
|
||||
public enum QuestionType : byte
|
||||
@@ -55,47 +59,131 @@ namespace Entities.Contracts
|
||||
|
||||
public enum SubjectAreaEnum : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
Mathematics, // 数学
|
||||
Physics, // 物理
|
||||
Chemistry, // 化学
|
||||
Biology, // 生物
|
||||
History, // 历史
|
||||
Geography, // 地理
|
||||
[Display(Name = "未知", Description = "未知")]
|
||||
Unknown = 0,
|
||||
|
||||
[Display(Name = "数学", Description = "数")]
|
||||
Mathematics, // 数学
|
||||
|
||||
[Display(Name = "物理", Description = "物")]
|
||||
Physics, // 物理
|
||||
|
||||
[Display(Name = "化学", Description = "化")]
|
||||
Chemistry, // 化学
|
||||
|
||||
[Display(Name = "生物", Description = "生")]
|
||||
Biology, // 生物
|
||||
|
||||
[Display(Name = "历史", Description = "史")]
|
||||
History, // 历史
|
||||
|
||||
[Display(Name = "地理", Description = "地")]
|
||||
Geography, // 地理
|
||||
|
||||
[Display(Name = "语文", Description = "语")]
|
||||
Literature, // 语文/文学
|
||||
English, // 英语
|
||||
ComputerScience, // 计算机科学
|
||||
|
||||
[Display(Name = "英语", Description = "英")]
|
||||
English, // 英语
|
||||
|
||||
[Display(Name = "计算机科学", Description = "计")]
|
||||
ComputerScience // 计算机科学
|
||||
}
|
||||
|
||||
public enum AssignmentStructType : byte
|
||||
{
|
||||
[Display(Name = "根节点", Description = "根")]
|
||||
Root,
|
||||
[Display(Name = "单个问题", Description = "问")]
|
||||
Question,
|
||||
[Display(Name = "问题组", Description = "组")]
|
||||
Group,
|
||||
[Display(Name = "结构", Description = "结")]
|
||||
Struct,
|
||||
[Display(Name = "子问题", Description = "子")]
|
||||
SubQuestion,
|
||||
[Display(Name = "选项", Description = "选")]
|
||||
Option
|
||||
}
|
||||
|
||||
|
||||
public enum ExamType : byte
|
||||
{
|
||||
MidtermExam, // 期中
|
||||
FinalExam, // 期末
|
||||
MonthlyExam, // 月考
|
||||
WeeklyExam, // 周考
|
||||
DailyTest, // 平时测试
|
||||
AITest, // AI测试
|
||||
}
|
||||
[Display(Name = "期中考试", Description = "中")]
|
||||
MidtermExam,
|
||||
|
||||
[Display(Name = "期末考试", Description = "末")]
|
||||
FinalExam,
|
||||
|
||||
[Display(Name = "月考", Description = "月")]
|
||||
MonthlyExam,
|
||||
|
||||
[Display(Name = "周考", Description = "周")]
|
||||
WeeklyExam,
|
||||
|
||||
[Display(Name = "平时测试", Description = "平")]
|
||||
DailyTest,
|
||||
|
||||
[Display(Name = "AI测试", Description = "AI")]
|
||||
AITest,
|
||||
}
|
||||
|
||||
public enum SubmissionStatus
|
||||
{
|
||||
Pending, // 待提交/未开始
|
||||
Submitted, // 已提交
|
||||
Graded, // 已批改
|
||||
Resubmission, // 待重新提交 (如果允许)
|
||||
Late, // 迟交
|
||||
Draft, // 草稿
|
||||
[Display(Name = "待提交/未开始", Description = "待")]
|
||||
Pending,
|
||||
|
||||
[Display(Name = "已提交", Description = "提")]
|
||||
Submitted,
|
||||
|
||||
[Display(Name = "已批改", Description = "批")]
|
||||
Graded,
|
||||
|
||||
[Display(Name = "待重新提交", Description = "重")]
|
||||
Resubmission,
|
||||
|
||||
[Display(Name = "迟交", Description = "迟")]
|
||||
Late,
|
||||
|
||||
[Display(Name = "草稿", Description = "草")]
|
||||
Draft,
|
||||
}
|
||||
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static string GetDisplayName(this Enum enumValue)
|
||||
{
|
||||
var fieldInfo = enumValue.GetType().GetField(enumValue.ToString());
|
||||
|
||||
if (fieldInfo == null)
|
||||
{
|
||||
return enumValue.ToString();
|
||||
}
|
||||
|
||||
var displayAttribute = fieldInfo.GetCustomAttribute<DisplayAttribute>();
|
||||
|
||||
if (displayAttribute != null)
|
||||
{
|
||||
return displayAttribute.Name;
|
||||
}
|
||||
|
||||
return enumValue.ToString();
|
||||
}
|
||||
|
||||
public static string GetShortName(this Enum enumValue)
|
||||
{
|
||||
var memberInfo = enumValue.GetType().GetMember(enumValue.ToString()).FirstOrDefault();
|
||||
|
||||
if (memberInfo != null)
|
||||
{
|
||||
var displayAttribute = memberInfo.GetCustomAttribute<DisplayAttribute>();
|
||||
|
||||
if (displayAttribute != null && !string.IsNullOrEmpty(displayAttribute.Description))
|
||||
{
|
||||
return displayAttribute.Description;
|
||||
}
|
||||
}
|
||||
|
||||
return enumValue.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,12 +40,16 @@ namespace Entities.Contracts
|
||||
[Column("group_state")]
|
||||
public AssignmentStructType StructType { get; set; } = AssignmentStructType.Question;
|
||||
|
||||
public QuestionType Type { get; set; } = QuestionType.Unknown;
|
||||
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[Column("score")]
|
||||
public float? Score { get; set; }
|
||||
|
||||
public bool BCorrect { get; set; }
|
||||
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
|
24
Entities/Contracts/Global.cs
Normal file
24
Entities/Contracts/Global.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
[Table("global")]
|
||||
public class Global
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public SubjectAreaEnum Area { get; set; }
|
||||
|
||||
public string Info { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -38,6 +38,7 @@ namespace Entities.Contracts
|
||||
[Column("subject_area")]
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
|
||||
public string QType { get; set; } = string.Empty;
|
||||
|
||||
[Column("options")]
|
||||
public string? Options { get; set; }
|
||||
|
@@ -34,7 +34,7 @@ namespace Entities.Contracts
|
||||
public DateTime SubmissionTime { get; set; }
|
||||
|
||||
[Column("overall_grade")]
|
||||
public float? OverallGrade { get; set; }
|
||||
public float OverallGrade { get; set; } = 0;
|
||||
|
||||
[Column("overall_feedback")]
|
||||
public string? OverallFeedback { get; set; }
|
||||
|
@@ -15,8 +15,8 @@ namespace Entities.Contracts
|
||||
public string? RefreshToken { get; set; }
|
||||
public DateTime? RefreshTokenExpiryTime { get; set; }
|
||||
public string? Address { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
public string? DisplayName { get; set; }
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
@@ -17,6 +17,8 @@ namespace Entities.DTO
|
||||
public float Score { get; set; } = 0;
|
||||
public string Sequence { get; set; } = string.Empty;
|
||||
public bool BCorrect { get; set; } = true;
|
||||
public QuestionType Type { get; set; } = QuestionType.Unknown;
|
||||
public string QType { get; set; } = string.Empty;
|
||||
|
||||
public Layout Layout { get; set; } = Layout.horizontal;
|
||||
public AssignmentStructType StructType { get; set; } = AssignmentStructType.Question;
|
||||
|
23
Entities/DTO/GlobalDto.cs
Normal file
23
Entities/DTO/GlobalDto.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Entities.Contracts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.DTO
|
||||
{
|
||||
|
||||
public class GlobalDto
|
||||
{
|
||||
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
public string Data { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class QuestionDisplayTypeData
|
||||
{
|
||||
public string Color { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
}
|
||||
}
|
@@ -16,6 +16,7 @@ namespace Entities.DTO
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public QuestionType Type { get; set; } = QuestionType.Unknown;
|
||||
public string QType { get; set; } = string.Empty;
|
||||
|
||||
public string? Answer { get; set; } = string.Empty;
|
||||
|
||||
|
@@ -13,8 +13,9 @@ namespace Entities.DTO
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
public UInt32 ErrorQuestionNum { get; set; }
|
||||
public Dictionary<QuestionType, UInt32> ErrorQuestionTypes { get; set; } = new Dictionary<QuestionType, UInt32>();
|
||||
public Dictionary<string, UInt32> ErrorQuestionTypes { get; set; } = new Dictionary<string, UInt32>();
|
||||
public Dictionary<SubjectAreaEnum, UInt32> SubjectAreaErrorQuestionDis { get; set; } = new Dictionary<SubjectAreaEnum, UInt32>();
|
||||
public Dictionary<byte, UInt32> LessonErrorDis { get; set; } = new Dictionary<byte, UInt32>();
|
||||
public float Score { get; set; }
|
||||
}
|
||||
}
|
||||
|
41
Entities/DTO/StudentSubmissionDetailDto.cs
Normal file
41
Entities/DTO/StudentSubmissionDetailDto.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Entities.Contracts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Entities.DTO
|
||||
{
|
||||
public class StudentSubmissionDetailDto
|
||||
{
|
||||
// 基本信息
|
||||
public Guid Id { get; set; }
|
||||
public Guid AssignmentId { get; set; }
|
||||
public Guid StudentId { get; set; }
|
||||
public DateTime SubmissionTime { get; set; }
|
||||
public float OverallGrade { get; set; }
|
||||
public string OverallFeedback { get; set; } = string.Empty;
|
||||
public SubmissionStatus Status { get; set; }
|
||||
|
||||
// Assignment信息
|
||||
public AssignmentDto Assignment { get; set; } = new AssignmentDto();
|
||||
|
||||
// 错误分析
|
||||
public Dictionary<string, int> ErrorTypeDistribution { get; set; } = new Dictionary<string, int>();
|
||||
public Dictionary<string, float> ErrorTypeScoreDistribution { get; set; } = new Dictionary<string, float>();
|
||||
|
||||
// 成绩统计
|
||||
public int TotalRank { get; set; }
|
||||
public List<float> AllScores { get; set; } = new List<float>();
|
||||
public float AverageScore { get; set; }
|
||||
public float ClassAverageScore { get; set; }
|
||||
|
||||
// 课文分布
|
||||
public Dictionary<string, int> LessonErrorDistribution { get; set; } = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> KeyPointErrorDistribution { get; set; } = new Dictionary<string, int>();
|
||||
|
||||
// 基础统计
|
||||
public int TotalQuestions { get; set; }
|
||||
public int CorrectCount { get; set; }
|
||||
public int ErrorCount { get; set; }
|
||||
public float AccuracyRate { get; set; }
|
||||
}
|
||||
}
|
22
Entities/DTO/StudentSubmissionSummaryDto.cs
Normal file
22
Entities/DTO/StudentSubmissionSummaryDto.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace Entities.DTO
|
||||
{
|
||||
public class StudentSubmissionSummaryDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string AssignmentName { get; set; }
|
||||
public int ErrorCount { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public float Score { get; set; }
|
||||
public int TotalQuestions { get; set; }
|
||||
public string StudentName { get; set; }
|
||||
public string Status { get; set; }
|
||||
}
|
||||
|
||||
public class StudentSubmissionSummaryResponseDto
|
||||
{
|
||||
public List<StudentSubmissionSummaryDto> Submissions { get; set; }
|
||||
public int TotalCount { get; set; }
|
||||
}
|
||||
}
|
14
Entities/DTO/SubjectTypeMetadataDto.cs
Normal file
14
Entities/DTO/SubjectTypeMetadataDto.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Collections.Generic;
|
||||
using Entities.Contracts;
|
||||
|
||||
namespace Entities.DTO
|
||||
{
|
||||
public class SubjectTypeMetadataDto
|
||||
{
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
//public Dictionary<string, (string Color, string DisplayName)> Data = new Dictionary<string, (string Color, string DisplayName)>();
|
||||
|
||||
public string Data = string.Empty;
|
||||
}
|
||||
}
|
31
TechHelper.Client/Helper/Helper.cs
Normal file
31
TechHelper.Client/Helper/Helper.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using MudBlazor;
|
||||
|
||||
namespace TechHelper.Client.Helper
|
||||
{
|
||||
public static class Helper
|
||||
{
|
||||
public static Color GetColorFromInt(int value)
|
||||
{
|
||||
var v = value % Enum.GetValues(typeof(Color)).Length;
|
||||
switch (value)
|
||||
{
|
||||
case 1:
|
||||
return MudBlazor.Color.Primary;
|
||||
case 2:
|
||||
return MudBlazor.Color.Secondary;
|
||||
case 3:
|
||||
return MudBlazor.Color.Success;
|
||||
case 4:
|
||||
return MudBlazor.Color.Info;
|
||||
case 5:
|
||||
return MudBlazor.Color.Warning;
|
||||
case 6:
|
||||
return MudBlazor.Color.Error;
|
||||
case 7:
|
||||
return MudBlazor.Color.Dark;
|
||||
default:
|
||||
return MudBlazor.Color.Default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,83 +4,63 @@
|
||||
<MudSnackbarProvider />
|
||||
<MudPopoverProvider />
|
||||
|
||||
@*
|
||||
<MudPaper Style="position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-image: url('/ref/bg4.jpg');
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
filter: blur(10px);
|
||||
z-index: -1;">
|
||||
</MudPaper>
|
||||
<MudPaper Class="d-flex flex-column flex-grow-0 overflow-auto" Style="height: 100vh; background-color:#22222200">
|
||||
<MudLayout>
|
||||
<MudAppBar Elevation="0" Class="rounded-xl" Style="background-color: transparent; border:none">
|
||||
<MudBreakpointProvider>
|
||||
<MudHidden Breakpoint="Breakpoint.SmAndDown" Invert=true>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Primary" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||
</MudHidden>
|
||||
<MudHidden Breakpoint="Breakpoint.SmAndDown">
|
||||
<SearchBar></SearchBar>
|
||||
<MudButton Class="mt-1">application</MudButton>
|
||||
</MudHidden>
|
||||
</MudBreakpointProvider>
|
||||
<MudSpacer />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.MoreVert" Color="Color.Primary" Edge="Edge.End" />
|
||||
</MudAppBar>
|
||||
<MudDrawer @bind-Open="_drawerOpen" Height="100%" Elevation="0" Style="background-color:#f5f6fb">
|
||||
<MudDrawerHeader Class="h-100 d-flex flex-grow-1" Style="background-color:#f5f6fb">
|
||||
<MudPaper Width="250px" Class="d-flex py-3 flex-column justify-content-between rounded-xl" Elevation="3">
|
||||
<MudNavMenu Bordered="true" Dense="true" Rounded="true" Color="Color.Error" Margin="Margin.Dense">
|
||||
<ApplicationMainIconCard></ApplicationMainIconCard>
|
||||
<MudDivider Class="my-2" />
|
||||
<MudNavLink Href="/">Home</MudNavLink>
|
||||
<MudNavLink Href="/exam">Exam</MudNavLink>
|
||||
<MudNavLink Href="/students">Students</MudNavLink>
|
||||
|
||||
|
||||
<MudPaper Class="d-flex flex-column flex-grow-1 overflow-hidden" Style="background-color:transparent">
|
||||
|
||||
|
||||
<MudPaper Elevation="3" Height="10%" Class=" d-flex justify-content-around flex-grow-0" Style="background-color:#ffffff55">
|
||||
<NavBar Class="flex-column flex-grow-1 " Style="background-color:transparent" />
|
||||
<AuthLinks Class="flex-column flex-grow-0 " Style="background-color:transparent" />
|
||||
</MudPaper>
|
||||
|
||||
|
||||
<MudPaper Elevation="3" Class="d-flex flex-row flex-grow-1 overflow-hidden" Style="background-color:transparent">
|
||||
|
||||
|
||||
<MudPaper Width="10%" Class="pa-2 ma-1 d-flex flex-column flex-grow-0 justify-content-between" Style="background-color:#ffffffaa">
|
||||
<MudSpacer />
|
||||
<MudNavLink Class="align-content-end" Href="/about">About</MudNavLink>
|
||||
</MudNavMenu>
|
||||
<MudSpacer />
|
||||
<MudNavMenu Class="align-content-end " Bordered="true" Dense="true" Rounded="true" Margin="Margin.Dense">
|
||||
<TechHelper.Client.Pages.Global.LoginInOut.LoginInOut></TechHelper.Client.Pages.Global.LoginInOut.LoginInOut>
|
||||
<MudNavLink Class="align-content-end" Href="/Account/Manage">Setting</MudNavLink>
|
||||
</MudNavMenu>
|
||||
</MudPaper>
|
||||
|
||||
|
||||
<MudPaper Elevation="3" Class="d-flex flex-grow-1 pa-3 ma-1 overflow-hidden" Style="background-color:#ffffff22 ">
|
||||
@Body
|
||||
</MudDrawerHeader>
|
||||
</MudDrawer>
|
||||
<MudMainContent Style="background: #f5f6fb">
|
||||
<SnackErrorBoundary @ref="errorBoundary">
|
||||
<MudPaper Height="calc(100vh - 64px)" Style="background-color:transparent" Class="overflow-hidden px-1 py-2" Elevation="0">
|
||||
<MudPaper Style="background-color:transparent" Elevation="0" Class="d-flex w-100 h-100 overflow-hidden pa-2 rounded-xl">
|
||||
@Body
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
</SnackErrorBoundary>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
@code {
|
||||
ErrorBoundary? errorBoundary;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
errorBoundary?.Recover();
|
||||
}
|
||||
|
||||
bool _drawerOpen = true;
|
||||
|
||||
</MudPaper>
|
||||
|
||||
|
||||
</MudPaper>
|
||||
|
||||
|
||||
</MudPaper>
|
||||
|
||||
*@
|
||||
|
||||
<MudPaper Style="position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-image: url('/ref/bg4.jpg');
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
filter: blur(10px);
|
||||
z-index: -1;">
|
||||
</MudPaper>
|
||||
<MudPaper Style="background-color:transparent ; height:100vh" Class="overflow-hidden">
|
||||
|
||||
<MudPaper Class="justify-content-center" Style="background-color:blue; height: 50px">
|
||||
<MudStack Row="true" Class="justify-content-between">
|
||||
|
||||
<NavBar Class="flex-grow-1" Style="background-color:transparent; color:white" />
|
||||
<AuthLinks Class="justify-content-end " Style="background-color:transparent; color:white" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Class="d-flex flex-grow-0 " Style="background-color:#30303022; height:calc(100vh - 50px)">
|
||||
@* <MudPaper Class="ma-1" Width="200px">
|
||||
|
||||
</MudPaper> *@
|
||||
|
||||
<MudPaper Class="d-flex ma-1 flex-grow-1 overflow-auto">
|
||||
@Body
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
void DrawerToggle()
|
||||
{
|
||||
_drawerOpen = !_drawerOpen;
|
||||
}
|
||||
}
|
@@ -2,9 +2,9 @@
|
||||
|
||||
<MudGrid Class="h-100">
|
||||
|
||||
<MudItem xs="12" sm="2" Class="h-100 pa-1 mt-1">
|
||||
<MudItem sm="2" Class="h-100 pa-1 mt-1">
|
||||
<MudStack Class="h-100">
|
||||
<MudText Style="color:white"> 期中测试BETA版本 </MudText>
|
||||
<MudText Style="color:white"> BETA版本 </MudText>
|
||||
<MudText Style="color:white" Typo="Typo.h3"><b> 75 </b></MudText>
|
||||
|
||||
<MudPaper Elevation=0 Class="h-100 w-100" Style="background-color:transparent">
|
||||
@@ -12,13 +12,13 @@
|
||||
<MudPaper Elevation=0 Height="100%" Width="100%" Style="background-color:transparent">
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
TotalNumber:
|
||||
总数:
|
||||
<span style="color: #fefefe;">15</span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
TotalScore:
|
||||
总分:
|
||||
<span style="color: #fefefe;">15</span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
<MudPaper Elevation=0 Height="100%" Width="100%" Style="background-color:transparent">
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
中位数:
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
中位:
|
||||
<span style="color: #fefefe;">15</span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
@@ -44,7 +44,7 @@
|
||||
</MudItem>
|
||||
|
||||
|
||||
<MudItem xs="12" sm="9">
|
||||
<MudItem sm="9">
|
||||
<MudPaper Style="background-color:transparent" Class="w-100 mt-n3" Height="100%" Elevation="0">
|
||||
<MudChart ChartType="ChartType.Line" Class="pt-0" ChartSeries="@Series" XAxisLabels="@XAxisLabels" CanHideSeries
|
||||
Height="150px" Width="100%" AxisChartOptions="_axisChartOptions" ChartOptions="options">
|
||||
@@ -67,12 +67,6 @@
|
||||
<MudChipSet T="string" SelectedValuesChanged="HandleSelectedValuesChanged" SelectedValues="@_selected" SelectionMode="SelectionMode.MultiSelection" CheckMark="true">
|
||||
<MudChip Size="Size.Small" Text="类型错误数量分布" Variant="Variant.Text" Color="Color.Default">类型分布</MudChip>
|
||||
<MudChip Size="Size.Small" Text="类型错误成绩分布" Variant="Variant.Text" Color="Color.Primary">课时分布</MudChip>
|
||||
<MudChip Size="Size.Small" Text="pink" Variant="Variant.Text" Color="Color.Secondary">成绩趋势</MudChip>
|
||||
<MudChip Size="Size.Small" Text="blue" Variant="Variant.Text" Color="Color.Info">分值区间</MudChip>
|
||||
<MudChip Size="Size.Small" Text="green" Variant="Variant.Text" Color="Color.Success">Success</MudChip>
|
||||
<MudChip Size="Size.Small" Text="orange" Variant="Variant.Text" Color="Color.Warning">Warning</MudChip>
|
||||
<MudChip Size="Size.Small" Text="red" Variant="Variant.Text" Color="Color.Error">Error</MudChip>
|
||||
<MudChip Size="Size.Small" Text="black" Variant="Variant.Text" Color="Color.Dark">Dark</MudChip>
|
||||
</MudChipSet>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
191
TechHelper.Client/Pages/Common/Exam/SubmissionInfoCard.razor
Normal file
191
TechHelper.Client/Pages/Common/Exam/SubmissionInfoCard.razor
Normal file
@@ -0,0 +1,191 @@
|
||||
@using Entities.DTO
|
||||
@using TechHelper.Client.Services
|
||||
<MudPaper Class="rounded-xl w-100 px-10 ma-3 pt-5" Elevation="5" Height="170px" Style="background-color:#6bc6be">
|
||||
|
||||
<MudGrid Class="h-100">
|
||||
|
||||
<MudItem sm="2" Class="h-100 pa-1 mt-1">
|
||||
<MudStack Class="h-100">
|
||||
<MudText Style="color:white"> BETA版本 </MudText>
|
||||
<MudText Style="color:white" Typo="Typo.h3"><b> @StudentSubmissionDetail.AverageScore </b></MudText>
|
||||
|
||||
<MudPaper Elevation=0 Class="h-100 w-100" Style="background-color:transparent">
|
||||
<MudStack Class="h-100" Row=true>
|
||||
<MudPaper Elevation=0 Height="100%" Width="100%" Style="background-color:transparent">
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
总数:
|
||||
<span style="color: #fefefe;"> @StudentSubmissionDetail.TotalQuestions </span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
总分:
|
||||
<span style="color: #fefefe;"> 150 </span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Elevation=0 Height="100%" Width="100%" Style="background-color:transparent">
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
排名:
|
||||
<span style="color: #fefefe;"> @StudentSubmissionDetail.TotalRank </span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
平均:
|
||||
<span style="color: #fefefe;"> @StudentSubmissionDetail.ClassAverageScore </span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
|
||||
|
||||
<MudItem sm="9">
|
||||
<MudPaper Style="background-color:transparent" Class="w-100 mt-n3" Height="100%" Elevation="0">
|
||||
<MudChart ChartType="ChartType.Line" Class="pt-0" ChartSeries="@Series" XAxisLabels="@XAxisLabels" CanHideSeries
|
||||
Height="150px" Width="100%" AxisChartOptions="_axisChartOptions" ChartOptions="options">
|
||||
<CustomGraphics>
|
||||
<style>
|
||||
.heavy {
|
||||
font: normal 12px helvetica;
|
||||
fill: rgb(255,255,255);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<text x="60" y="15" class="heavy"> 成绩的整体分布情况 </text>
|
||||
</CustomGraphics>
|
||||
</MudChart>
|
||||
</MudPaper>
|
||||
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="1">
|
||||
<MudChipSet T="string" SelectedValuesChanged="HandleSelectedValuesChanged" SelectedValues="@_selected" SelectionMode="SelectionMode.MultiSelection" CheckMark="true">
|
||||
<MudChip Size="Size.Small" Text="类型错误数量分布" Variant="Variant.Text" Color="Color.Default">类型分布</MudChip>
|
||||
<MudChip Size="Size.Small" Text="类型错误成绩分布" Variant="Variant.Text" Color="Color.Primary">课时分布</MudChip>
|
||||
</MudChipSet>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
|
||||
@* <MudChip Size="Size.Small" Text="pink" Variant="Variant.Text" Color="Color.Secondary">成绩趋势</MudChip>
|
||||
<MudChip Size="Size.Small" Text="blue" Variant="Variant.Text" Color="Color.Info">分值区间</MudChip>
|
||||
<MudChip Size="Size.Small" Text="green" Variant="Variant.Text" Color="Color.Success">Success</MudChip>
|
||||
<MudChip Size="Size.Small" Text="orange" Variant="Variant.Text" Color="Color.Warning">Warning</MudChip>
|
||||
<MudChip Size="Size.Small" Text="red" Variant="Variant.Text" Color="Color.Error">Error</MudChip>
|
||||
<MudChip Size="Size.Small" Text="black" Variant="Variant.Text" Color="Color.Dark">Dark</MudChip> *@
|
||||
|
||||
@code {
|
||||
private AxisChartOptions _axisChartOptions = new AxisChartOptions
|
||||
{
|
||||
};
|
||||
private ChartOptions options = new ChartOptions
|
||||
{
|
||||
InterpolationOption = InterpolationOption.NaturalSpline,
|
||||
YAxisFormat = "c2",
|
||||
ShowLegend = false,
|
||||
YAxisLines = false,
|
||||
XAxisLines = false,
|
||||
XAxisLabelPosition = XAxisLabelPosition.None,
|
||||
YAxisLabelPosition = YAxisLabelPosition.None,
|
||||
YAxisTicks = 100,
|
||||
ShowLabels = false,
|
||||
ShowLegendLabels = false
|
||||
|
||||
};
|
||||
public List<ChartSeries> Series = new List<ChartSeries>()
|
||||
{
|
||||
new ChartSeries() { Name = "类型错误数量分布", Data = new double[] { 35, 41, 35, 51, 49, 62, 69, 91, 148 } },
|
||||
};
|
||||
public string[] XAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" };
|
||||
|
||||
Random random = new Random();
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
options.InterpolationOption = InterpolationOption.NaturalSpline;
|
||||
options.YAxisFormat = "c2";
|
||||
options.ShowLegend = false;
|
||||
options.YAxisLines = false;
|
||||
options.XAxisLines = false;
|
||||
options.XAxisLabelPosition = XAxisLabelPosition.None;
|
||||
options.YAxisLabelPosition = YAxisLabelPosition.None;
|
||||
options.ShowLabels = false;
|
||||
options.ShowLegendLabels = false;
|
||||
options.LineStrokeWidth = 1;
|
||||
_axisChartOptions.MatchBoundsToSize = true;
|
||||
|
||||
Series[0].LineDisplayType = LineDisplayType.Area;
|
||||
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public Guid SubmissionID { get; set; } = Guid.Empty;
|
||||
|
||||
private StudentSubmissionDetailDto StudentSubmissionDetail { get; set; } = new StudentSubmissionDetailDto();
|
||||
private IReadOnlyCollection<string> _selected;
|
||||
#pragma warning restore 1998
|
||||
#nullable restore
|
||||
#line (82, 8) - (143, 1) "D:\AllWX\AllC\TechHelper\TechHelper.Client\Pages\Common\Exam\SubmissionInfoCard.razor"
|
||||
|
||||
|
||||
|
||||
[Inject]
|
||||
public IStudentSubmissionDetailService StudentSubmissionDetailService { get; set; }
|
||||
[Inject]
|
||||
public ISnackbar Snackbar { get; set; }
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (SubmissionID != Guid.Empty)
|
||||
{
|
||||
|
||||
StudentSubmissionDetailDto result;
|
||||
try
|
||||
{
|
||||
result = await StudentSubmissionDetailService.GetSubmissionDetailAsync(SubmissionID);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
StudentSubmissionDetail = result;
|
||||
XAxisLabels = result.ErrorTypeDistribution.Keys.ToArray();
|
||||
Series.Clear();
|
||||
Series.Add(new ChartSeries
|
||||
{
|
||||
Name = "类型错误数量分布",
|
||||
Data = result.ErrorTypeDistribution.Values.Select(d => (double)d).ToArray()
|
||||
});
|
||||
Series.Add(new ChartSeries
|
||||
{
|
||||
Name = "类型错误成绩分布",
|
||||
Data = result.ErrorTypeScoreDistribution.Values.Select(d => (double)d).ToArray()
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"获取提交错误, 请重试, {ex.Message}", Severity.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void HandleSelectedValuesChanged(IReadOnlyCollection<string> selected)
|
||||
{
|
||||
Series.ForEach(x => x.Visible = false);
|
||||
|
||||
foreach (var item in selected)
|
||||
{
|
||||
var sv = Series.FirstOrDefault(predicate: x => x.Name == item);
|
||||
if (sv != null)
|
||||
{
|
||||
sv.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,143 @@
|
||||
<MudPaper Class="rounded-xl w-100 px-10 ma-3 pt-5" Elevation="5" Height="170px" Style="background-color:#6bc6be">
|
||||
|
||||
<MudGrid Class="h-100">
|
||||
|
||||
<MudItem xs="12" sm="2" Class="h-100 pa-1 mt-1">
|
||||
<MudStack Class="h-100">
|
||||
<MudText Style="color:white"> BETA版本 </MudText>
|
||||
<MudText Style="color:white" Typo="Typo.h3"><b> 75 </b></MudText>
|
||||
|
||||
<MudPaper Elevation=0 Class="h-100 w-100" Style="background-color:transparent">
|
||||
<MudStack Class="h-100" Row=true>
|
||||
<MudPaper Elevation=0 Height="100%" Width="100%" Style="background-color:transparent">
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
总数:
|
||||
<span style="color: #fefefe;">15</span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
总分:
|
||||
<span style="color: #fefefe;">15</span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Elevation=0 Height="100%" Width="100%" Style="background-color:transparent">
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
中位:
|
||||
<span style="color: #fefefe;">15</span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
<MudPaper Elevation=0 Height="50%" Style="background-color:transparent">
|
||||
<MudText Style="color:#9ed5f7" Typo="Typo.body2">
|
||||
方差:
|
||||
<span style="color: #fefefe;">15</span>
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
|
||||
|
||||
<MudItem xs="12" sm="9">
|
||||
<MudPaper Style="background-color:transparent" Class="w-100 mt-n3" Height="100%" Elevation="0">
|
||||
<MudChart ChartType="ChartType.Line" Class="pt-0" ChartSeries="@Series" XAxisLabels="@XAxisLabels" CanHideSeries
|
||||
Height="150px" Width="100%" AxisChartOptions="_axisChartOptions" ChartOptions="options">
|
||||
<CustomGraphics>
|
||||
<style>
|
||||
.heavy {
|
||||
font: normal 12px helvetica;
|
||||
fill: rgb(255,255,255);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<text x="60" y="15" class="heavy"> 成绩的整体分布情况 </text>
|
||||
</CustomGraphics>
|
||||
</MudChart>
|
||||
</MudPaper>
|
||||
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="1">
|
||||
<MudChipSet T="string" SelectedValuesChanged="HandleSelectedValuesChanged" SelectedValues="@_selected" SelectionMode="SelectionMode.MultiSelection" CheckMark="true">
|
||||
<MudChip Size="Size.Small" Text="类型错误数量分布" Variant="Variant.Text" Color="Color.Default">类型分布</MudChip>
|
||||
<MudChip Size="Size.Small" Text="类型错误成绩分布" Variant="Variant.Text" Color="Color.Primary">课时分布</MudChip>
|
||||
</MudChipSet>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
|
||||
@* <MudChip Size="Size.Small" Text="pink" Variant="Variant.Text" Color="Color.Secondary">成绩趋势</MudChip>
|
||||
<MudChip Size="Size.Small" Text="blue" Variant="Variant.Text" Color="Color.Info">分值区间</MudChip>
|
||||
<MudChip Size="Size.Small" Text="green" Variant="Variant.Text" Color="Color.Success">Success</MudChip>
|
||||
<MudChip Size="Size.Small" Text="orange" Variant="Variant.Text" Color="Color.Warning">Warning</MudChip>
|
||||
<MudChip Size="Size.Small" Text="red" Variant="Variant.Text" Color="Color.Error">Error</MudChip>
|
||||
<MudChip Size="Size.Small" Text="black" Variant="Variant.Text" Color="Color.Dark">Dark</MudChip> *@
|
||||
|
||||
@code {
|
||||
public double[] data = { 25, 77, 28, 5 };
|
||||
public string[] labels = { "Oil", "Coal", "Gas", "Biomass" };
|
||||
private AxisChartOptions _axisChartOptions = new AxisChartOptions
|
||||
{
|
||||
};
|
||||
private ChartOptions options = new ChartOptions
|
||||
{
|
||||
InterpolationOption = InterpolationOption.NaturalSpline,
|
||||
YAxisFormat = "c2",
|
||||
ShowLegend = false,
|
||||
YAxisLines = false,
|
||||
XAxisLines = false,
|
||||
XAxisLabelPosition = XAxisLabelPosition.None,
|
||||
YAxisLabelPosition = YAxisLabelPosition.None,
|
||||
YAxisTicks = 100,
|
||||
ShowLabels = false,
|
||||
ShowLegendLabels = false
|
||||
|
||||
};
|
||||
public List<ChartSeries> Series = new List<ChartSeries>()
|
||||
{
|
||||
new ChartSeries() { Name = "类型错误数量分布", Data = new double[] { 35, 41, 35, 51, 49, 62, 69, 91, 148 } },
|
||||
new ChartSeries() { Name = "类型错误成绩分布", Data = new double[] { 55, 21, 45, 11, 45, 23, 11, 56, 13 } },
|
||||
};
|
||||
public string[] XAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" };
|
||||
|
||||
Random random = new Random();
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
options.InterpolationOption = InterpolationOption.NaturalSpline;
|
||||
options.YAxisFormat = "c2";
|
||||
options.ShowLegend = false;
|
||||
options.YAxisLines = false;
|
||||
options.XAxisLines = false;
|
||||
options.XAxisLabelPosition = XAxisLabelPosition.None;
|
||||
options.YAxisLabelPosition = YAxisLabelPosition.None;
|
||||
options.ShowLabels = false;
|
||||
options.ShowLegendLabels = false;
|
||||
options.LineStrokeWidth = 1;
|
||||
_axisChartOptions.MatchBoundsToSize = true;
|
||||
|
||||
Series[0].LineDisplayType = LineDisplayType.Area;
|
||||
|
||||
}
|
||||
|
||||
private IReadOnlyCollection<string> _selected;
|
||||
|
||||
private void HandleSelectedValuesChanged(IReadOnlyCollection<string> selected)
|
||||
{
|
||||
Series.ForEach(x => x.Visible = false);
|
||||
|
||||
foreach(var item in selected)
|
||||
{
|
||||
var sv = Series.FirstOrDefault(predicate: x => x.Name == item);
|
||||
if(sv != null)
|
||||
{
|
||||
sv.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
TechHelper.Client/Pages/Common/ExamGlobalInfoDialog.razor
Normal file
34
TechHelper.Client/Pages/Common/ExamGlobalInfoDialog.razor
Normal file
@@ -0,0 +1,34 @@
|
||||
@using Entities.DTO
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<MudDialog Class="rounded-xl" Style="background-color: #dedede" >
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.h6">
|
||||
<MudIcon Icon="@Icons.Material.Filled.EditAttributes" Class="mr-3 mb-n1" />
|
||||
<b> 编辑属性 </b>
|
||||
</MudText>
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
<GlobalInfoCard AssignmentDto="Assignment"></GlobalInfoCard>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel">Cancel</MudButton>
|
||||
<MudButton Color="Color.Error" OnClick="Confirm">确认</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private IMudDialogInstance MudDialog { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public AssignmentDto Assignment { get; set; } = new AssignmentDto();
|
||||
|
||||
private void Cancel() => MudDialog.Cancel();
|
||||
|
||||
private void Confirm()
|
||||
{
|
||||
Snackbar.Add("属性已更新", Severity.Success);
|
||||
MudDialog.Close(DialogResult.Ok(Assignment));
|
||||
}
|
||||
}
|
37
TechHelper.Client/Pages/Common/GlobalInfoCard.razor
Normal file
37
TechHelper.Client/Pages/Common/GlobalInfoCard.razor
Normal file
@@ -0,0 +1,37 @@
|
||||
@using Entities.DTO
|
||||
@using Entities.Contracts
|
||||
@using Helper
|
||||
|
||||
<MudPaper Elevation=5 Class="w-100 pa-5 rounded-xl" Height="@Height" Style="@Style">
|
||||
<MudTextField Value="@AssignmentDto.Title"></MudTextField>
|
||||
<MudTextField Value="@AssignmentDto.Score">SCORE</MudTextField>
|
||||
<MudTextField Value="@AssignmentDto.TotalQuestions">NUMQUESTION</MudTextField>
|
||||
<MudChipSet T="SubjectAreaEnum" SelectedValue="@AssignmentDto.SubjectArea" CheckMark SelectionMode="SelectionMode.SingleSelection" SelectedValueChanged="HandleQTSelectedValueChanged">
|
||||
|
||||
@foreach (SubjectAreaEnum item in Enum.GetValues(typeof(SubjectAreaEnum)))
|
||||
{
|
||||
var color = Helper.GetColorFromInt((int)item);
|
||||
<MudChip Color=@color
|
||||
Value="@item">
|
||||
</MudChip>
|
||||
}
|
||||
</MudChipSet>
|
||||
<MudText>DUETIME</MudText>
|
||||
<MudText>EXAMTYPE</MudText>
|
||||
</MudPaper>
|
||||
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
|
||||
public AssignmentDto AssignmentDto { get; set; }
|
||||
[Parameter]
|
||||
public string Style { get; set; }
|
||||
[Parameter]
|
||||
public string Height { get; set; } = "auto";
|
||||
|
||||
public void HandleQTSelectedValueChanged(SubjectAreaEnum subject)
|
||||
{
|
||||
AssignmentDto.SubjectArea = subject;
|
||||
}
|
||||
}
|
@@ -31,4 +31,4 @@
|
||||
Snackbar.Add("属性已更新", Severity.Success);
|
||||
MudDialog.Close(DialogResult.Ok(Questions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<MudPaper Elevation=5 Class="w-100 rounded-xl" Height="@Height" Style="@Style">
|
||||
<MudPaper Elevation=1 Class="w-100 rounded-xl ma-2 pa-2" Height="@Height" Style="@Style">
|
||||
<MudPaper Elevation=0 Class="w-100 pa-2 align-content-center" Height="20%" Style="background-color:transparent"> @TitleContent </MudPaper>
|
||||
<MudPaper Elevation=0 Class="w-100 pa-2" Style="background-color:transparent" Height="60%"> @BodyContent </MudPaper>
|
||||
<MudPaper Elevation=0 Class="w-100 pa-2 align-content-center" Style="background-color:transparent" Height="20%"> @FooterContent </MudPaper>
|
||||
|
7
TechHelper.Client/Pages/Exam/AssignmentManagerCard.razor
Normal file
7
TechHelper.Client/Pages/Exam/AssignmentManagerCard.razor
Normal file
@@ -0,0 +1,7 @@
|
||||
<MudPaper>
|
||||
<MudText> ExamName </MudText>
|
||||
<MudText> 已经指派人数 </MudText>
|
||||
<MudText> 总人数 </MudText>
|
||||
<MudText> 平均S </MudText>
|
||||
<MudText> 指派 </MudText>
|
||||
</MudPaper>
|
@@ -1,5 +1,6 @@
|
||||
@using Entities.DTO
|
||||
@using Entities.Contracts
|
||||
@using Newtonsoft.Json
|
||||
@using TechHelper.Client.Exam
|
||||
@using TechHelper.Client.Pages.Exam.QuestionCard
|
||||
|
||||
@@ -12,12 +13,30 @@
|
||||
<MudTextField @bind-Value="AssignmentQuestion.Index" Label="Index" Variant="Variant.Text" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoFocus="true" />
|
||||
<MudTextField @bind-Value="AssignmentQuestion.Score" Label="Score" Variant="Variant.Text" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoFocus="true" />
|
||||
<MudChipSet T="AssignmentStructType" SelectedValue="AssignmentQuestion.StructType" CheckMark SelectionMode="SelectionMode.SingleSelection" SelectedValueChanged="HandleSelectedValueChanged">
|
||||
<MudChip Text="pink" Color="Color.Secondary" Value="@AssignmentStructType.Root">@AssignmentStructType.Root</MudChip>
|
||||
<MudChip Text="pink" Color="Color.Secondary" Value="@AssignmentStructType.Struct">@AssignmentStructType.Struct</MudChip>
|
||||
<MudChip Text="purple" Color="Color.Primary" Value="@AssignmentStructType.Group">@AssignmentStructType.Group</MudChip>
|
||||
<MudChip Text="blue" Color="Color.Info" Value="@AssignmentStructType.Question">@AssignmentStructType.Question</MudChip>
|
||||
<MudChip Text="green" Color="Color.Warning" Value="@AssignmentStructType.SubQuestion">@AssignmentStructType.SubQuestion</MudChip>
|
||||
<MudChip Text="orange" Color="Color.Error" Value="@AssignmentStructType.Option">@AssignmentStructType.Option</MudChip>
|
||||
</MudChipSet>
|
||||
|
||||
|
||||
<MudChipSet T="string" SelectedValue="@AssignmentQuestion.QType" CheckMark SelectionMode="SelectionMode.SingleSelection" SelectedValueChanged="HandleQTSelectedValueChanged">
|
||||
|
||||
@foreach (var item in QuestionTypes)
|
||||
{
|
||||
var qt = item;
|
||||
@* Style = "@($"background - color:{ item.Value.Color} ")"*@
|
||||
|
||||
<MudChip Style="@(qt.Key == AssignmentQuestion.QType ?
|
||||
$"background-color:#ffffff; color:{item.Value.Color}" :
|
||||
$"background-color:{item.Value.Color}; color:#ffffff")"
|
||||
Value="@item.Key">
|
||||
@item.Value.DisplayName
|
||||
</MudChip>
|
||||
}
|
||||
</MudChipSet>
|
||||
</MudPaper>
|
||||
@if (AssignmentQuestion.Question != null)
|
||||
{
|
||||
@@ -30,6 +49,10 @@
|
||||
[Parameter]
|
||||
public AssignmentQuestionDto AssignmentQuestion { get; set; } = new AssignmentQuestionDto();
|
||||
public QuestionDto TempQuesdto;
|
||||
Dictionary<string, QuestionDisplayTypeData> QuestionTypes = new Dictionary<string, QuestionDisplayTypeData>();
|
||||
|
||||
[Inject]
|
||||
private ILocalStorageService LocalStorageService { get; set; }
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
@@ -37,6 +60,30 @@
|
||||
{
|
||||
TempQuesdto = AssignmentQuestion.Question;
|
||||
}
|
||||
|
||||
var cs = LocalStorageService.GetItem<string>("GlobalInfo");
|
||||
var GlobalInfo = JsonConvert.DeserializeObject<Dictionary<string, QuestionDisplayTypeData>>(cs);
|
||||
if(GlobalInfo != null)
|
||||
{
|
||||
QuestionTypes = GlobalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleQTSelectedValueChanged(string type)
|
||||
{
|
||||
AssignmentQuestion.QType = type;
|
||||
if (AssignmentQuestion.ChildrenAssignmentQuestion.Count > 0 && AssignmentQuestion.StructType == AssignmentStructType.Group)
|
||||
{
|
||||
foreach (var item in AssignmentQuestion.ChildrenAssignmentQuestion)
|
||||
{
|
||||
item.QType = type;
|
||||
if (item.Question != null)
|
||||
{
|
||||
item.Question.QType = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void HandleSelectedValueChanged(AssignmentStructType type)
|
||||
|
@@ -1,5 +1,7 @@
|
||||
@page "/exam/create"
|
||||
@using AutoMapper
|
||||
@using Entities.Contracts
|
||||
@using Newtonsoft.Json
|
||||
@using TechHelper.Client.Pages.Common
|
||||
@using TechHelper.Client.Pages.Exam.ExamView
|
||||
@using TechHelper.Client.Services
|
||||
@@ -39,10 +41,12 @@
|
||||
<MudStack Class="flex-grow-1 h-100">
|
||||
|
||||
<MudPaper Class="rounded-xl ma-1 pa-2" Style="background-color:#fefefefe">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="OpenEditor">文本编辑器</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="ParseExam">载入</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="OpenPublish">发布</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="OpenPublish">指派</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="OpenEditor">文本编辑器</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="ParseExam">载入</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="OpenPublish">发布</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="OpenPublish">指派</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="OpenTest">Test</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Secondary" Class="rounded-xl" Size="Size.Small" OnClick="HandleGlobalInfo">GlobalExamInfo</MudButton>
|
||||
</MudPaper>
|
||||
|
||||
|
||||
@@ -84,11 +88,32 @@
|
||||
private ExamParserConfig _examParserConfig { get; set; } = new ExamParserConfig();
|
||||
private string EditorText = "";
|
||||
|
||||
[Inject]
|
||||
private ILocalStorageService LocalStorageService { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IMapper Mapper { get; set; }
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
var response = await NoteService.GetNote((byte)SubjectAreaEnum.Literature);
|
||||
|
||||
if (response.Status)
|
||||
{
|
||||
try
|
||||
{
|
||||
LocalStorageService.SetItem("GlobalInfo", response.Result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void OpenEditor()
|
||||
{
|
||||
var parameters = new DialogParameters<TextEditorDialog> { { x => x.TextEditor, _textEditor } };
|
||||
@@ -169,13 +194,43 @@
|
||||
[Inject]
|
||||
public IExamService examService { get; set; }
|
||||
|
||||
[Inject]
|
||||
public INoteService NoteService { get; set; }
|
||||
|
||||
|
||||
public async Task Publish()
|
||||
{
|
||||
var apiRespon = await examService.SaveParsedExam(ExamContent);
|
||||
Snackbar.Add(apiRespon.Message);
|
||||
}
|
||||
public async Task OpenTest()
|
||||
{
|
||||
Dictionary<string, (Color, string)> Note = new Dictionary<string, (Color, string)> { { "Hello", (Color.Surface, "World") }, { "My", (Color.Surface, "App") }, };
|
||||
var json = JsonConvert.SerializeObject(Note);
|
||||
var result = await NoteService.AddNote(new GlobalDto { SubjectArea = Entities.Contracts.SubjectAreaEnum.Physics, Data = json });
|
||||
|
||||
|
||||
|
||||
Console.WriteLine(json);
|
||||
var res = JsonConvert.DeserializeObject<Dictionary<string, (Color, string)>>(json);
|
||||
|
||||
}
|
||||
|
||||
private async void HandleGlobalInfo()
|
||||
{
|
||||
// _open = true;
|
||||
// _edit = true;
|
||||
// StateHasChanged();
|
||||
|
||||
var parameters = new DialogParameters<ExamGlobalInfoDialog> { { x => x.Assignment, ExamContent } };
|
||||
|
||||
var dialog = await DialogService.ShowAsync<ExamGlobalInfoDialog>("Exam_GlobalInfo", parameters);
|
||||
var result = await dialog.Result;
|
||||
if (!result.Canceled)
|
||||
{
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -21,8 +21,6 @@ else
|
||||
<MudPaper Class="d-flex flex-wrap flex-grow-0 gap-4" Height="100%" Width="100%">
|
||||
@foreach (var item in examDtos)
|
||||
{
|
||||
@* <ExamPreview AssignmentDto="item" Width="256px" Height="256px"> </ExamPreview> *@
|
||||
<AssignmentInfoCard></AssignmentInfoCard>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
@using Entities.Contracts
|
||||
@using Entities.DTO
|
||||
@using Newtonsoft.Json
|
||||
@using TechHelper.Client.Exam
|
||||
@using TechHelper.Client.Pages.Exam.QuestionCard
|
||||
|
||||
@@ -22,6 +23,11 @@
|
||||
<MudIconButton Color="Color.Tertiary" Icon="@Icons.Material.Filled.ExpandMore" Size="Size.Small" />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" aria-label="delete" Size="Size.Small" />
|
||||
<MudChip T="string" Color="Color.Info" Class="justify-content-end">@ExamStruct.StructType</MudChip>
|
||||
<MudChip T="string" Color="Color.Warning" Class="justify-content-end">@(ExamStruct.QType == string.Empty ? "" : QuestionTypes[ExamStruct.QType].DisplayName)</MudChip>
|
||||
@if(ExamStruct.Question!=null)
|
||||
{
|
||||
<MudRating SelectedValue="@((int)ExamStruct.Question.DifficultyLevel)" ReadOnly="true" Size="Size.Small" />
|
||||
}
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
@@ -75,6 +81,22 @@
|
||||
[Parameter]
|
||||
public string Style { get; set; } = "background-color : #eeeeee";
|
||||
|
||||
Dictionary<string, QuestionDisplayTypeData> QuestionTypes = new Dictionary<string, QuestionDisplayTypeData>();
|
||||
|
||||
[Inject]
|
||||
private ILocalStorageService LocalStorageService { get; set; }
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
var cs = LocalStorageService.GetItem<string>("GlobalInfo");
|
||||
var GlobalInfo = JsonConvert.DeserializeObject<Dictionary<string, QuestionDisplayTypeData>>(cs);
|
||||
if (GlobalInfo != null)
|
||||
{
|
||||
QuestionTypes = GlobalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private async void HandleClick()
|
||||
{
|
||||
await ClickedStruct.InvokeAsync(ExamStruct);
|
||||
@@ -84,4 +106,10 @@
|
||||
{
|
||||
await ClickedStruct.InvokeAsync(clickedChildExamStruct);
|
||||
}
|
||||
|
||||
private void HandleSelected(int num)
|
||||
{
|
||||
ExamStruct.Question.DifficultyLevel = (DifficultyLevel)num;
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +1,34 @@
|
||||
@page "/exam"
|
||||
@using TechHelper.Client.Pages.Student.BaseInfoCard
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<AuthorizeView Roles="Teacher">
|
||||
<Authorized>
|
||||
<MudPaper Class="rounded-xl ma-2 px-2 overflow-auto w-100 h-100">
|
||||
<StudentSubmissionPreviewTableCard />
|
||||
</MudPaper>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
|
||||
<MudText>HELLO WORLD</MudText>
|
||||
<AuthorizeView Roles="Student">
|
||||
<Authorized>
|
||||
<MudPaper Class="rounded-xl ma-2 px-2 overflow-auto w-100 h-100">
|
||||
<StudentSubmissionPreviewTableCard />
|
||||
</MudPaper>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
@code {
|
||||
|
||||
|
||||
[CascadingParameter]
|
||||
private Task<AuthenticationState> authenticationStateTask { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (authenticationStateTask is null)
|
||||
{
|
||||
NavigationManager.Refresh(forceReload: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,29 @@
|
||||
@using Entities.DTO
|
||||
@using Entities.Contracts
|
||||
@using Newtonsoft.Json
|
||||
@using TechHelper.Client.Exam
|
||||
|
||||
|
||||
<MudPaper Elevation="1" Class="ma-4 pa-5 rounded-xl">
|
||||
@* <MudText>@Question.Id</MudText> *@
|
||||
<MudText Class="mt-3" Typo="Typo.button"><b>问题属性</b></MudText>
|
||||
|
||||
<MudChipSet T="string" SelectedValue="@Question.QType" CheckMark SelectionMode="SelectionMode.SingleSelection" SelectedValueChanged="HandleQTSelectedValueChanged">
|
||||
|
||||
@foreach (var item in QuestionTypes)
|
||||
{
|
||||
var qt = item;
|
||||
@* Style = "@($"background - color:{ item.Value.Color} ")"*@
|
||||
|
||||
<MudChip Style="@(qt.Key == Question.QType ?
|
||||
$"background-color:#ffffff; color:{item.Value.Color}" :
|
||||
$"background-color:{item.Value.Color}; color:#ffffff")"
|
||||
Value="@item.Key">
|
||||
@item.Value.DisplayName
|
||||
</MudChip>
|
||||
}
|
||||
</MudChipSet>
|
||||
<MudRating SelectedValue="@(diffi)" SelectedValueChanged="HandleSelected" Size="Size.Small" />
|
||||
<MudTextField @bind-Value="Question.Title" Label="Title" Variant="Variant.Text" Margin="Margin.Dense" AutoGrow="true" />
|
||||
<MudTextField @bind-Value="Question.Answer" Label="Answer" Variant="Variant.Text" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoGrow="true" />
|
||||
<MudTextField @bind-Value="Question.Options" Label="Options" Variant="Variant.Text" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoGrow="true" />
|
||||
@@ -15,4 +34,35 @@
|
||||
@code {
|
||||
[Parameter]
|
||||
public QuestionDto Question { get; set; } = new QuestionDto();
|
||||
public int diffi = 0;
|
||||
Dictionary<string, QuestionDisplayTypeData> QuestionTypes = new Dictionary<string, QuestionDisplayTypeData>();
|
||||
|
||||
[Inject]
|
||||
private ILocalStorageService LocalStorageService { get; set; }
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
var cs = LocalStorageService.GetItem<string>("GlobalInfo");
|
||||
var GlobalInfo = JsonConvert.DeserializeObject<Dictionary<string, QuestionDisplayTypeData>>(cs);
|
||||
if (GlobalInfo != null)
|
||||
{
|
||||
QuestionTypes = GlobalInfo;
|
||||
}
|
||||
}
|
||||
private void HandleSelectedValueChanged(QuestionType type)
|
||||
{
|
||||
Question.Type = type;
|
||||
}
|
||||
|
||||
private void HandleSelected(int num)
|
||||
{
|
||||
Question.DifficultyLevel = (DifficultyLevel)num;
|
||||
}
|
||||
|
||||
private void HandleQTSelectedValueChanged(string type)
|
||||
{
|
||||
Question.QType = type;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
4
TechHelper.Client/Pages/Exam/StudentExamView.razor
Normal file
4
TechHelper.Client/Pages/Exam/StudentExamView.razor
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
@code {
|
||||
|
||||
}
|
32
TechHelper.Client/Pages/Global/LoginInOut/LoginInOut.razor
Normal file
32
TechHelper.Client/Pages/Global/LoginInOut/LoginInOut.razor
Normal file
@@ -0,0 +1,32 @@
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
@inject NavigationManager Navigation
|
||||
@inject IAuthenticationClientService AuthenticationClientService
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<MudText>
|
||||
Hello, @context.User.Identity.Name!
|
||||
</MudText>
|
||||
<MudButton OnClick="Logout"> LOGOUT </MudButton>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<MudButton Class="" Href="Login"> Login </MudButton>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private Task<AuthenticationState> authenticationStateTask { get; set; }
|
||||
|
||||
private async Task Logout()
|
||||
{
|
||||
await AuthenticationClientService.LogoutAsync();
|
||||
Navigation.NavigateTo("/");
|
||||
}
|
||||
|
||||
private void LoginIN()
|
||||
{
|
||||
Navigation.NavigateToLogin("/login");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
<MudPaper Class="d-flex flex-row my-3" Height="@Height" Width="@Width" Elevation="0">
|
||||
<MudIcon Icon="@Icons.Custom.Brands.MudBlazor" Color="Color.Primary" />
|
||||
<MudText Class="mx-3"><b>TechHelper</b></MudText>
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string Height { get; set; } = "30px";
|
||||
[Parameter]
|
||||
public string Width { get; set; } = "100%";
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<MudPaper Class="d-flex flex-grow-1 rounded-xl pl-6" Elevation="0">
|
||||
<MudTextField @bind-Value="TextValue" Label="Search for everything" Variant="Variant.Text"></MudTextField>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Search"></MudIconButton>
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
public string TextValue { get; set; }
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
@inherits ErrorBoundary
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
@if (CurrentException is null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else if (ErrorContent is not null)
|
||||
{
|
||||
@ErrorContent(CurrentException)
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="custom-error-ui">
|
||||
<MudAlert Severity="Severity.Error" Icon="@Icons.Material.Filled.Error">
|
||||
<MudText>组件加载或执行时出现了问题。</MudText>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Class="mt-3">
|
||||
重试
|
||||
</MudButton>
|
||||
</MudAlert>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
protected override async Task OnErrorAsync(Exception exception)
|
||||
{
|
||||
Snackbar.Add("操作失败,请重试或联系管理员。", Severity.Error);
|
||||
|
||||
await base.OnErrorAsync(exception);
|
||||
}
|
||||
|
||||
}
|
@@ -7,10 +7,6 @@
|
||||
<TechHelper.Client.Pages.Student.HomePage />
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
|
||||
<AssignmentInfoCard></AssignmentInfoCard>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private Task<AuthenticationState> authenticationStateTask { get; set; }
|
||||
|
@@ -0,0 +1,11 @@
|
||||
<MudPaper Class="d-flex my-3 flex-column justify-content-center mx-auto" Height="@Height" Width="@Width" Elevation="0">
|
||||
<MudImage Width="150" Height="150" Class="rounded-pill justify-content-center" Src="ref/Keda.png"></MudImage>
|
||||
<MudText Class="mx-3"><b>TechHelper</b></MudText>
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string Height { get; set; } = "250px";
|
||||
[Parameter]
|
||||
public string Width { get; set; } = "100%";
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
@using static TechHelper.Client.Pages.Student.BaseInfoCard.StudentSubmissionPreviewTableCard
|
||||
|
||||
|
||||
@if(StudentSubmission!=null)
|
||||
{
|
||||
<MudPaper Class="ma-2 pa-2 rounded-xl d-flex w-100 flex-nowrap">
|
||||
<MudText Class="flex-grow-0 flex-shrink-0" Style="width:60%"> @StudentSubmission.StudentName </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> @StudentSubmission.TotalProblems </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> @StudentSubmission.ErrorCount </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> @StudentSubmission.TimeSpent </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> @StudentSubmission.Score </MudText>
|
||||
</MudPaper>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudPaper Class="ma-1 pa-2 rounded-xl d-flex w-100 flex-nowrap">
|
||||
<MudText Class="flex-grow-0 flex-shrink-0" Style="width:60%"> 名称 </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> 题目总数 </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> 错误总数 </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> 时间 </MudText>
|
||||
<MudText Class="flex-grow-0 flex-shrink-0 text-start" Style="width:10%"> 得分 </MudText>
|
||||
</MudPaper>
|
||||
}
|
||||
@code{
|
||||
|
||||
[Parameter]
|
||||
public StudentSubmission StudentSubmission{ get; set; }
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
@using TechHelper.Client.Services
|
||||
@inject IStudentSubmissionService StudentSubmissionService
|
||||
|
||||
<MudPaper Class="ma-2 pa-2 rounded-xl d-flex flex-column flex-grow-1 overflow-auto" MaxHeight="100%">
|
||||
|
||||
<StudentSubmissionPreviewCard />
|
||||
@if (_isLoading)
|
||||
{
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: 200px;">
|
||||
<MudProgressCircular Color="Color.Primary" Size="Size.Large" />
|
||||
</div>
|
||||
}
|
||||
else if (_studentSubmissions == null || _studentSubmissions.Count == 0)
|
||||
{
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: 200px;">
|
||||
<MudText TextColor="Color.TextSecondary" Align="Align.Center">暂无提交记录</MudText>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var submission in _studentSubmissions)
|
||||
{
|
||||
<StudentSubmissionPreviewCard StudentSubmission="@submission" />
|
||||
}
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
// 学生提交数据模型
|
||||
public class StudentSubmission
|
||||
{
|
||||
public string StudentName { get; set; }
|
||||
public int TotalProblems { get; set; }
|
||||
public int ErrorCount { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public float Score { get; set; }
|
||||
public string AssignmentName { get; set; }
|
||||
public string Status { get; set; }
|
||||
public TimeSpan TimeSpent { get; set; }
|
||||
}
|
||||
|
||||
// 学生提交列表
|
||||
private List<StudentSubmission> _studentSubmissions = new();
|
||||
private bool _isLoading = true;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadStudentSubmissions();
|
||||
}
|
||||
|
||||
private async Task LoadStudentSubmissions()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isLoading = true;
|
||||
StateHasChanged();
|
||||
|
||||
var result = await StudentSubmissionService.GetMySubmissionsAsync();
|
||||
|
||||
if (result.Status && result.Result != null)
|
||||
{
|
||||
// 从服务器获取的数据映射到我们的模型
|
||||
var submissions = result.Result as List<Entities.DTO.StudentSubmissionSummaryDto>;
|
||||
|
||||
if (submissions != null)
|
||||
{
|
||||
_studentSubmissions = submissions.Select(submission => new StudentSubmission
|
||||
{
|
||||
AssignmentName = submission.AssignmentName,
|
||||
CreatedDate = submission.CreatedDate,
|
||||
ErrorCount = submission.ErrorCount,
|
||||
Score = submission.Score,
|
||||
StudentName = submission.StudentName,
|
||||
Status = submission.Status,
|
||||
TotalProblems = submission.TotalQuestions,
|
||||
TimeSpent = TimeSpan.FromMinutes(30) // 默认值,实际应用中可以从服务器获取
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果API调用失败,使用空列表
|
||||
_studentSubmissions = new List<StudentSubmission>();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 处理异常,可以记录日志
|
||||
_studentSubmissions = new List<StudentSubmission>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
@using MudBlazor
|
||||
@using System.Collections.Generic
|
||||
|
||||
<MudDataGrid Items="@Elements.Take(4)" Hover="@_hover" Dense="@_dense" Striped="@_striped" Bordered="@_bordered"
|
||||
RowStyleFunc="@_rowStyleFunc" RowClass="my-2 rounded-xl">
|
||||
<Columns >
|
||||
<PropertyColumn Property="x => x.Number" Title="Nr" />
|
||||
<PropertyColumn Property="x => x.Sign" />
|
||||
<PropertyColumn Property="x => x.Name" CellStyleFunc="@_cellStyleFunc" />
|
||||
<PropertyColumn Property="x => x.Position" />
|
||||
<PropertyColumn Property="x => x.Molar" Title="Molar mass" />
|
||||
</Columns>
|
||||
</MudDataGrid>
|
||||
|
||||
<div class="d-flex flex-wrap mt-4">
|
||||
<MudSwitch @bind-Value="_hover" Color="Color.Primary">Hover</MudSwitch>
|
||||
<MudSwitch @bind-Value="_dense" Color="Color.Secondary">Dense</MudSwitch>
|
||||
<MudSwitch @bind-Value="_striped" Color="Color.Tertiary">Striped</MudSwitch>
|
||||
<MudSwitch @bind-Value="_bordered" Color="Color.Warning">Bordered</MudSwitch>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
// Element类定义
|
||||
public class Element
|
||||
{
|
||||
public int Number { get; set; }
|
||||
public string Sign { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Position { get; set; }
|
||||
public decimal Molar { get; set; }
|
||||
}
|
||||
|
||||
// 示例数据
|
||||
private IEnumerable<Element> Elements = new List<Element>
|
||||
{
|
||||
new Element { Number = 1, Sign = "H", Name = "Hydrogen", Position = 1, Molar = 1.008m },
|
||||
new Element { Number = 2, Sign = "He", Name = "Helium", Position = 0, Molar = 4.0026m },
|
||||
new Element { Number = 3, Sign = "Li", Name = "Lithium", Position = 1, Molar = 6.94m },
|
||||
new Element { Number = 4, Sign = "Be", Name = "Beryllium", Position = 2, Molar = 9.0122m },
|
||||
new Element { Number = 5, Sign = "B", Name = "Boron", Position = 13, Molar = 10.81m }
|
||||
};
|
||||
|
||||
private bool _hover;
|
||||
private bool _dense;
|
||||
private bool _striped;
|
||||
private bool _bordered;
|
||||
|
||||
// 行样式函数:Position为0的行显示为斜体
|
||||
private Func<Element, int, string> _rowStyleFunc => (x, i) =>
|
||||
{
|
||||
if (x.Position == 0)
|
||||
return "font-style:italic";
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
// 单元格样式函数:根据元素编号设置背景色,根据摩尔质量设置字体粗细
|
||||
private Func<Element, string> _cellStyleFunc => x =>
|
||||
{
|
||||
string style = "";
|
||||
|
||||
if (x.Number == 1)
|
||||
style += "background-color:#8CED8C"; // 浅绿色
|
||||
|
||||
else if (x.Number == 2)
|
||||
style += "background-color:#E5BDE5"; // 浅紫色
|
||||
|
||||
else if (x.Number == 3)
|
||||
style += "background-color:#EACE5D"; // 浅黄色
|
||||
|
||||
else if (x.Number == 4)
|
||||
style += "background-color:#F1F165"; // 浅黄色
|
||||
|
||||
if (x.Molar > 5)
|
||||
style += ";font-weight:bold";
|
||||
|
||||
return style;
|
||||
};
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
<MudPaper Class="doc-section-component-container">
|
||||
<MudChart ChartType="ChartType.Bar" ChartSeries="@_series" Height="150px" Width="100%" XAxisLabels="@_xAxisLabels" AxisChartOptions="_axisChartOptions"></MudChart>
|
||||
</MudPaper>
|
||||
|
||||
@code{
|
||||
private string[] _xAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" };
|
||||
private AxisChartOptions _axisChartOptions = new AxisChartOptions
|
||||
{
|
||||
};
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_axisChartOptions.MatchBoundsToSize = true;
|
||||
}
|
||||
private List<ChartSeries> _series = new List<ChartSeries>()
|
||||
{
|
||||
new ChartSeries() { Name = "United States", Data = new double[] { 40, 20, 25, 27, 46, 60, 48, 80, 15 } }
|
||||
};
|
||||
}
|
@@ -1,141 +1,25 @@
|
||||
|
||||
@using TechHelper.Client.Pages.Common.Exam;
|
||||
@using TechHelper.Client.Pages.Student.BaseInfoCard;
|
||||
@using TechHelper.Client.Pages.Common;
|
||||
|
||||
<MudPaper Class="w-100 h-100 d-flex flex-row" Style="background-color: transparent" Elevation="0">
|
||||
<MudPaper Class="flex-grow-1 mx-2 d-flex flex-column" Style="background-color:transparent" Elevation="0">
|
||||
<SubmissionInfoCard ></SubmissionInfoCard>
|
||||
<MudPaper Class="d-flex flex-row" Style="background-color:transparent" Elevation="0">
|
||||
<NotifyCard></NotifyCard>
|
||||
<HomeworkCard></HomeworkCard>
|
||||
<NotifyCard></NotifyCard>
|
||||
<HomeworkCard></HomeworkCard>
|
||||
</MudPaper>
|
||||
<StudentSubmissionPreviewTableCard></StudentSubmissionPreviewTableCard>
|
||||
</MudPaper>
|
||||
<MudPaper Width="300px" Class="mx-2 align-content-center d-flex flex-column flex-grow-1" Style="background-color: transparent" Elevation="0">
|
||||
<HeadIconCard></HeadIconCard>
|
||||
<TotalErrorQuestionType></TotalErrorQuestionType>
|
||||
|
||||
<MudPaper Class="flex-grow-1 w-100 h-100 ma-auto">
|
||||
<MudGrid Class="w-100 h-100">
|
||||
<MudItem xs="12" sm="4">
|
||||
<MudPaper Style="background-color:transparent" Class="w-100 justify-content-center">
|
||||
<MudChart ChartType="ChartType.Donut" Width="200px" Height="200px" InputData="@data" InputLabels="@labels" Class="ma-auto">
|
||||
<CustomGraphics>
|
||||
<text class="donut-inner-text" x="50%" y="35%" dominant-baseline="middle" text-anchor="middle" fill="black" font-family="Helvetica" font-size="20">Total</text>
|
||||
<text class="donut-inner-text" x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" fill="black" font-family="Helvetica" font-size="50">@data.Sum().ToString()</text>
|
||||
</CustomGraphics>
|
||||
</MudChart>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Style="background-color:transparent" Class="w-100 pa-5">
|
||||
<TechHelper.Client.Pages.Common.SimpleCard Style="background-color:#ff4081">
|
||||
<BodyContent>
|
||||
<MudText>BodyContent</MudText>
|
||||
</BodyContent>
|
||||
<TitleContent>
|
||||
<MudText>TitleContent</MudText>
|
||||
</TitleContent>
|
||||
<FooterContent>
|
||||
<MudText>FooterContent</MudText>
|
||||
</FooterContent>
|
||||
</TechHelper.Client.Pages.Common.SimpleCard>
|
||||
|
||||
<TechHelper.Client.Pages.Common.SimpleCard Style="background-color:#1ec8a5">
|
||||
<BodyContent>
|
||||
<MudText>BodyContent</MudText>
|
||||
</BodyContent>
|
||||
<TitleContent>
|
||||
<MudText>TitleContent</MudText>
|
||||
</TitleContent>
|
||||
<FooterContent>
|
||||
<MudText>FooterContent</MudText>
|
||||
</FooterContent>
|
||||
</TechHelper.Client.Pages.Common.SimpleCard>
|
||||
|
||||
<TechHelper.Client.Pages.Common.SimpleCard Style="background-color:#4680ff">
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.body1">TitleContent</MudText>
|
||||
</TitleContent>
|
||||
<BodyContent>
|
||||
<MudText Typo="Typo.button"><b>BodyContent</b></MudText>
|
||||
</BodyContent>
|
||||
<FooterContent>
|
||||
<MudText Typo="Typo.body2">leran about this curson</MudText>
|
||||
</FooterContent>
|
||||
</TechHelper.Client.Pages.Common.SimpleCard>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="8">
|
||||
<MudPaper Style="background-color:transparent" Class="w-100 h-100">
|
||||
|
||||
<TechHelper.Client.Pages.Common.SimpleCard Style="background-color:#c2bef8" Height="350px">
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.button"><b>Visits Summary:</b></MudText>
|
||||
</TitleContent>
|
||||
<BodyContent>
|
||||
<MudChart ChartType="ChartType.Line" LegendPosition="Position.Left" Class="pt-55" ChartSeries="@Series" XAxisLabels="@XAxisLabels" Height="110%" Width="100%" AxisChartOptions="_axisChartOptions" ChartOptions="options"></MudChart>
|
||||
</BodyContent>
|
||||
<FooterContent>
|
||||
<MudText Typo="Typo.body2">leran about this curson</MudText>
|
||||
</FooterContent>
|
||||
</TechHelper.Client.Pages.Common.SimpleCard>
|
||||
|
||||
|
||||
@* <TechHelper.Client.Pages.Common.SimpleCard Style="background-color:#c2bef8" Height="100%">
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.button"><b>Visits Summary:</b></MudText>
|
||||
</TitleContent>
|
||||
<BodyContent>
|
||||
<MudDataGrid Items="@Elements" Filterable="true" FilterMode="@_filterMode" FilterCaseSensitivity="@_caseSensitivity">
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Number" Title="Nr" Filterable="false" />
|
||||
<PropertyColumn Property="x => x.Sign" />
|
||||
<PropertyColumn Property="x => x.Name" />
|
||||
<PropertyColumn Property="x => x.Position" Filterable="false" />
|
||||
<PropertyColumn Property="x => x.Molar" Title="Molar mass" />
|
||||
<PropertyColumn Property="x => x.Group" Title="Category" />
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="Element" />
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
</BodyContent>
|
||||
<FooterContent>
|
||||
<MudText Typo="Typo.body2">leran about this curson</MudText>
|
||||
</FooterContent>
|
||||
</TechHelper.Client.Pages.Common.SimpleCard> *@
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
public double[] data = { 25, 77, 28, 5 };
|
||||
public string[] labels = { "Oil", "Coal", "Gas", "Biomass" };
|
||||
private AxisChartOptions _axisChartOptions = new AxisChartOptions();
|
||||
private ChartOptions options = new ChartOptions();
|
||||
public List<ChartSeries> Series = new List<ChartSeries>()
|
||||
{
|
||||
new ChartSeries() { Name = "Series 1", Data = new double[] { 90, 79, 72, 69, 62, 62, 55, 65, 70 } },
|
||||
new ChartSeries() { Name = "Series 2", Data = new double[] { 35, 41, 35, 51, 49, 62, 69, 91, 148 } },
|
||||
};
|
||||
public string[] XAxisLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep" };
|
||||
|
||||
Random random = new Random();
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
options.InterpolationOption = InterpolationOption.NaturalSpline;
|
||||
options.YAxisFormat = "c2";
|
||||
_axisChartOptions.MatchBoundsToSize = true;
|
||||
}
|
||||
|
||||
public void RandomizeData()
|
||||
{
|
||||
foreach (var series in Series)
|
||||
{
|
||||
for (int i = 0; i < series.Data.Length - 1; i++)
|
||||
{
|
||||
series.Data[i] = random.NextDouble() * 100 + 10;
|
||||
}
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnClickMenu(InterpolationOption interpolationOption)
|
||||
{
|
||||
options.InterpolationOption = interpolationOption;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
12
TechHelper.Client/Pages/Student/HomeworkCard.razor
Normal file
12
TechHelper.Client/Pages/Student/HomeworkCard.razor
Normal file
@@ -0,0 +1,12 @@
|
||||
@using TechHelper.Client.Pages.Common;
|
||||
<SimpleCard>
|
||||
<TitleContent>
|
||||
<MudText> 作业</MudText>
|
||||
</TitleContent>
|
||||
<BodyContent>
|
||||
<MudText> 你暂时还没有任何作业 </MudText>
|
||||
</BodyContent>
|
||||
</SimpleCard>
|
||||
@code {
|
||||
|
||||
}
|
12
TechHelper.Client/Pages/Student/NotifyCard.razor
Normal file
12
TechHelper.Client/Pages/Student/NotifyCard.razor
Normal file
@@ -0,0 +1,12 @@
|
||||
@using TechHelper.Client.Pages.Common;
|
||||
<SimpleCard>
|
||||
<TitleContent>
|
||||
<MudText> 通知</MudText>
|
||||
</TitleContent>
|
||||
<BodyContent>
|
||||
<MudText> 暂时没有任何通知</MudText>
|
||||
</BodyContent>
|
||||
</SimpleCard>
|
||||
@code {
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
@page "/studentSubmissionView"
|
||||
@using TechHelper.Client.Pages.Student.BaseInfoCard
|
||||
|
||||
|
||||
|
||||
<MudPaper Class="rounded-xl ma-2 px-2 overflow-auto">
|
||||
<TechHelper.Client.Pages.Common.ExamGlobalInfoDialog>
|
||||
|
||||
</TechHelper.Client.Pages.Common.ExamGlobalInfoDialog>
|
||||
<StudentSubmissionPreviewTableCard />
|
||||
</MudPaper>
|
3
TechHelper.Client/Pages/Teacher/ExamDetailView.razor
Normal file
3
TechHelper.Client/Pages/Teacher/ExamDetailView.razor
Normal file
@@ -0,0 +1,3 @@
|
||||
<MudPaper>
|
||||
<MudText> EXAM NAME</MudText>
|
||||
</MudPaper>
|
14
TechHelper.Client/Pages/Teacher/StudentCard.razor
Normal file
14
TechHelper.Client/Pages/Teacher/StudentCard.razor
Normal file
@@ -0,0 +1,14 @@
|
||||
@using Entities.DTO
|
||||
<h3>StudentCard</h3>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public StudentDto StudentDto{ get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -6,7 +6,9 @@
|
||||
|
||||
@foreach(var cs in ClassStudents)
|
||||
{
|
||||
<MudText> @cs.DisplayName </MudText>
|
||||
<StudentCard StudentDto="@cs">
|
||||
</StudentCard>
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -39,12 +39,15 @@ builder.Services.AddLocalStorageServices();
|
||||
|
||||
builder.Services.AddScoped<IAuthenticationClientService, AuthenticationClientService>();
|
||||
builder.Services.AddScoped<IExamService, ExamService>();
|
||||
builder.Services.AddScoped<IStudentSubmissionService, StudentSubmissionService>();
|
||||
builder.Services.AddScoped<IStudentSubmissionDetailService, StudentSubmissionDetailService>();
|
||||
builder.Services.AddScoped<AuthenticationStateProvider, AuthStateProvider>();
|
||||
builder.Services.AddScoped<IRefreshTokenService, RefreshTokenService>();
|
||||
builder.Services.AddScoped<IClassServices, ClasssServices>();
|
||||
builder.Services.AddScoped<IEmailSender, QEmailSender>();
|
||||
builder.Services.AddScoped<HttpInterceptorHandlerService>();
|
||||
builder.Services.AddScoped<IAIService, AiService>();
|
||||
builder.Services.AddScoped<INoteService, NoteService>();
|
||||
builder.Services.AddScoped<IUserServices, UserServices>();
|
||||
builder.Services.AddHttpClient("WebApiClient", client =>
|
||||
{
|
||||
|
@@ -20,7 +20,16 @@ namespace TechHelper.Client.Services
|
||||
|
||||
public Task<ResponseDto> CreateClass(UserRegistrationToClassDto userClass)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
try
|
||||
{
|
||||
return Task.FromResult(new ResponseDto { IsSuccessfulRegistration = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 实际应用中,这里应该加入日志记录
|
||||
Console.WriteLine($"Error in CreateClass: {ex.Message}");
|
||||
return Task.FromResult(new ResponseDto { IsSuccessfulRegistration = false, Errors = new string[] { ex.Message } });
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetClassStudents()
|
||||
@@ -54,6 +63,29 @@ namespace TechHelper.Client.Services
|
||||
}
|
||||
}
|
||||
|
||||
public StudentDto GetStudents(byte Class)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _client.PostAsJsonAsync("class/getClassStudents", Class);
|
||||
var content = result.Result.Content.ReadAsStringAsync();
|
||||
if (content.Result != null)
|
||||
{
|
||||
var users = JsonConvert.DeserializeObject<StudentDto>(content.Result);
|
||||
return users;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new StudentDto();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"获取失败,{ex.Message}, InnerException: {ex.InnerException}");
|
||||
return new StudentDto();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResponseDto> UserRegister(UserRegistrationToClassDto userRegistrationToClassDto)
|
||||
{
|
||||
try
|
||||
|
@@ -10,5 +10,6 @@ namespace TechHelper.Client.Services
|
||||
public Task<ResponseDto> CreateClass(UserRegistrationToClassDto userClass);
|
||||
public Task<ApiResponse> GetClassStudents();
|
||||
public Task<ApiResponse> GetGradeClasses(byte grade);
|
||||
public StudentDto GetStudents(byte Class);
|
||||
}
|
||||
}
|
||||
|
14
TechHelper.Client/Services/INoteService.cs
Normal file
14
TechHelper.Client/Services/INoteService.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public interface INoteService
|
||||
{
|
||||
public Task<ApiResponse> AddNote(GlobalDto dto);
|
||||
public Task<ApiResponse> DeleteNote(byte id);
|
||||
public Task<ApiResponse> GetAllNotes();
|
||||
public Task<ApiResponse> GetNote(byte id);
|
||||
public Task<ApiResponse> UpdateNote(GlobalDto dto);
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public interface IStudentSubmissionDetailService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取学生提交的详细信息
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <returns>学生提交详细信息</returns>
|
||||
Task<StudentSubmissionDetailDto> GetSubmissionDetailAsync(Guid submissionId);
|
||||
}
|
||||
}
|
22
TechHelper.Client/Services/IStudentSubmissionService.cs
Normal file
22
TechHelper.Client/Services/IStudentSubmissionService.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public interface IStudentSubmissionService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取当前学生的所有提交摘要
|
||||
/// </summary>
|
||||
/// <returns>学生提交摘要列表</returns>
|
||||
Task<ApiResponse> GetMySubmissionsAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前学生的提交摘要(分页)
|
||||
/// </summary>
|
||||
/// <param name="pageNumber">页码,默认为1</param>
|
||||
/// <param name="pageSize">每页数量,默认为10</param>
|
||||
/// <returns>分页的学生提交摘要列表</returns>
|
||||
Task<ApiResponse> GetMySubmissionsPagedAsync(int pageNumber = 1, int pageSize = 10);
|
||||
}
|
||||
}
|
151
TechHelper.Client/Services/NoteService.cs
Normal file
151
TechHelper.Client/Services/NoteService.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using Entities.DTO;
|
||||
using System.Net.Http.Json;
|
||||
using TechHelper.Client.AI;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public class NoteService : INoteService
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public NoteService(HttpClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个新笔记
|
||||
/// </summary>
|
||||
/// <param name="dto">包含笔记数据的数据传输对象</param>
|
||||
/// <returns>操作结果</returns>
|
||||
public async Task<ApiResponse> AddNote(GlobalDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.PostAsJsonAsync("note", dto);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<ApiResponse>();
|
||||
return result ?? ApiResponse.Success("操作成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error($"添加失败。状态码: {response.StatusCode}。详情: {errorContent}");
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
return ApiResponse.Error($"网络请求错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 ID 删除一个笔记
|
||||
/// </summary>
|
||||
/// <param name="id">要删除的笔记的 ID</param>
|
||||
/// <returns>操作结果</returns>
|
||||
public async Task<ApiResponse> DeleteNote(byte id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.DeleteAsync($"note/{id}");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<ApiResponse>();
|
||||
return result ?? ApiResponse.Success("删除成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error($"删除失败。状态码: {response.StatusCode}。详情: {errorContent}");
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
return ApiResponse.Error($"网络请求错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有笔记
|
||||
/// </summary>
|
||||
/// <returns>包含所有笔记列表的操作结果</returns>
|
||||
public async Task<ApiResponse> GetAllNotes()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.GetAsync("note");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<ApiResponse>();
|
||||
return result ?? ApiResponse.Success("获取成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error($"获取失败。状态码: {response.StatusCode}。详情: {errorContent}");
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
return ApiResponse.Error($"网络请求错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 ID 获取单个笔记
|
||||
/// </summary>
|
||||
/// <param name="id">要获取的笔记的 ID</param>
|
||||
/// <returns>包含单个笔记数据的操作结果</returns>
|
||||
public async Task<ApiResponse> GetNote(byte id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.GetAsync($"note/{id}");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<ApiResponse>();
|
||||
return result ?? ApiResponse.Success("获取成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error($"获取失败。状态码: {response.StatusCode}。详情: {errorContent}");
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
return ApiResponse.Error($"网络请求错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateNote(GlobalDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.PutAsJsonAsync("note", dto);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<ApiResponse>();
|
||||
return result ?? ApiResponse.Success("更新成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error($"更新失败。状态码: {response.StatusCode}。详情: {errorContent}");
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
return ApiResponse.Error($"网络请求错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
TechHelper.Client/Services/StudentSubmissionDetailService.cs
Normal file
26
TechHelper.Client/Services/StudentSubmissionDetailService.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Client.HttpRepository;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public class StudentSubmissionDetailService : IStudentSubmissionDetailService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public StudentSubmissionDetailService(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<StudentSubmissionDetailDto> GetSubmissionDetailAsync(Guid submissionId)
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"api/student-submission-detail/{submissionId}");
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return await response.Content.ReadFromJsonAsync<StudentSubmissionDetailDto>();
|
||||
}
|
||||
throw new HttpRequestException($"获取学生提交详细信息失败: {response.StatusCode}");
|
||||
}
|
||||
}
|
||||
}
|
75
TechHelper.Client/Services/StudentSubmissionService.cs
Normal file
75
TechHelper.Client/Services/StudentSubmissionService.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
using System.Net.Http.Json;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public class StudentSubmissionService : IStudentSubmissionService
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public StudentSubmissionService(HttpClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前学生的所有提交摘要
|
||||
/// </summary>
|
||||
/// <returns>学生提交摘要列表</returns>
|
||||
public async Task<ApiResponse> GetMySubmissionsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.GetAsync("student-submission/my-submissions");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var submissions = JsonConvert.DeserializeObject<List<StudentSubmissionSummaryDto>>(content);
|
||||
return ApiResponse.Success(result: submissions);
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error(message: $"获取学生提交信息失败: {response.StatusCode} - {errorContent}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error(message: $"内部错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前学生的提交摘要(分页)
|
||||
/// </summary>
|
||||
/// <param name="pageNumber">页码,默认为1</param>
|
||||
/// <param name="pageSize">每页数量,默认为10</param>
|
||||
/// <returns>分页的学生提交摘要列表</returns>
|
||||
public async Task<ApiResponse> GetMySubmissionsPagedAsync(int pageNumber = 1, int pageSize = 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.GetAsync($"student-submission/my-submissions-paged?pageNumber={pageNumber}&pageSize={pageSize}");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<StudentSubmissionSummaryResponseDto>(content);
|
||||
return ApiResponse.Success(result: result);
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error(message: $"获取学生提交信息失败: {response.StatusCode} - {errorContent}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error(message: $"内部错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,16 +1,44 @@
|
||||
@inherits LayoutComponentBase
|
||||
@layout AccountLayout
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<AuthorizeView Roles="Teacher">
|
||||
<Authorized>
|
||||
<MudPaper Class="d-flex flex-row flex-grow-1 overflow-hidden" Height="100%">
|
||||
<MudPaper Width="200px">
|
||||
<MudDivider Class="flex-grow-0" />
|
||||
<ExamNavMenu />
|
||||
</MudPaper>
|
||||
<MudPaper Class="d-flex flex-grow-1 overflow-auto">
|
||||
@Body
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
<MudPaper Class="d-flex flex-row flex-grow-1 overflow-hidden" Height="100%">
|
||||
<AuthorizeView Roles="Student">
|
||||
<Authorized>
|
||||
<MudPaper Class="d-flex flex-row flex-grow-1 overflow-hidden" Height="100%">
|
||||
<MudPaper Width="200px">
|
||||
<MudDivider Class="flex-grow-0" />
|
||||
<ExamNavMenu />
|
||||
</MudPaper>
|
||||
<MudPaper Class="d-flex h-100 w-100 flex-grow-1 overflow-auto">
|
||||
@Body
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
<MudPaper Width="200px">
|
||||
<MudDivider Class="flex-grow-0" />
|
||||
<ExamNavMenu />
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private Task<AuthenticationState> authenticationStateTask { get; set; }
|
||||
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Class="flex-grow-1 overflow-auto">
|
||||
@Body
|
||||
</MudPaper>
|
||||
</MudPaper>
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (authenticationStateTask is null)
|
||||
{
|
||||
NavigationManager.Refresh(forceReload: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,22 +1,39 @@
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
|
||||
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="exam/create" Match="NavLinkMatch.All">创建</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="exam/manage">管理</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/ChangePassword">Password</NavLink>
|
||||
</li>
|
||||
@* <li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/TwoFactorAuthentication">Two-factor authentication</NavLink>
|
||||
</li> *@
|
||||
</ul>
|
||||
|
||||
<AuthorizeView Roles="Teacher">
|
||||
<Authorized>
|
||||
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="exam/create" Match="NavLinkMatch.All">创建</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="exam/manage">管理</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/ChangePassword">Password</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
|
||||
<AuthorizeView Roles="Student">
|
||||
<Authorized>
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="exam/studentHomework" Match="NavLinkMatch.All">Homework</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="exam/manage">管理</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
@code {
|
||||
private bool hasExternalLogins;
|
||||
private bool hasExternalLogins;
|
||||
|
||||
}
|
||||
|
@@ -9,3 +9,17 @@
|
||||
@Body
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private Task<AuthenticationState> authenticationStateTask { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (authenticationStateTask is null)
|
||||
{
|
||||
// NavigationManager.Refresh(forceReload: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,11 +9,8 @@
|
||||
<NavLink class="nav-link" href="Account/Manage/Class">Class</NavLink>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/ChangePassword">Password</NavLink>
|
||||
<NavLink class="nav-link" href="Account/Manage/ChangePassword">重设密码</NavLink>
|
||||
</li>
|
||||
@* <li class="nav-item">
|
||||
<NavLink class="nav-link" href="Account/Manage/TwoFactorAuthentication">Two-factor authentication</NavLink>
|
||||
</li> *@
|
||||
</ul>
|
||||
|
||||
@code {
|
||||
|
@@ -19,4 +19,5 @@
|
||||
@using TechHelper.Client.HttpRepository
|
||||
@using TechHelper.Client.Pages.Author
|
||||
@using TechHelper.Client.Pages
|
||||
@using Blazored.TextEditor
|
||||
@using Blazored.TextEditor
|
||||
@using TechHelper.Client.Pages.Global.MainStruct
|
@@ -36,6 +36,11 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.js"></script>
|
||||
<script src="_content/Blazored.TextEditor/quill-blot-formatter.min.js"></script>
|
||||
<script src="_content/Blazored.TextEditor/Blazored-BlazorQuill.js"></script>
|
||||
<script async
|
||||
defer
|
||||
src="https://maxkb.eazygame.cn/chat/api/embed?protocol=https&host=maxkb.eazygame.cn&token=be77837293de870e">
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
|
BIN
TechHelper.Client/wwwroot/ref/Buou.png
Normal file
BIN
TechHelper.Client/wwwroot/ref/Buou.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
TechHelper.Client/wwwroot/ref/Caiq.png
Normal file
BIN
TechHelper.Client/wwwroot/ref/Caiq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
TechHelper.Client/wwwroot/ref/Hasq.png
Normal file
BIN
TechHelper.Client/wwwroot/ref/Hasq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
TechHelper.Client/wwwroot/ref/Keda.png
Normal file
BIN
TechHelper.Client/wwwroot/ref/Keda.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
@@ -21,6 +21,7 @@ namespace TechHelper.Context
|
||||
public DbSet<Submission> Submissions { get; set; }
|
||||
public DbSet<SubmissionDetail> SubmissionDetails { get; set; }
|
||||
public DbSet<QuestionContext> QuestionContexts { get; set; }
|
||||
public DbSet<Global> Globals { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
|
@@ -2,6 +2,10 @@
|
||||
using AutoMapper.Internal.Mappers;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TechHelper.Context
|
||||
{
|
||||
@@ -23,13 +27,13 @@ namespace TechHelper.Context
|
||||
public AutoMapperProFile()
|
||||
{
|
||||
CreateMap<UserForRegistrationDto, User>()
|
||||
.ForMember(dest => dest.Id, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Name))
|
||||
.ForMember(dest => dest.Id, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Name))
|
||||
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
|
||||
.ForMember(dest => dest.PhoneNumber, opt => opt.MapFrom(src => src.PhoneNumber))
|
||||
.ForMember(dest => dest.Address, opt => opt.MapFrom(src => src.HomeAddress))
|
||||
.ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore());
|
||||
.ForMember(dest => dest.Address, opt => opt.MapFrom(src => src.HomeAddress))
|
||||
.ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore());
|
||||
|
||||
CreateMap<ClassDto, Class>()
|
||||
.ForMember(d => d.Number, o => o.MapFrom(src => src.Class))
|
||||
@@ -44,7 +48,7 @@ namespace TechHelper.Context
|
||||
|
||||
CreateMap<QuestionDto, Question>().ReverseMap();
|
||||
|
||||
CreateMap<QuestionContext, QuestionContextDto>().ReverseMap();
|
||||
CreateMap<QuestionContext, QuestionContextDto>().ReverseMap();
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +56,24 @@ namespace TechHelper.Context
|
||||
// Submission
|
||||
CreateMap<SubmissionDto, Submission>().ReverseMap();
|
||||
|
||||
CreateMap<SubmissionDetailDto, SubmissionDetail>().ReverseMap();
|
||||
CreateMap<SubmissionDetailDto, SubmissionDetail>().ReverseMap();
|
||||
|
||||
// Student Submission Detail
|
||||
CreateMap<Submission, StudentSubmissionDetailDto>()
|
||||
.ForMember(dest => dest.AssignmentId, opt => opt.MapFrom(src => src.AssignmentId))
|
||||
.ForMember(dest => dest.StudentId, opt => opt.MapFrom(src => src.StudentId))
|
||||
.ForMember(dest => dest.SubmissionTime, opt => opt.MapFrom(src => src.SubmissionTime))
|
||||
.ForMember(dest => dest.OverallGrade, opt => opt.MapFrom(src => src.OverallGrade))
|
||||
.ForMember(dest => dest.OverallFeedback, opt => opt.MapFrom(src => src.OverallFeedback))
|
||||
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status));
|
||||
|
||||
CreateMap<Assignment, AssignmentDto>().ReverseMap();
|
||||
|
||||
|
||||
CreateMap<SubjectTypeMetadataDto, Global>()
|
||||
.ForMember(dest => dest.Info, opt => opt.MapFrom(src => JsonConvert.SerializeObject(src.Data)));
|
||||
CreateMap<Global, SubjectTypeMetadataDto>()
|
||||
.ForMember(dest => dest.Data, opt => opt.MapFrom(src => JsonConvert.DeserializeObject<Dictionary<string, (string Color, string DisplayName)>>(src.Info)));
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -39,6 +39,7 @@ namespace TechHelper.Context.Configuration
|
||||
|
||||
builder.Property(s => s.OverallGrade)
|
||||
.HasColumnName("overall_grade")
|
||||
.IsRequired()
|
||||
.HasPrecision(5, 2); // 应用精度设置
|
||||
|
||||
// OverallFeedback
|
||||
|
@@ -10,6 +10,10 @@ using Entities.Contracts;
|
||||
|
||||
namespace TechHelper.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 账户管理控制器
|
||||
/// 处理用户注册、登录、密码重置等认证相关操作
|
||||
/// </summary>
|
||||
[Route("api/account")]
|
||||
[ApiController]
|
||||
public class AccountController : ControllerBase
|
||||
@@ -19,6 +23,13 @@ namespace TechHelper.Controllers
|
||||
private IAuthenticationService _authenticationService;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化账户控制器
|
||||
/// </summary>
|
||||
/// <param name="userManager">用户管理服务</param>
|
||||
/// <param name="userRegistrationService">用户注册服务</param>
|
||||
/// <param name="emailSender">邮件发送服务</param>
|
||||
/// <param name="authenticationService">认证服务</param>
|
||||
public AccountController(UserManager<User> userManager,
|
||||
IUserRegistrationService userRegistrationService,
|
||||
IEmailSender emailSender,
|
||||
@@ -30,6 +41,13 @@ namespace TechHelper.Controllers
|
||||
_authenticationService = authenticationService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册新用户
|
||||
/// </summary>
|
||||
/// <param name="userForRegistrationDto">用户注册信息数据传输对象</param>
|
||||
/// <returns>注册结果响应</returns>
|
||||
/// <response code="201">用户注册成功</response>
|
||||
/// <response code="400">注册请求无效或验证失败</response>
|
||||
[HttpPost("register")]
|
||||
public async Task<IActionResult> RegisterUsesr(
|
||||
[FromBody] UserForRegistrationDto userForRegistrationDto)
|
||||
@@ -93,6 +111,14 @@ namespace TechHelper.Controllers
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户登录认证
|
||||
/// </summary>
|
||||
/// <param name="userForAuthentication">用户认证信息数据传输对象</param>
|
||||
/// <returns>认证结果响应</returns>
|
||||
/// <response code="200">登录成功,返回认证令牌</response>
|
||||
/// <response code="401">认证失败,用户名或密码错误</response>
|
||||
/// <response code="400">请求无效或验证失败</response>
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Logion(
|
||||
[FromBody] UserForAuthenticationDto userForAuthentication)
|
||||
@@ -158,6 +184,11 @@ namespace TechHelper.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成两步验证的OTP令牌
|
||||
/// </summary>
|
||||
/// <param name="user">用户对象</param>
|
||||
/// <returns>两步验证响应</returns>
|
||||
private async Task<IActionResult> GenerateOTPFor2StepVerification(User user)
|
||||
{
|
||||
var providers = await _userManager.GetValidTwoFactorProvidersAsync(user);
|
||||
@@ -180,6 +211,14 @@ namespace TechHelper.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 忘记密码请求
|
||||
/// 发送密码重置令牌到用户邮箱
|
||||
/// </summary>
|
||||
/// <param name="forgotPasswordDto">忘记密码请求数据传输对象</param>
|
||||
/// <returns>操作结果</returns>
|
||||
/// <response code="200">密码重置邮件发送成功</response>
|
||||
/// <response code="400">请求无效或用户不存在</response>
|
||||
[HttpPost("forgotPassword")]
|
||||
public async Task<IActionResult> ForgotPassword(
|
||||
[FromBody] ForgotPasswordDto forgotPasswordDto)
|
||||
@@ -203,6 +242,13 @@ namespace TechHelper.Controllers
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 重置用户密码
|
||||
/// </summary>
|
||||
/// <param name="resetPasswordDto">密码重置数据传输对象</param>
|
||||
/// <returns>重置结果响应</returns>
|
||||
/// <response code="200">密码重置成功</response>
|
||||
/// <response code="400">密码重置失败</response>
|
||||
[HttpPost("resetPassword")]
|
||||
public async Task<IActionResult> ResetPassword(
|
||||
[FromBody] ResetPasswordDto resetPasswordDto)
|
||||
@@ -231,6 +277,15 @@ namespace TechHelper.Controllers
|
||||
return Ok(new ResetPasswordResponseDto { IsResetPasswordSuccessful = true});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 邮箱确认验证
|
||||
/// 验证用户邮箱确认令牌
|
||||
/// </summary>
|
||||
/// <param name="email">用户邮箱地址</param>
|
||||
/// <param name="token">邮箱确认令牌</param>
|
||||
/// <returns>验证结果</returns>
|
||||
/// <response code="200">邮箱确认成功</response>
|
||||
/// <response code="400">邮箱确认失败</response>
|
||||
[HttpGet("emailconfirmation")]
|
||||
public async Task<IActionResult> EmailConfirmaation([FromQuery] string email,
|
||||
[FromQuery] string token)
|
||||
@@ -245,6 +300,14 @@ namespace TechHelper.Controllers
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 两步验证确认
|
||||
/// 验证用户提供的两步验证令牌
|
||||
/// </summary>
|
||||
/// <param name="twoFactorVerificationDto">两步验证数据传输对象</param>
|
||||
/// <returns>验证结果响应</returns>
|
||||
/// <response code="200">验证成功,返回认证令牌</response>
|
||||
/// <response code="400">验证失败</response>
|
||||
[HttpPost("TwoStepVerification")]
|
||||
public async Task<IActionResult> TwoStepVerification(
|
||||
[FromBody] TwoFactorVerificationDto twoFactorVerificationDto)
|
||||
|
@@ -9,18 +9,35 @@ using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 班级管理控制器
|
||||
/// 处理班级相关的操作,如用户注册到班级、获取班级学生等
|
||||
/// </summary>
|
||||
[Route("api/class")]
|
||||
[ApiController]
|
||||
public class ClassController : ControllerBase
|
||||
{
|
||||
private IClassService _classService;
|
||||
private UserManager<User> _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化班级控制器
|
||||
/// </summary>
|
||||
/// <param name="classService">班级服务</param>
|
||||
/// <param name="userManager">用户管理服务</param>
|
||||
public ClassController(IClassService classService, UserManager<User> userManager)
|
||||
{
|
||||
_classService = classService;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户注册到班级
|
||||
/// </summary>
|
||||
/// <param name="toClass">用户注册到班级的数据传输对象</param>
|
||||
/// <returns>操作结果</returns>
|
||||
/// <response code="200">注册成功</response>
|
||||
/// <response code="400">注册失败</response>
|
||||
[HttpPost("userRegiste")]
|
||||
public async Task<IActionResult> UserRegisterToClass(
|
||||
[FromBody] UserRegistrationToClassDto toClass)
|
||||
@@ -36,6 +53,13 @@ namespace TechHelper.Server.Controllers
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取班级学生列表
|
||||
/// 仅限教师角色访问,根据教师所在班级信息获取学生列表
|
||||
/// </summary>
|
||||
/// <returns>班级学生列表</returns>
|
||||
/// <response code="200">成功获取学生列表</response>
|
||||
/// <response code="400">权限不足或班级信息缺失</response>
|
||||
[HttpPost("getClassStudents")]
|
||||
public async Task<IActionResult> GetClassStudents()
|
||||
{
|
||||
@@ -84,6 +108,13 @@ namespace TechHelper.Server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建新班级
|
||||
/// </summary>
|
||||
/// <param name="classDto">班级数据传输对象</param>
|
||||
/// <returns>操作结果</returns>
|
||||
/// <response code="200">班级创建成功</response>
|
||||
/// <response code="400">班级创建失败</response>
|
||||
[HttpPost("Create")]
|
||||
public async Task<IActionResult> Create(
|
||||
[FromBody] ClassDto classDto)
|
||||
@@ -94,6 +125,13 @@ namespace TechHelper.Server.Controllers
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定年级的所有班级列表
|
||||
/// </summary>
|
||||
/// <param name="classDto">年级编号</param>
|
||||
/// <returns>班级列表</returns>
|
||||
/// <response code="200">成功获取班级列表</response>
|
||||
/// <response code="400">获取失败</response>
|
||||
[HttpPost("GetGradeClasses")]
|
||||
public async Task<IActionResult> GetGradeClasses(
|
||||
[FromBody] byte classDto)
|
||||
|
91
TechHelper.Server/Controllers/NoteController.cs
Normal file
91
TechHelper.Server/Controllers/NoteController.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Controllers
|
||||
{
|
||||
[Route("api/note")]
|
||||
[ApiController]
|
||||
public class NoteController : ControllerBase
|
||||
{
|
||||
private readonly INoteService _noteService;
|
||||
|
||||
// 通过依赖注入获取 NoteService
|
||||
public NoteController(INoteService noteService)
|
||||
{
|
||||
_noteService = noteService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有全局数据。
|
||||
/// GET: api/Note
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll([FromQuery] QueryParameter query)
|
||||
{
|
||||
var response = await _noteService.GetAllAsync(query);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 ID 获取单个全局数据。
|
||||
/// GET: api/Note/{id}
|
||||
/// </summary>
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> Get(byte id)
|
||||
{
|
||||
var response = await _noteService.GetAsync(id);
|
||||
if (!response.Status)
|
||||
{
|
||||
return NotFound(response);
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加新的全局数据。
|
||||
/// POST: api/Note
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Add([FromBody] GlobalDto model)
|
||||
{
|
||||
var response = await _noteService.AddAsync(model);
|
||||
if (!response.Status)
|
||||
{
|
||||
return BadRequest(response);
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新已存在的全局数据。
|
||||
/// PUT: api/Note
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> Update([FromBody] GlobalDto model)
|
||||
{
|
||||
var response = await _noteService.UpdateAsync(model);
|
||||
if (!response.Status)
|
||||
{
|
||||
return NotFound(response);
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 ID 删除全局数据。
|
||||
/// DELETE: api/Note/{id}
|
||||
/// </summary>
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> Delete(byte id)
|
||||
{
|
||||
var response = await _noteService.DeleteAsync(id);
|
||||
if (!response.Status)
|
||||
{
|
||||
return NotFound(response);
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
||||
}
|
127
TechHelper.Server/Controllers/StudentSubmissionController.cs
Normal file
127
TechHelper.Server/Controllers/StudentSubmissionController.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TechHelper.Server.Services;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace TechHelper.Server.Controllers
|
||||
{
|
||||
[Route("api/student-submission")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class StudentSubmissionController : ControllerBase
|
||||
{
|
||||
private readonly IStudentSubmissionService _studentSubmissionService;
|
||||
private readonly UserManager<User> _userManager;
|
||||
|
||||
public StudentSubmissionController(
|
||||
IStudentSubmissionService studentSubmissionService,
|
||||
UserManager<User> userManager)
|
||||
{
|
||||
_studentSubmissionService = studentSubmissionService;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前学生的所有提交摘要
|
||||
/// </summary>
|
||||
/// <returns>学生提交摘要列表</returns>
|
||||
[HttpGet("my-submissions")]
|
||||
public async Task<IActionResult> GetMySubmissions()
|
||||
{
|
||||
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||
if (user == null)
|
||||
return NotFound("未找到用户信息");
|
||||
|
||||
var result = await _studentSubmissionService.GetStudentSubmissionsAsync(user.Id);
|
||||
|
||||
if (result.Status)
|
||||
{
|
||||
return Ok(result.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest(result.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前学生的提交摘要(分页)
|
||||
/// </summary>
|
||||
/// <param name="pageNumber">页码,默认为1</param>
|
||||
/// <param name="pageSize">每页数量,默认为10</param>
|
||||
/// <returns>分页的学生提交摘要列表</returns>
|
||||
[HttpGet("my-submissions-paged")]
|
||||
public async Task<IActionResult> GetMySubmissionsPaged(int pageNumber = 1, int pageSize = 10)
|
||||
{
|
||||
if (pageNumber < 1) pageNumber = 1;
|
||||
if (pageSize < 1) pageSize = 10;
|
||||
if (pageSize > 100) pageSize = 100; // 限制最大页面大小
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||
if (user == null)
|
||||
return NotFound("未找到用户信息");
|
||||
|
||||
var result = await _studentSubmissionService.GetStudentSubmissionsPagedAsync(user.Id, pageNumber, pageSize);
|
||||
|
||||
if (result.Status)
|
||||
{
|
||||
return Ok(result.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest(result.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定学生的提交摘要(仅教师可使用)
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <returns>学生提交摘要列表</returns>
|
||||
[HttpGet("student/{studentId:guid}")]
|
||||
[Authorize(Roles = "Teacher")]
|
||||
public async Task<IActionResult> GetStudentSubmissions(Guid studentId)
|
||||
{
|
||||
var result = await _studentSubmissionService.GetStudentSubmissionsAsync(studentId);
|
||||
|
||||
if (result.Status)
|
||||
{
|
||||
return Ok(result.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest(result.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定学生的提交摘要(分页,仅教师可使用)
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="pageNumber">页码,默认为1</param>
|
||||
/// <param name="pageSize">每页数量,默认为10</param>
|
||||
/// <returns>分页的学生提交摘要列表</returns>
|
||||
[HttpGet("student/{studentId:guid}/paged")]
|
||||
[Authorize(Roles = "Teacher")]
|
||||
public async Task<IActionResult> GetStudentSubmissionsPaged(Guid studentId, int pageNumber = 1, int pageSize = 10)
|
||||
{
|
||||
if (pageNumber < 1) pageNumber = 1;
|
||||
if (pageSize < 1) pageSize = 10;
|
||||
if (pageSize > 100) pageSize = 100; // 限制最大页面大小
|
||||
|
||||
var result = await _studentSubmissionService.GetStudentSubmissionsPagedAsync(studentId, pageNumber, pageSize);
|
||||
|
||||
if (result.Status)
|
||||
{
|
||||
return Ok(result.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest(result.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TechHelper.Server.Services;
|
||||
using TechHelper.Context;
|
||||
using TechHelper.Repository;
|
||||
using SharedDATA.Api;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace TechHelper.Server.Controllers
|
||||
{
|
||||
[Route("api/student-submission-detail")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class StudentSubmissionDetailController : ControllerBase
|
||||
{
|
||||
private readonly IStudentSubmissionDetailService _studentSubmissionDetailService;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
|
||||
public StudentSubmissionDetailController(
|
||||
IStudentSubmissionDetailService studentSubmissionDetailService,
|
||||
UserManager<User> userManager,
|
||||
IUnitOfWork unitOfWork)
|
||||
{
|
||||
_studentSubmissionDetailService = studentSubmissionDetailService;
|
||||
_userManager = userManager;
|
||||
_unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生提交的详细信息
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <returns>学生提交详细信息</returns>
|
||||
[HttpGet("{submissionId:guid}")]
|
||||
public async Task<IActionResult> GetSubmissionDetail(Guid submissionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 验证用户权限 - 只有学生本人或教师可以查看
|
||||
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound("未找到用户信息");
|
||||
}
|
||||
|
||||
var submission = await _unitOfWork.GetRepository<Submission>()
|
||||
.GetFirstOrDefaultAsync(predicate: s => s.Id == submissionId);
|
||||
|
||||
if (submission == null)
|
||||
{
|
||||
return NotFound("未找到指定的提交记录");
|
||||
}
|
||||
|
||||
// 检查权限:学生只能查看自己的提交,教师可以查看所有提交
|
||||
if (user.Id != submission.StudentId && !User.IsInRole("Teacher"))
|
||||
{
|
||||
return Forbid("您没有权限查看此提交记录");
|
||||
}
|
||||
|
||||
var result = await _studentSubmissionDetailService.GetSubmissionDetailAsync(submissionId);
|
||||
|
||||
if (result.Status)
|
||||
{
|
||||
return Ok(result.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest(result.Message);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, $"获取学生提交详细信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1277
TechHelper.Server/Migrations/20250901072725_question_qt_update.Designer.cs
generated
Normal file
1277
TechHelper.Server/Migrations/20250901072725_question_qt_update.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class question_qt_update : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("0775702a-5db7-4747-94d0-4376fad2b58b"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("37f41430-0cb7-44e5-988b-976200bd602d"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70"));
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "QType",
|
||||
table: "questions",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AddColumn<byte>(
|
||||
name: "Type",
|
||||
table: "assignment_questions",
|
||||
type: "tinyint unsigned",
|
||||
nullable: false,
|
||||
defaultValue: (byte)0);
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae"), null, "Student", "STUDENT" },
|
||||
{ new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274"), null, "Administrator", "ADMINISTRATOR" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274"));
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "QType",
|
||||
table: "questions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Type",
|
||||
table: "assignment_questions");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("0775702a-5db7-4747-94d0-4376fad2b58b"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("37f41430-0cb7-44e5-988b-976200bd602d"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70"), null, "Student", "STUDENT" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
1296
TechHelper.Server/Migrations/20250901080732_question_qt_update_2.Designer.cs
generated
Normal file
1296
TechHelper.Server/Migrations/20250901080732_question_qt_update_2.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class question_qt_update_2 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274"));
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "global",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
Area = table.Column<byte>(type: "tinyint unsigned", nullable: false),
|
||||
Info = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_global", x => x.id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558"), null, "Student", "STUDENT" },
|
||||
{ new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5"), null, "Administrator", "ADMINISTRATOR" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "global");
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5"));
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae"), null, "Student", "STUDENT" },
|
||||
{ new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274"), null, "Administrator", "ADMINISTRATOR" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
1299
TechHelper.Server/Migrations/20250901083708_question_qt_update_3.Designer.cs
generated
Normal file
1299
TechHelper.Server/Migrations/20250901083708_question_qt_update_3.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class question_qt_update_3 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5"));
|
||||
|
||||
migrationBuilder.AddColumn<byte>(
|
||||
name: "SubjectArea",
|
||||
table: "AspNetUsers",
|
||||
type: "tinyint unsigned",
|
||||
nullable: false,
|
||||
defaultValue: (byte)0);
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("2670f35a-df0c-4071-8879-80eb99d138a1"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043"), null, "Student", "STUDENT" },
|
||||
{ new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db"), null, "Administrator", "ADMINISTRATOR" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("2670f35a-df0c-4071-8879-80eb99d138a1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db"));
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubjectArea",
|
||||
table: "AspNetUsers");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558"), null, "Student", "STUDENT" },
|
||||
{ new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5"), null, "Administrator", "ADMINISTRATOR" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
1299
TechHelper.Server/Migrations/20250904101811_submission_up_2.Designer.cs
generated
Normal file
1299
TechHelper.Server/Migrations/20250904101811_submission_up_2.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class submission_up_2 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("2670f35a-df0c-4071-8879-80eb99d138a1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db"));
|
||||
|
||||
migrationBuilder.AlterColumn<float>(
|
||||
name: "overall_grade",
|
||||
table: "submissions",
|
||||
type: "float",
|
||||
precision: 5,
|
||||
scale: 2,
|
||||
nullable: false,
|
||||
defaultValue: 0f,
|
||||
oldClrType: typeof(float),
|
||||
oldType: "float",
|
||||
oldPrecision: 5,
|
||||
oldScale: 2,
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc"), null, "Student", "STUDENT" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc"));
|
||||
|
||||
migrationBuilder.AlterColumn<float>(
|
||||
name: "overall_grade",
|
||||
table: "submissions",
|
||||
type: "float",
|
||||
precision: 5,
|
||||
scale: 2,
|
||||
nullable: true,
|
||||
oldClrType: typeof(float),
|
||||
oldType: "float",
|
||||
oldPrecision: 5,
|
||||
oldScale: 2);
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("2670f35a-df0c-4071-8879-80eb99d138a1"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043"), null, "Student", "STUDENT" },
|
||||
{ new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db"), null, "Administrator", "ADMINISTRATOR" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
1299
TechHelper.Server/Migrations/20250904102023_submission_up_3.Designer.cs
generated
Normal file
1299
TechHelper.Server/Migrations/20250904102023_submission_up_3.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class submission_up_3 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc"));
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9"), null, "Student", "STUDENT" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9"));
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc"), null, "Student", "STUDENT" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
1302
TechHelper.Server/Migrations/20250905101308_tee.Designer.cs
generated
Normal file
1302
TechHelper.Server/Migrations/20250905101308_tee.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
82
TechHelper.Server/Migrations/20250905101308_tee.cs
Normal file
82
TechHelper.Server/Migrations/20250905101308_tee.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class tee : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9"));
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "BCorrect",
|
||||
table: "assignment_questions",
|
||||
type: "tinyint(1)",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("d480cdca-7de2-4abe-8129-73bbaa6c1b32"), null, "Student", "STUDENT" },
|
||||
{ new Guid("d7bcfb37-3f1c-467b-a3f0-b2339a8a990d"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("f4a6788a-04d8-499c-9e64-73dfba97ca6b"), null, "Administrator", "ADMINISTRATOR" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("d480cdca-7de2-4abe-8129-73bbaa6c1b32"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("d7bcfb37-3f1c-467b-a3f0-b2339a8a990d"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("f4a6788a-04d8-499c-9e64-73dfba97ca6b"));
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BCorrect",
|
||||
table: "assignment_questions");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9"), null, "Student", "STUDENT" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -175,6 +175,9 @@ namespace TechHelper.Server.Migrations
|
||||
b.Property<Guid?>("AssignmentId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<bool>("BCorrect")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("created_at");
|
||||
@@ -219,6 +222,9 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("varchar(1024)")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.Property<byte>("Type")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AssignmentId");
|
||||
@@ -332,6 +338,25 @@ namespace TechHelper.Server.Migrations
|
||||
b.ToTable("class_teachers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Global", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<byte>("Area")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<string>("Info")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("global");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.KeyPoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -445,6 +470,10 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("options");
|
||||
|
||||
b.Property<string>("QType")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("tinyint unsigned")
|
||||
@@ -532,7 +561,7 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("overall_feedback");
|
||||
|
||||
b.Property<float?>("OverallGrade")
|
||||
b.Property<float>("OverallGrade")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("overall_grade");
|
||||
@@ -723,6 +752,9 @@ namespace TechHelper.Server.Migrations
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
@@ -771,19 +803,19 @@ namespace TechHelper.Server.Migrations
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70"),
|
||||
Id = new Guid("d480cdca-7de2-4abe-8129-73bbaa6c1b32"),
|
||||
Name = "Student",
|
||||
NormalizedName = "STUDENT"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("0775702a-5db7-4747-94d0-4376fad2b58b"),
|
||||
Id = new Guid("d7bcfb37-3f1c-467b-a3f0-b2339a8a990d"),
|
||||
Name = "Teacher",
|
||||
NormalizedName = "TEACHER"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("37f41430-0cb7-44e5-988b-976200bd602d"),
|
||||
Id = new Guid("f4a6788a-04d8-499c-9e64-73dfba97ca6b"),
|
||||
Name = "Administrator",
|
||||
NormalizedName = "ADMINISTRATOR"
|
||||
});
|
||||
|
@@ -14,12 +14,15 @@ using TechHelper.Server.Services;
|
||||
using TechHelper.Server.Repositories;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// TechHelper 服务器应用程序的主入口点
|
||||
/// 配置和启动 ASP.NET Core Web API 应用程序
|
||||
/// </summary>
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddControllers(); // <EFBFBD><EFBFBD><EFBFBD><EFBFBD> MVC <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> API)
|
||||
builder.Services.AddControllers(); // 添加 MVC 控制器服务 (用于 API)
|
||||
|
||||
// 2. <EFBFBD><EFBFBD><EFBFBD>ݿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (DbContext)
|
||||
// 2. 数据库服务 (DbContext)
|
||||
builder.Services.AddDbContext<ApplicationContext>(options =>
|
||||
options.UseMySql(
|
||||
builder.Configuration.GetConnectionString("XSDB"),
|
||||
@@ -34,17 +37,20 @@ builder.Services.AddDbContext<ApplicationContext>(options =>
|
||||
.AddCustomRepository<ClassTeacher, ClassTeacherRepository>()
|
||||
.AddCustomRepository<Question, QuestionRepository>()
|
||||
.AddCustomRepository<QuestionContext, QuestionContextRepository>()
|
||||
.AddCustomRepository<Submission, SubmissionRepository>();
|
||||
.AddCustomRepository<Submission, SubmissionRepository>()
|
||||
.AddCustomRepository<User, UserRepository>()
|
||||
.AddCustomRepository<Global, GlobalRepository>();
|
||||
|
||||
|
||||
builder.Services.AddAutoMapper(typeof(AutoMapperProFile).Assembly);
|
||||
|
||||
// 3. <EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD> (IOptions)
|
||||
// 3. 配置服务 (IOptions)
|
||||
builder.Services.Configure<ApiConfiguration>(builder.Configuration.GetSection("ApiConfiguration"));
|
||||
builder.Services.Configure<JwtConfiguration>(builder.Configuration.GetSection("JWTSettings"));
|
||||
|
||||
|
||||
// 4. <EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> (Identity, JWT, <EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD> Auth)
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ASP.NET Core Identity (<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD>ϵ<EFBFBD> Cookie <20><>֤<EFBFBD><D6A4><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>)
|
||||
// 4. 认证和授权服务 (Identity, JWT, 自定义 Auth)
|
||||
// 添加 ASP.NET Core Identity (包含默认的 Cookie 认证和授权服务)
|
||||
builder.Services.AddIdentity<User, IdentityRole<Guid>>(opt =>
|
||||
{
|
||||
opt.User.AllowedUserNameCharacters = "";
|
||||
@@ -60,25 +66,25 @@ builder.Services.Configure<DataProtectionTokenProviderOptions>(Options =>
|
||||
});
|
||||
|
||||
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> JWT Bearer <EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// 添加 JWT Bearer 认证方案
|
||||
var jwtSettings = builder.Configuration.GetSection("JWTSettings");
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ JWT Bearer
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ս<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ JWT Bearer
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; // 设置默认认证方案为 JWT Bearer
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; // 设置默认挑战方案为 JWT Bearer
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true, // <EFBFBD><EFBFBD>֤ǩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
ValidateAudience = true, // <EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
ValidateLifetime = true, // <EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD>
|
||||
ValidateIssuerSigningKey = true, // <EFBFBD><EFBFBD>֤ǩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Կ
|
||||
ValidateIssuer = true, // 验证签发人
|
||||
ValidateAudience = true, // 验证受众
|
||||
ValidateLifetime = true, // 验证令牌有效期
|
||||
ValidateIssuerSigningKey = true, // 验证签名密钥
|
||||
|
||||
ValidIssuer = jwtSettings["validIssuer"], // <EFBFBD>Ϸ<EFBFBD><EFBFBD><EFBFBD>ǩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
ValidAudience = jwtSettings["validAudience"], // <EFBFBD>Ϸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["securityKey"])) // ǩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Կ
|
||||
ValidIssuer = jwtSettings["validIssuer"], // 合法的签发人
|
||||
ValidAudience = jwtSettings["validAudience"], // 合法的受众
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["securityKey"])) // 签名密钥
|
||||
};
|
||||
});
|
||||
|
||||
@@ -89,7 +95,10 @@ builder.Services.AddScoped<IClassService, ClassService>();
|
||||
builder.Services.AddScoped<IExamService, ExamService>();
|
||||
builder.Services.AddScoped<IUserSerivces, UserServices>();
|
||||
builder.Services.AddScoped<ISubmissionServices, SubmissionServices>();
|
||||
builder.Services.AddScoped<IStudentSubmissionService, StudentSubmissionService>();
|
||||
builder.Services.AddScoped<IStudentSubmissionDetailService, StudentSubmissionDetailService>();
|
||||
builder.Services.AddScoped<IExamRepository, ExamRepository>();
|
||||
builder.Services.AddScoped<INoteService, NoteService>();
|
||||
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
@@ -128,7 +137,7 @@ builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowSpecificOrigin",
|
||||
builder => builder
|
||||
.WithOrigins("https://localhost:7047", "http://localhost:7047")
|
||||
.WithOrigins("https://localhost:7047", "http://localhost:7047", "https://localhost:5001", "http://localhost:5001")
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()
|
||||
.AllowCredentials());
|
||||
|
17
TechHelper.Server/Repository/GlobalRepository.cs
Normal file
17
TechHelper.Server/Repository/GlobalRepository.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Entities.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Context;
|
||||
|
||||
namespace TechHelper.Repository
|
||||
{
|
||||
public class GlobalRepository : Repository<Global>, IRepository<Global>
|
||||
{
|
||||
public GlobalRepository(ApplicationContext dbContext) : base(dbContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -143,6 +143,21 @@ namespace TechHelper.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Task GetClassStudents(byte Grade, byte Class)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _work.GetRepository<Class>().GetFirstOrDefault(predicate:
|
||||
c => c.Grade == Grade && c.Number == Class,
|
||||
include: i => i
|
||||
.Include(c => c.ClassStudents)
|
||||
.ThenInclude(cs => cs.Student));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ }
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetGradeClasses(byte Grade)
|
||||
{
|
||||
try
|
||||
|
@@ -11,6 +11,6 @@ namespace TechHelper.Services
|
||||
public Task<ApiResponse> GetUserClassRole(Guid user); // List<UserClassRoleDto>
|
||||
public Task<ApiResponse> GetClassStudents(ClassDto classDto); // Class
|
||||
public Task<ApiResponse> GetGradeClasses(byte Grade); // Class
|
||||
|
||||
Task GetClassStudents(byte grade, byte id);
|
||||
}
|
||||
}
|
||||
|
13
TechHelper.Server/Services/INoteService.cs
Normal file
13
TechHelper.Server/Services/INoteService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using System.Net;
|
||||
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
|
||||
|
||||
public interface INoteService : IBaseService<GlobalDto, byte>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IStudentSubmissionDetailService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取学生提交的详细信息
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <returns>学生提交详细信息</returns>
|
||||
Task<ApiResponse> GetSubmissionDetailAsync(Guid submissionId);
|
||||
}
|
||||
}
|
24
TechHelper.Server/Services/IStudentSubmissionService.cs
Normal file
24
TechHelper.Server/Services/IStudentSubmissionService.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IStudentSubmissionService : IBaseService<StudentSubmissionSummaryDto, Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取学生提交的作业摘要列表
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <returns>学生提交摘要列表</returns>
|
||||
Task<ApiResponse> GetStudentSubmissionsAsync(Guid studentId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生提交的作业摘要列表(分页)
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="pageNumber">页码</param>
|
||||
/// <param name="pageSize">每页数量</param>
|
||||
/// <returns>分页的学生提交摘要列表</returns>
|
||||
Task<ApiResponse> GetStudentSubmissionsPagedAsync(Guid studentId, int pageNumber = 1, int pageSize = 10);
|
||||
}
|
||||
}
|
107
TechHelper.Server/Services/NoteService.cs
Normal file
107
TechHelper.Server/Services/NoteService.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using SharedDATA.Api;
|
||||
using System.Net;
|
||||
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
public class NoteService : INoteService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public NoteService(IUnitOfWork work)
|
||||
{
|
||||
_work = work;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(GlobalDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var globalEntity = new Global
|
||||
{
|
||||
Area = model.SubjectArea,
|
||||
Info = model.Data
|
||||
};
|
||||
|
||||
await _work.GetRepository<Global>().InsertAsync(globalEntity);
|
||||
await _work.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success("数据已成功添加。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"添加数据时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(byte id)
|
||||
{
|
||||
var globalRepo = _work.GetRepository<Global>();
|
||||
var globalEntity = await globalRepo.GetFirstOrDefaultAsync(predicate: x => x.Area == (SubjectAreaEnum)id);
|
||||
|
||||
if (globalEntity == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到要删除的数据。");
|
||||
}
|
||||
|
||||
globalRepo.Delete(globalEntity);
|
||||
await _work.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success("数据已成功删除。");
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
var repository = _work.GetRepository<Global>();
|
||||
// 获取所有实体,并将其 Info 属性作为结果返回
|
||||
var entities = await repository.GetAllAsync();
|
||||
|
||||
// 直接返回字符串列表
|
||||
var resultData = entities.Select(e => e.Info).ToList();
|
||||
|
||||
return ApiResponse.Success("数据已成功检索。", resultData);
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(byte id)
|
||||
{
|
||||
var globalEntity = await _work.GetRepository<Global>().GetFirstOrDefaultAsync(predicate: x => x.Area == (SubjectAreaEnum)id);
|
||||
|
||||
if (globalEntity == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到数据。");
|
||||
}
|
||||
|
||||
// 直接返回 Info 字符串
|
||||
return ApiResponse.Success("数据已成功检索。", globalEntity.Info);
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(GlobalDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<Global>();
|
||||
var existingEntity = await repository.GetFirstOrDefaultAsync(predicate: x => x.Area == (SubjectAreaEnum)model.SubjectArea);
|
||||
|
||||
if (existingEntity == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到要更新的数据。");
|
||||
}
|
||||
|
||||
// 直接将传入的字符串赋值给 Info 属性
|
||||
existingEntity.Info = model.Data;
|
||||
repository.Update(existingEntity);
|
||||
await _work.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success("数据已成功更新。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"更新数据时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
144
TechHelper.Server/Services/StudentSubmissionDetailService.cs
Normal file
144
TechHelper.Server/Services/StudentSubmissionDetailService.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using AutoMapper;
|
||||
using AutoMapper.Internal.Mappers;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Context;
|
||||
using TechHelper.Repository;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public class StudentSubmissionDetailService : IStudentSubmissionDetailService
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IExamService examService;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public StudentSubmissionDetailService(
|
||||
IUnitOfWork unitOfWork,
|
||||
IExamService examService,
|
||||
IMapper mapper)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
this.examService = examService;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetSubmissionDetailAsync(Guid submissionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取submission基本信息
|
||||
var submission = await _unitOfWork.GetRepository<Submission>()
|
||||
.GetAll(s => s.Id == submissionId)
|
||||
.Include(s => s.Assignment)
|
||||
.ThenInclude(a => a.Creator)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (submission == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到指定的提交记录");
|
||||
}
|
||||
|
||||
var assignment = await examService.GetAsync(submission.AssignmentId);
|
||||
if (assignment == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到指定的作业");
|
||||
}
|
||||
|
||||
// 获取所有提交详情
|
||||
var submissionDetails = await _unitOfWork.GetRepository<SubmissionDetail>()
|
||||
.GetAll(sd => sd.SubmissionId == submissionId)
|
||||
.Include(sd => sd.AssignmentQuestion)
|
||||
.ThenInclude(aq => aq.Question)
|
||||
.ThenInclude(q => q.Lesson)
|
||||
.ThenInclude(q => q.KeyPoints)
|
||||
.ToListAsync();
|
||||
|
||||
// 获取同作业的所有提交用于排名和成绩分布
|
||||
var allSubmissions = await _unitOfWork.GetRepository<Submission>()
|
||||
.GetAll(s => s.AssignmentId == submission.AssignmentId)
|
||||
.ToListAsync();
|
||||
|
||||
// 映射基本信息
|
||||
var result = _mapper.Map<StudentSubmissionDetailDto>(submission);
|
||||
result.Assignment = assignment.Result as AssignmentDto ?? new AssignmentDto();
|
||||
|
||||
var errorQuestion = submissionDetails
|
||||
.Where(sd => sd.IsCorrect == false && sd.AssignmentQuestion?.StructType == AssignmentStructType.Question && sd.AssignmentQuestion?.Question != null)
|
||||
.ToList();
|
||||
|
||||
// 计算基础统计
|
||||
result.TotalQuestions = submissionDetails.Select(x => x.AssignmentQuestion.StructType == AssignmentStructType.Question && x.AssignmentQuestion?.Question != null).Count();
|
||||
result.ErrorCount = errorQuestion.Count;
|
||||
result.CorrectCount = result.TotalQuestions - result.ErrorCount;
|
||||
result.AccuracyRate = result.TotalQuestions > 0 ?
|
||||
(float)result.CorrectCount / result.TotalQuestions : 0;
|
||||
|
||||
// 计算错误类型分布 - 只获取题目类型的错误
|
||||
result.ErrorTypeDistribution = errorQuestion
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Type.ToString())
|
||||
.ToDictionary(g => g.Key, g => g.Count()); ;
|
||||
|
||||
// 计算错误类型成绩分布 - 只获取题目类型的错误
|
||||
result.ErrorTypeScoreDistribution = errorQuestion
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Type.ToString())
|
||||
.ToDictionary(g => g.Key, g => g.Sum(sd => sd.PointsAwarded ?? 0));
|
||||
|
||||
// 计算成绩排名
|
||||
var orderedSubmissions = allSubmissions
|
||||
.OrderByDescending(s => s.OverallGrade)
|
||||
.ToList();
|
||||
result.TotalRank = orderedSubmissions.FindIndex(s => s.Id == submissionId) + 1;
|
||||
|
||||
SetBCorrect(result.Assignment, errorQuestion);
|
||||
// 计算成绩分布
|
||||
result.AllScores = allSubmissions.Select(s => s.OverallGrade).ToList();
|
||||
result.AverageScore = submission.OverallGrade;
|
||||
result.ClassAverageScore = allSubmissions.Average(s => s.OverallGrade);
|
||||
|
||||
// 计算课文错误分布
|
||||
result.LessonErrorDistribution = errorQuestion
|
||||
.Where(eq => eq.AssignmentQuestion.Question.Lesson != null)
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Lesson.Title)
|
||||
.ToDictionary(g => g.Key, g => g.Count());
|
||||
|
||||
// 计算关键点错误分布
|
||||
result.KeyPointErrorDistribution = errorQuestion
|
||||
.Where(eq => eq.AssignmentQuestion.Question.Lesson != null)
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.KeyPoint.Key)
|
||||
.ToDictionary(g => g.Key, g => g.Count());
|
||||
|
||||
return ApiResponse.Success(result: result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取学生提交详细信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBCorrect(AssignmentDto assignment, List<SubmissionDetail> submissionDetails)
|
||||
{
|
||||
SetBCorrect(assignment.ExamStruct, submissionDetails);
|
||||
}
|
||||
|
||||
public void SetBCorrect(AssignmentQuestionDto assignmentQuestion, List<SubmissionDetail> submissionDetails)
|
||||
{
|
||||
var sd = submissionDetails.FirstOrDefault(x => x.AssignmentQuestionId == assignmentQuestion.Id);
|
||||
if (sd != null)
|
||||
assignmentQuestion.BCorrect = sd.AssignmentQuestion.BCorrect;
|
||||
else
|
||||
assignmentQuestion.BCorrect = false;
|
||||
|
||||
assignmentQuestion.ChildrenAssignmentQuestion?.ForEach(
|
||||
cq => SetBCorrect(cq, submissionDetails));
|
||||
}
|
||||
|
||||
//Task<ApiResponse> IStudentSubmissionDetailService.GetSubmissionDetailAsync(Guid submissionId)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
}
|
||||
}
|
142
TechHelper.Server/Services/StudentSubmissionService.cs
Normal file
142
TechHelper.Server/Services/StudentSubmissionService.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Context;
|
||||
using TechHelper.Repository;
|
||||
using TechHelper.Server.Repositories;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public class StudentSubmissionService : IStudentSubmissionService
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IRepository<Submission> _submissionRepository;
|
||||
private readonly IRepository<Assignment> _assignmentRepository;
|
||||
private readonly IRepository<User> _userRepository;
|
||||
|
||||
public StudentSubmissionService(
|
||||
IUnitOfWork unitOfWork,
|
||||
IMapper mapper,
|
||||
IRepository<Submission> submissionRepository,
|
||||
IRepository<Assignment> assignmentRepository,
|
||||
IRepository<User> userRepository)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_mapper = mapper;
|
||||
_submissionRepository = submissionRepository;
|
||||
_assignmentRepository = assignmentRepository;
|
||||
_userRepository = userRepository;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetStudentSubmissionsAsync(Guid studentId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submissions = await _submissionRepository
|
||||
.GetAll(s => s.StudentId == studentId)
|
||||
.Include(s => s.Assignment)
|
||||
.ThenInclude(a => a.Creator)
|
||||
.OrderByDescending(s => s.SubmissionTime)
|
||||
.ToListAsync();
|
||||
|
||||
var result = new List<StudentSubmissionSummaryDto>();
|
||||
|
||||
foreach (var submission in submissions)
|
||||
{
|
||||
var summary = new StudentSubmissionSummaryDto
|
||||
{
|
||||
Id = submission.Id,
|
||||
AssignmentName = submission.Assignment?.Title ?? "未知作业",
|
||||
ErrorCount = await CalculateErrorCountAsync(submission.Id),
|
||||
CreatedDate = submission.SubmissionTime,
|
||||
Score = (int)submission.OverallGrade,
|
||||
TotalQuestions = submission.Assignment?.TotalQuestions ?? 0,
|
||||
StudentName = submission.Assignment?.Creator?.UserName ?? "未知老师",
|
||||
Status = submission.Status.ToString()
|
||||
};
|
||||
result.Add(summary);
|
||||
}
|
||||
|
||||
return ApiResponse.Success(result: result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取学生提交信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetStudentSubmissionsPagedAsync(Guid studentId, int pageNumber = 1, int pageSize = 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
var totalCount = await _submissionRepository
|
||||
.GetAll(s => s.StudentId == studentId)
|
||||
.CountAsync();
|
||||
|
||||
var submissions = await _submissionRepository
|
||||
.GetAll(s => s.StudentId == studentId)
|
||||
.Include(s => s.Assignment)
|
||||
.ThenInclude(a => a.Creator)
|
||||
.OrderByDescending(s => s.SubmissionTime)
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
var result = new List<StudentSubmissionSummaryDto>();
|
||||
|
||||
foreach (var submission in submissions)
|
||||
{
|
||||
var summary = new StudentSubmissionSummaryDto
|
||||
{
|
||||
Id = submission.Id,
|
||||
AssignmentName = submission.Assignment?.Title ?? "未知作业",
|
||||
ErrorCount = await CalculateErrorCountAsync(submission.Id),
|
||||
CreatedDate = submission.SubmissionTime,
|
||||
Score = submission.OverallGrade,
|
||||
TotalQuestions = submission.Assignment?.TotalQuestions ?? 0,
|
||||
StudentName = submission.Assignment?.Creator?.UserName ?? "未知老师",
|
||||
Status = submission.Status.ToString()
|
||||
};
|
||||
result.Add(summary);
|
||||
}
|
||||
|
||||
var response = new StudentSubmissionSummaryResponseDto
|
||||
{
|
||||
Submissions = result,
|
||||
TotalCount = totalCount
|
||||
};
|
||||
|
||||
return ApiResponse.Success(result: response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取学生提交信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<int> CalculateErrorCountAsync(Guid submissionId)
|
||||
{
|
||||
|
||||
var submissionDetails = await _unitOfWork.GetRepository<SubmissionDetail>()
|
||||
.GetAll(sd => sd.SubmissionId == submissionId)
|
||||
.ToListAsync();
|
||||
return submissionDetails.Select(x => !x.IsCorrect).Count();
|
||||
}
|
||||
|
||||
// 以下方法是IBaseService接口的实现,可以根据需要实现
|
||||
public Task<ApiResponse> GetAllAsync() => throw new NotImplementedException();
|
||||
public Task<ApiResponse> GetAsync(Guid id) => throw new NotImplementedException();
|
||||
public Task<ApiResponse> AddAsync(StudentSubmissionSummaryDto model) => throw new NotImplementedException();
|
||||
public Task<ApiResponse> UpdateAsync(StudentSubmissionSummaryDto model) => throw new NotImplementedException();
|
||||
public Task<ApiResponse> DeleteAsync(Guid id) => throw new NotImplementedException();
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,6 +6,10 @@ using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户服务实现类
|
||||
/// 处理用户相关的业务逻辑操作
|
||||
/// </summary>
|
||||
public class UserServices : IUserSerivces
|
||||
{
|
||||
|
||||
@@ -13,6 +17,12 @@ namespace TechHelper.Server.Services
|
||||
private readonly IClassService _classService;
|
||||
private readonly UserManager<User> _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化用户服务
|
||||
/// </summary>
|
||||
/// <param name="unitOfWork">工作单元实例</param>
|
||||
/// <param name="classService">班级服务实例</param>
|
||||
/// <param name="userManager">用户管理实例</param>
|
||||
public UserServices(IUnitOfWork unitOfWork, IClassService classService, UserManager<User> userManager)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
@@ -20,31 +30,62 @@ namespace TechHelper.Server.Services
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加新用户
|
||||
/// </summary>
|
||||
/// <param name="model">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public Task<ApiResponse> AddAsync(User model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定用户
|
||||
/// </summary>
|
||||
/// <param name="id">用户唯一标识符</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有用户列表
|
||||
/// </summary>
|
||||
/// <param name="query">查询参数对象</param>
|
||||
/// <returns>用户列表响应</returns>
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户信息
|
||||
/// </summary>
|
||||
/// <param name="id">用户唯一标识符</param>
|
||||
/// <returns>用户信息响应</returns>
|
||||
public Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生详细信息
|
||||
/// </summary>
|
||||
/// <param name="userId">用户唯一标识符</param>
|
||||
/// <returns>学生详细信息响应</returns>
|
||||
public Task<ApiResponse> GetStudentDetailInfo(Guid userId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复用户角色信息
|
||||
/// 根据用户所在班级信息恢复用户的角色权限
|
||||
/// </summary>
|
||||
/// <param name="user">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public async Task<ApiResponse> RestoreUserRoleInformation(User user)
|
||||
{
|
||||
var result = await _classService.GetUserClassRole(user.Id);
|
||||
@@ -64,11 +105,21 @@ namespace TechHelper.Server.Services
|
||||
return ApiResponse.Error();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新用户信息
|
||||
/// </summary>
|
||||
/// <param name="model">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public Task<ApiResponse> UpdateAsync(User model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证用户信息
|
||||
/// </summary>
|
||||
/// <param name="userId">用户唯一标识符</param>
|
||||
/// <returns>验证结果响应</returns>
|
||||
public Task<ApiResponse> VerifyUserInformation(Guid userId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user