Chinh sua UI
This commit is contained in:
parent
8f144c1a8b
commit
8cca84ceec
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6,29 +6,45 @@
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\form1.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:form1.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\form1.designer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:form1.designer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\form2.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:form2.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\form1.designer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:form1.designer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\response\\quiz.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:response\\quiz.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\response\\questionoption.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:response\\questionoption.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\service\\executeexcelservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:service\\executeexcelservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\response\\question.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:response\\question.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\dbhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:dbhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\service\\datautil.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:service\\datautil.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|E:\\QuizMaster\\QuizMaster\\form1.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:form1.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\service\\excelvalidator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:service\\excelvalidator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\form2.designer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:form2.designer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|e:\\quizmaster\\quizmaster\\dbhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{582DBFA6-720D-44B4-B48C-909F4DD98783}|QuizMaster.csproj|solutionrelative:dbhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
@ -48,7 +64,7 @@
|
||||
"RelativeDocumentMoniker": "Form1.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Form1.cs",
|
||||
"RelativeToolTip": "Form1.cs",
|
||||
"ViewState": "AQIAAAYEAAAAAAAAAAAcwBEEAAApAAAA",
|
||||
"ViewState": "AQIAAE8AAAAAAAAAAAAuwGUAAABVAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-26T01:54:54.164Z",
|
||||
"IsPinned": true,
|
||||
@ -56,28 +72,16 @@
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"DocumentIndex": 2,
|
||||
"Title": "Form2.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Form2.cs",
|
||||
"RelativeDocumentMoniker": "Form2.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Form2.cs",
|
||||
"RelativeToolTip": "Form2.cs",
|
||||
"ViewState": "AQIAAGMAAAAAAAAAAAAAAGwAAAAxAAAA",
|
||||
"ViewState": "AQIAAF0AAAAAAAAAAAAIwG8AAAAUAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-02T06:28:48.666Z",
|
||||
"IsPinned": true,
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "Form1.cs [Design]",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Form1.cs",
|
||||
"RelativeDocumentMoniker": "Form1.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Form1.cs [Design]",
|
||||
"RelativeToolTip": "Form1.cs [Design]",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-08T02:47:37.753Z"
|
||||
"IsPinned": true
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
@ -95,52 +99,111 @@
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:17:0:{e8034f19-ab72-4f06-83fd-f6832b41aa63}"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"Title": "Question.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Response\\Question.cs",
|
||||
"RelativeDocumentMoniker": "Response\\Question.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Response\\Question.cs",
|
||||
"RelativeToolTip": "Response\\Question.cs",
|
||||
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-14T06:24:38.262Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "Quiz.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Response\\Quiz.cs",
|
||||
"RelativeDocumentMoniker": "Response\\Quiz.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Response\\Quiz.cs",
|
||||
"RelativeToolTip": "Response\\Quiz.cs",
|
||||
"ViewState": "AQIAAAAAAAAAAAAAAAAAAA0AAAAWAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-13T08:59:40.254Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"Title": "ExecuteExcelService.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Service\\ExecuteExcelService.cs",
|
||||
"RelativeDocumentMoniker": "Service\\ExecuteExcelService.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Service\\ExecuteExcelService.cs",
|
||||
"RelativeToolTip": "Service\\ExecuteExcelService.cs",
|
||||
"ViewState": "AQIAAA8AAAAAAAAAAAAAADAAAAAAAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-13T03:41:10.651Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "QuestionOption.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Response\\QuestionOption.cs",
|
||||
"RelativeDocumentMoniker": "Response\\QuestionOption.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Response\\QuestionOption.cs",
|
||||
"RelativeToolTip": "Response\\QuestionOption.cs",
|
||||
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAYAAAAWAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-10T06:59:55.277Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"Title": "ExcelValidator.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Service\\ExcelValidator.cs",
|
||||
"RelativeDocumentMoniker": "Service\\ExcelValidator.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Service\\ExcelValidator.cs",
|
||||
"RelativeToolTip": "Service\\ExcelValidator.cs",
|
||||
"ViewState": "AQIAAFcAAAAAAAAAAAAQwEwAAAAJAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-10T03:12:07.301Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"Title": "DataUtil.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Service\\DataUtil.cs",
|
||||
"RelativeDocumentMoniker": "Service\\DataUtil.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Service\\DataUtil.cs",
|
||||
"RelativeToolTip": "Service\\DataUtil.cs",
|
||||
"ViewState": "AQIAABsBAAAAAAAAAAAwwEABAAAAAAAA",
|
||||
"ViewState": "AQIAAAAAAAAAAAAAAAAAABEAAAAJAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-29T01:45:12.308Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"DocumentIndex": 1,
|
||||
"Title": "Form1.Designer.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Form1.Designer.cs",
|
||||
"RelativeDocumentMoniker": "Form1.Designer.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Form1.Designer.cs",
|
||||
"RelativeToolTip": "Form1.Designer.cs",
|
||||
"ViewState": "AQIAABoBAAAAAAAAAAAYwCcBAAAwAAAA",
|
||||
"ViewState": "AQIAAE8AAAAAAAAAAAAuwGUAAAAxAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-09-30T04:14:48.709Z",
|
||||
"EditorCaption": ""
|
||||
"WhenOpened": "2025-09-30T04:14:48.709Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"DocumentIndex": 10,
|
||||
"Title": "Form2.Designer.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\Form2.Designer.cs",
|
||||
"RelativeDocumentMoniker": "Form2.Designer.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\Form2.Designer.cs",
|
||||
"RelativeToolTip": "Form2.Designer.cs",
|
||||
"ViewState": "AQIAAAAAAAAAAAAAAAAAACcAAAAbAAAA",
|
||||
"ViewState": "AQIAAAAAAAAAAAAAAAAAADYAAAAgAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-10-02T06:23:49.946Z"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"DocumentIndex": 7,
|
||||
"Title": "DbHelper.cs",
|
||||
"DocumentMoniker": "E:\\QuizMaster\\QuizMaster\\DbHelper.cs",
|
||||
"RelativeDocumentMoniker": "DbHelper.cs",
|
||||
"ToolTip": "E:\\QuizMaster\\QuizMaster\\DbHelper.cs",
|
||||
"RelativeToolTip": "DbHelper.cs",
|
||||
"ViewState": "AQIAADAAAAAAAAAAAAAYwBIAAAAPAAAA",
|
||||
"ViewState": "AQIAADYAAAAAAAAAAAAYwBIAAAAPAAAA",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-26T01:35:21.294Z"
|
||||
}
|
||||
|
||||
8
QuizMaster/Form1.Designer.cs
generated
8
QuizMaster/Form1.Designer.cs
generated
@ -98,8 +98,8 @@
|
||||
panelcb.BorderStyle = BorderStyle.FixedSingle;
|
||||
panelcb.Location = new Point(50, 50);
|
||||
panelcb.Name = "panelcb";
|
||||
panelcb.Size = new Size(600, 300);
|
||||
panelcb.MaximumSize = new Size(600, 300);
|
||||
panelcb.Size = new Size(770, 200);
|
||||
panelcb.MaximumSize = new Size(770, 400);
|
||||
panelcb.TabIndex = 1;
|
||||
panelcb.AutoScroll = true;
|
||||
panelcb.AutoSize = true;
|
||||
@ -113,8 +113,8 @@
|
||||
panelop.Controls.Add(lblNumberOfCopies);
|
||||
panelop.Controls.Add(txtNumberOfCopies);
|
||||
panelop.Name = "panelop";
|
||||
panelop.Size = new Size(600, 100);
|
||||
panelop.MaximumSize = new Size(600, 300);
|
||||
panelop.Size = new Size(770, 100);
|
||||
panelop.MaximumSize = new Size(770, 300);
|
||||
panelop.TabIndex = 2;
|
||||
panelop.AutoScroll = true;
|
||||
panelop.AutoSize = true;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
3
QuizMaster/Form2.Designer.cs
generated
3
QuizMaster/Form2.Designer.cs
generated
@ -35,6 +35,7 @@
|
||||
this.txtResult.Location = new System.Drawing.Point(0, 0);
|
||||
this.txtResult.Name = "txtResult";
|
||||
this.txtResult.Size = new System.Drawing.Size(800, 450);
|
||||
this.txtResult.WordWrap = true;
|
||||
this.txtResult.TabIndex = 0;
|
||||
//
|
||||
//btnExoortWord
|
||||
@ -49,8 +50,8 @@
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||
this.Controls.Add(this.txtResult);
|
||||
this.Controls.Add(this.btnExportWord);
|
||||
this.Controls.Add(this.txtResult);
|
||||
this.Name = "Form2";
|
||||
this.Text = "Kết quả Generate";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
@ -4,7 +4,6 @@ using System.Windows.Forms;
|
||||
using Xceed.Words.NET;
|
||||
using Xceed.Document.NET;
|
||||
|
||||
|
||||
namespace QuizMaster
|
||||
{
|
||||
public partial class Form2 : Form
|
||||
@ -16,7 +15,7 @@ namespace QuizMaster
|
||||
{
|
||||
InitializeComponent();
|
||||
_content = content;
|
||||
txtResult.Text = content;
|
||||
txtResult.Text = _content.Replace("\n", Environment.NewLine);
|
||||
}
|
||||
|
||||
private void btnExportWord_Click(object sender, EventArgs e)
|
||||
|
||||
Binary file not shown.
@ -6,5 +6,7 @@
|
||||
public string Question { get; set; }
|
||||
public string Option { get; set; }
|
||||
public int IsCorrect { get; set; } // 1 = đúng, 0 = sai
|
||||
public string DoKho { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ namespace QuizMaster.Response
|
||||
public string? B { get; set; }
|
||||
public string? C { get; set; }
|
||||
public string? D { get; set; }
|
||||
public required string DapAn { get; set; }
|
||||
public required List<string> DapAn { get; set; } = new List<string>();
|
||||
public string DoKho { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ namespace QuizMaster.Service
|
||||
|
||||
// 1. Kiểm tra xem câu hỏi đã tồn tại chưa
|
||||
var questionIdCmd = new NpgsqlCommand(@"
|
||||
SELECT id FROM question WHERE content = @content AND category_id = @category_id;
|
||||
SELECT id FROM question WHERE content = @content AND category_id = @category_id;
|
||||
", conn);
|
||||
|
||||
questionIdCmd.Parameters.AddWithValue("content", questionContent);
|
||||
@ -42,9 +42,9 @@ namespace QuizMaster.Service
|
||||
try
|
||||
{
|
||||
var cmd = new NpgsqlCommand(@"
|
||||
SELECT name
|
||||
FROM category
|
||||
ORDER BY name;
|
||||
SELECT name
|
||||
FROM category
|
||||
ORDER BY name;
|
||||
", conn);
|
||||
|
||||
await using var reader = await cmd.ExecuteReaderAsync();
|
||||
@ -75,11 +75,11 @@ namespace QuizMaster.Service
|
||||
try
|
||||
{
|
||||
var cmd = new NpgsqlCommand(@"
|
||||
SELECT c.name
|
||||
FROM category c
|
||||
INNER JOIN department d ON c.department_id = d.id
|
||||
WHERE d.name = @departmentName
|
||||
ORDER BY c.name;
|
||||
SELECT c.name
|
||||
FROM category c
|
||||
INNER JOIN department d ON c.department_id = d.id
|
||||
WHERE d.name = @departmentName
|
||||
ORDER BY c.name;
|
||||
", conn);
|
||||
|
||||
cmd.Parameters.AddWithValue("departmentName", departmentName);
|
||||
@ -103,6 +103,48 @@ namespace QuizMaster.Service
|
||||
return categories;
|
||||
}
|
||||
|
||||
public static async Task<List<CategoryInfo>> GetTotalOptionQuestionsAsync(List<string> lstCategory, string DoKho)
|
||||
{
|
||||
var categories = new List<CategoryInfo>();
|
||||
if (lstCategory == null || lstCategory.Count == 0)
|
||||
{
|
||||
return categories;
|
||||
}
|
||||
string whereCate = string.Join(",", lstCategory.Select(c => $"'{c.Replace("'", "''")}'"));
|
||||
await using var conn = new NpgsqlConnection(DbHelper.connectionString);
|
||||
await conn.OpenAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var cmd = new NpgsqlCommand($@"
|
||||
SELECT c.name, COUNT(q.id) AS Total
|
||||
FROM question q
|
||||
INNER JOIN category c ON q.category_id = c.id
|
||||
WHERE c.name IN ({whereCate})
|
||||
AND q.level = '{DoKho}'
|
||||
GROUP BY c.name
|
||||
ORDER BY c.name;
|
||||
", conn);
|
||||
|
||||
await using var reader = await cmd.ExecuteReaderAsync();
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
categories.Add(new CategoryInfo
|
||||
{
|
||||
Category = reader.GetString(0),
|
||||
Total = reader.GetInt32(1)
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Lỗi khi lấy danh sách số câu khó: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
throw;
|
||||
}
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
public static async Task<List<CategoryInfo>> GetTotalCategoriesAsync(List<string> lstCategory)
|
||||
{
|
||||
var categories = new List<CategoryInfo>();
|
||||
@ -117,12 +159,12 @@ namespace QuizMaster.Service
|
||||
try
|
||||
{
|
||||
var cmd = new NpgsqlCommand($@"
|
||||
SELECT c.name, COUNT(q.id) AS Total
|
||||
FROM question q
|
||||
INNER JOIN category c ON q.category_id = c.id
|
||||
WHERE c.name IN ({whereCate})
|
||||
GROUP BY c.name
|
||||
ORDER BY c.name;
|
||||
SELECT c.name, COUNT(q.id) AS Total
|
||||
FROM question q
|
||||
INNER JOIN category c ON q.category_id = c.id
|
||||
WHERE c.name IN ({whereCate})
|
||||
GROUP BY c.name
|
||||
ORDER BY c.name;
|
||||
", conn);
|
||||
|
||||
await using var reader = await cmd.ExecuteReaderAsync();
|
||||
@ -144,7 +186,6 @@ namespace QuizMaster.Service
|
||||
return categories;
|
||||
}
|
||||
|
||||
|
||||
public static async Task<List<QuestionOption>> getAllQA(string Category)
|
||||
{
|
||||
var questionOption = new List<QuestionOption>();
|
||||
@ -154,13 +195,12 @@ namespace QuizMaster.Service
|
||||
|
||||
try
|
||||
{
|
||||
var cmd = new NpgsqlCommand(@"
|
||||
SELECT q.id, q.content, o.option_text, o.is_correct
|
||||
FROM question q
|
||||
INNER JOIN question_option o ON o.question_id = q.id
|
||||
INNER JOIN category c ON q.category_id = c.id
|
||||
WHERE c.name = @category
|
||||
ORDER BY q.id, o.id;
|
||||
var cmd = new NpgsqlCommand(@"SELECT q.id, q.content, q.level, o.option_text, o.is_correct
|
||||
FROM question q
|
||||
INNER JOIN question_option o ON o.question_id = q.id
|
||||
INNER JOIN category c ON q.category_id = c.id
|
||||
WHERE c.name = @category
|
||||
ORDER BY q.id, o.id
|
||||
", conn);
|
||||
|
||||
cmd.Parameters.AddWithValue("category", Category);
|
||||
@ -170,10 +210,11 @@ namespace QuizMaster.Service
|
||||
{
|
||||
questionOption.Add(new QuestionOption
|
||||
{
|
||||
QuestionId = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
|
||||
Question = reader.IsDBNull(1) ? string.Empty : reader.GetString(1),
|
||||
Option = reader.IsDBNull(2) ? string.Empty : reader.GetString(2),
|
||||
IsCorrect = reader.IsDBNull(3) ? 0 : reader.GetInt32(3)
|
||||
QuestionId = reader.GetInt32(0),
|
||||
Question = reader.GetString(1),
|
||||
DoKho = reader.IsDBNull(2) ? "" : reader.GetString(2),
|
||||
Option = reader.IsDBNull(3) ? string.Empty : reader.GetString(3),
|
||||
IsCorrect = reader.IsDBNull(4) ? 0 : reader.GetInt32(4)
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -186,37 +227,78 @@ namespace QuizMaster.Service
|
||||
return questionOption;
|
||||
}
|
||||
|
||||
|
||||
public static async Task<bool> InsertQuestionAndOptionsAsync(List<Quiz> questions)
|
||||
{
|
||||
if (questions == null || questions.Count == 0)
|
||||
return false;
|
||||
|
||||
await using var conn = new NpgsqlConnection(DbHelper.connectionString);
|
||||
await conn.OpenAsync();
|
||||
await using var transaction = await conn.BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
// --- 1. Cache categoryId ---
|
||||
var categoryCache = new Dictionary<string, int>();
|
||||
foreach (var q in questions)
|
||||
{
|
||||
// Lấy category_id
|
||||
var cmdCategory = new NpgsqlCommand("SELECT id FROM category WHERE name = @name", conn, transaction);
|
||||
cmdCategory.Parameters.AddWithValue("name", q.LinhVuc);
|
||||
var categoryIdObj = await cmdCategory.ExecuteScalarAsync();
|
||||
if (categoryIdObj == null)
|
||||
throw new Exception($"Category '{q.LinhVuc}' không tồn tại.");
|
||||
if (!categoryCache.ContainsKey(q.LinhVuc))
|
||||
{
|
||||
var cmdCategory = new NpgsqlCommand(
|
||||
"SELECT id FROM category WHERE name = @name", conn, transaction);
|
||||
cmdCategory.Parameters.AddWithValue("name", q.LinhVuc);
|
||||
var categoryIdObj = await cmdCategory.ExecuteScalarAsync();
|
||||
if (categoryIdObj == null)
|
||||
throw new Exception($"Category '{q.LinhVuc}' không tồn tại.");
|
||||
categoryCache[q.LinhVuc] = (int)categoryIdObj;
|
||||
}
|
||||
}
|
||||
|
||||
int categoryId = (int)categoryIdObj;
|
||||
// --- 2. Batch insert questions ---
|
||||
var batchQuestions = new NpgsqlBatch(conn, transaction);
|
||||
foreach (var q in questions)
|
||||
{
|
||||
var cmd = new NpgsqlBatchCommand(@"
|
||||
INSERT INTO question (content, category_id, level)
|
||||
VALUES (@content, @categoryId, @level)
|
||||
RETURNING id;
|
||||
");
|
||||
cmd.Parameters.AddWithValue("content", q.CauHoi);
|
||||
cmd.Parameters.AddWithValue("categoryId", categoryCache[q.LinhVuc]);
|
||||
cmd.Parameters.AddWithValue("level", q.DoKho);
|
||||
batchQuestions.BatchCommands.Add(cmd);
|
||||
}
|
||||
|
||||
// Insert Question
|
||||
var cmdQuestion = new NpgsqlCommand(@"
|
||||
INSERT INTO question (content, category_id)
|
||||
VALUES (@content, @categoryId)
|
||||
RETURNING id;
|
||||
", conn, transaction);
|
||||
cmdQuestion.Parameters.AddWithValue("content", q.CauHoi);
|
||||
cmdQuestion.Parameters.AddWithValue("categoryId", categoryId);
|
||||
// --- 3. Execute batch question và lấy questionId ---
|
||||
var questionIds = new List<int>();
|
||||
await using (var reader = await batchQuestions.ExecuteReaderAsync())
|
||||
{
|
||||
foreach (var _ in questions)
|
||||
{
|
||||
if (!await reader.ReadAsync())
|
||||
throw new Exception("Không lấy đủ questionId từ batch.");
|
||||
questionIds.Add(reader.GetInt32(0));
|
||||
|
||||
// Chuyển sang result set tiếp theo (mỗi INSERT RETURNING tạo 1 result set)
|
||||
await reader.NextResultAsync();
|
||||
}
|
||||
}
|
||||
|
||||
// --- 4. Batch insert options ---
|
||||
var batchOptions = new NpgsqlBatch(conn, transaction);
|
||||
for (int i = 0; i < questions.Count; i++)
|
||||
{
|
||||
var q = questions[i];
|
||||
var qid = questionIds[i];
|
||||
|
||||
if (q.DapAn == null || q.DapAn.Count == 0 || q.DapAn.Any(a => !"ABCD".Contains(a)))
|
||||
{
|
||||
var dapAnStr = q.DapAn != null ? string.Join(",", q.DapAn) : "(null)";
|
||||
throw new Exception($"Câu hỏi '{q.CauHoi}' có đáp án không hợp lệ: {dapAnStr}");
|
||||
}
|
||||
|
||||
int questionId = (int)await cmdQuestion.ExecuteScalarAsync();
|
||||
|
||||
// Insert QuestionOption
|
||||
var options = new Dictionary<string, string?>
|
||||
{
|
||||
{ "A", q.A },
|
||||
@ -227,19 +309,20 @@ namespace QuizMaster.Service
|
||||
|
||||
foreach (var opt in options)
|
||||
{
|
||||
var cmdOption = new NpgsqlCommand(@"
|
||||
INSERT INTO question_option (question_id, option_text, is_correct)
|
||||
VALUES (@questionId, @optionText, @isCorrect);
|
||||
", conn, transaction);
|
||||
|
||||
cmdOption.Parameters.AddWithValue("questionId", questionId);
|
||||
var cmdOption = new NpgsqlBatchCommand(@"
|
||||
INSERT INTO question_option (question_id, option_text, is_correct)
|
||||
VALUES (@questionId, @optionText, @isCorrect);
|
||||
");
|
||||
cmdOption.Parameters.AddWithValue("questionId", qid);
|
||||
cmdOption.Parameters.AddWithValue("optionText", opt.Value ?? (object)DBNull.Value);
|
||||
cmdOption.Parameters.AddWithValue("isCorrect", opt.Key == q.DapAn ? 1 : 0);
|
||||
|
||||
await cmdOption.ExecuteNonQueryAsync();
|
||||
cmdOption.Parameters.AddWithValue("isCorrect", q.DapAn.Contains(opt.Key) ? 1 : 0);
|
||||
batchOptions.BatchCommands.Add(cmdOption);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 5. Execute batch options ---
|
||||
await batchOptions.ExecuteNonQueryAsync();
|
||||
|
||||
await transaction.CommitAsync();
|
||||
return true;
|
||||
}
|
||||
@ -250,6 +333,7 @@ namespace QuizMaster.Service
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static async Task<int> GetTotalQuestionCount()
|
||||
{
|
||||
string query = "SELECT COUNT(*) FROM Question";
|
||||
@ -267,26 +351,6 @@ namespace QuizMaster.Service
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
|
||||
//public static async Task<List<Question>> GetRandomQuestions(int requestedCount)
|
||||
//{
|
||||
// int totalCount = await GetTotalQuestionCount();
|
||||
|
||||
// if (requestedCount <= 0)
|
||||
// {
|
||||
// MessageBox.Show("Vui lòng nhập số lượng lớn hơn 0.", "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
// return new List<Question>();
|
||||
// }
|
||||
|
||||
// if (requestedCount > totalCount)
|
||||
// {
|
||||
// MessageBox.Show($"Chỉ có {totalCount} câu hỏi trong cơ sở dữ liệu.", "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
// return new List<Question>();
|
||||
// }
|
||||
|
||||
// string query = $"SELECT * FROM Question ORDER BY RANDOM() LIMIT {requestedCount}";
|
||||
// return await DbHelper.ExecuteSelectQuery<Question>(query);
|
||||
//}
|
||||
|
||||
public static async Task<List<string>> GetDepartmentsAsync()
|
||||
{
|
||||
List<string> deplist = new List<string>();
|
||||
@ -316,5 +380,6 @@ namespace QuizMaster.Service
|
||||
return deplist;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using OfficeOpenXml;
|
||||
using Xceed.Document.NET;
|
||||
|
||||
namespace QuizMaster.Service
|
||||
{
|
||||
@ -11,7 +13,7 @@ namespace QuizMaster.Service
|
||||
{
|
||||
private static readonly List<string> ExpectedHeaders = new()
|
||||
{
|
||||
"Lĩnh vực", "Câu hỏi", "A", "B", "C", "D", "Đáp án"
|
||||
"Lĩnh vực", "Câu hỏi", "A", "B", "C", "D", "Đáp án", "Độ khó"
|
||||
};
|
||||
|
||||
public sealed class RowData
|
||||
@ -23,11 +25,14 @@ namespace QuizMaster.Service
|
||||
public string B { get; init; } = string.Empty;
|
||||
public string C { get; init; } = string.Empty;
|
||||
public string D { get; init; } = string.Empty;
|
||||
public string Answer { get; init; } = string.Empty;
|
||||
public List<string> Answers { get; init; } = new List<string>();
|
||||
public string Level { get; init; } = string.Empty;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static List<string> ValidateHeaders(OfficeOpenXml.ExcelWorksheet worksheet)
|
||||
public static List<string> ValidateHeaders(OfficeOpenXml.ExcelWorksheet worksheet)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
for (int i = 0; i < ExpectedHeaders.Count; i++)
|
||||
@ -50,6 +55,9 @@ namespace QuizMaster.Service
|
||||
if (string.IsNullOrWhiteSpace(data.Question))
|
||||
errors.Add($"Dòng {data.Row}: 'Câu hỏi' không được trống");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(data.Level))
|
||||
errors.Add($"Dòng {data.Row}: 'Độ khó' không được trống");
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
@ -71,31 +79,40 @@ namespace QuizMaster.Service
|
||||
public static List<string> ValidateRowAnswer(RowData data)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
if (string.IsNullOrWhiteSpace(data.Answer))
|
||||
|
||||
if (data.Answers == null || data.Answers.Count == 0)
|
||||
{
|
||||
errors.Add($"Dòng {data.Row}: 'Đáp án' không được trống");
|
||||
return errors;
|
||||
}
|
||||
|
||||
var valid = new[] { "A", "B", "C", "D" };
|
||||
if (!valid.Contains(data.Answer))
|
||||
{
|
||||
errors.Add($"Dòng {data.Row}: 'Đáp án' phải là A, B, C hoặc D (hiện tại là '{data.Answer}')");
|
||||
return errors;
|
||||
}
|
||||
var validOptions = new HashSet<string> { "A", "B", "C", "D" };
|
||||
|
||||
bool answerPointsToEmpty = (data.Answer == "A" && string.IsNullOrWhiteSpace(data.A)) ||
|
||||
(data.Answer == "B" && string.IsNullOrWhiteSpace(data.B)) ||
|
||||
(data.Answer == "C" && string.IsNullOrWhiteSpace(data.C)) ||
|
||||
(data.Answer == "D" && string.IsNullOrWhiteSpace(data.D));
|
||||
if (answerPointsToEmpty)
|
||||
foreach (var ans in data.Answers)
|
||||
{
|
||||
errors.Add($"Dòng {data.Row}: 'Đáp án' {data.Answer} không hợp lệ vì phương án {data.Answer} đang trống");
|
||||
if (!validOptions.Contains(ans))
|
||||
{
|
||||
errors.Add($"Dòng {data.Row}: 'Đáp án' phải là A, B, C hoặc D (phát hiện '{ans}')");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isEmptyOption =
|
||||
(ans == "A" && string.IsNullOrWhiteSpace(data.A)) ||
|
||||
(ans == "B" && string.IsNullOrWhiteSpace(data.B)) ||
|
||||
(ans == "C" && string.IsNullOrWhiteSpace(data.C)) ||
|
||||
(ans == "D" && string.IsNullOrWhiteSpace(data.D));
|
||||
|
||||
if (isEmptyOption)
|
||||
{
|
||||
errors.Add($"Dòng {data.Row}: 'Đáp án' {ans} không hợp lệ vì phương án {ans} đang trống");
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________________
|
||||
|
||||
public static List<string> ValidateRowDuplicate(RowData data, Dictionary<string, int> questionOptionDict)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
@ -134,6 +151,12 @@ namespace QuizMaster.Service
|
||||
var firstCell = worksheet.Cells[row, 1];
|
||||
if (string.IsNullOrWhiteSpace(firstCell.Text)) break; // Dòng trống → kết thúc
|
||||
|
||||
var answerText = worksheet.Cells[row, 7].Text.Trim().ToUpper();
|
||||
var answers = Regex.Matches(answerText.ToUpper(), "[ABCD]")
|
||||
.Select(m => m.Value.Trim())
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
var data = new RowData
|
||||
{
|
||||
Row = row,
|
||||
@ -143,7 +166,8 @@ namespace QuizMaster.Service
|
||||
B = worksheet.Cells[row, 4].Text.Trim(),
|
||||
C = worksheet.Cells[row, 5].Text.Trim(),
|
||||
D = worksheet.Cells[row, 6].Text.Trim(),
|
||||
Answer = worksheet.Cells[row, 7].Text.Trim().ToUpper()
|
||||
Answers = answers,
|
||||
Level = worksheet.Cells[row, 8].Text.Trim()
|
||||
};
|
||||
|
||||
errors.AddRange(ValidateRowRequired(data));
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using OfficeOpenXml;
|
||||
using QuizMaster.Response;
|
||||
@ -21,6 +22,8 @@ namespace QuizMaster.Service
|
||||
|
||||
for (int row = 2; row <= rowCount; row++) // Bắt đầu từ dòng 2, bỏ dòng tiêu đề
|
||||
{
|
||||
var answerText = worksheet.Cells[row, 7].Text.Trim().ToUpper();
|
||||
|
||||
var ch = new Quiz
|
||||
{
|
||||
LinhVuc = worksheet.Cells[row, 1].Text,
|
||||
@ -29,13 +32,16 @@ namespace QuizMaster.Service
|
||||
B = worksheet.Cells[row, 4].Text,
|
||||
C = worksheet.Cells[row, 5].Text,
|
||||
D = worksheet.Cells[row, 6].Text,
|
||||
DapAn = worksheet.Cells[row, 7].Text
|
||||
};
|
||||
|
||||
DapAn = Regex.Matches(answerText.ToUpper(), "[ABCD]")
|
||||
.Select(m => m.Value.Trim())
|
||||
.Distinct()
|
||||
.ToList(),
|
||||
DoKho = worksheet.Cells[row, 8].Text
|
||||
};
|
||||
result.Add(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user