-
Кто ты воин?
@@ -133,6 +132,10 @@
+
Направление
+
Платник?
diff --git a/src/Otchinslator/Components/Pages/Questionnaire.razor.js b/src/Otchinslator/Components/Pages/Questionnaire.razor.js
index 3c6351b..80c57bb 100644
--- a/src/Otchinslator/Components/Pages/Questionnaire.razor.js
+++ b/src/Otchinslator/Components/Pages/Questionnaire.razor.js
@@ -19,6 +19,7 @@ export function onLoad() {
}
});
+ const specialitySelect = document.getElementById('speciality');
const continueButton = document.querySelector('a[href="/statement"]');
const options = document.querySelectorAll('input[name="options"]');
const kursElements = document.querySelectorAll('input[name="kurs"]');
@@ -31,6 +32,26 @@ export function onLoad() {
const kursElement4 = Array.from(kursElements).find(k => k.getAttribute('aria-label') === '4');
const kursElement5 = Array.from(kursElements).find(k => k.getAttribute('aria-label') === '5');
+ fetch('/api/getSpecialities?institutId=' + localStorage.getItem('institut'))
+ .then(response => response.json())
+ .then(data => {
+ const specialities = data.filter(speciality => speciality.name === 'Программная инженерия');
+ const otherSpecialities = data.filter(speciality => speciality.name !== 'Программная инженерия');
+
+ specialities.concat(otherSpecialities).forEach(speciality => {
+ const option = document.createElement('option');
+ option.value = speciality.id;
+ option.text = speciality.code + " " + (speciality.name.includes('Программная инженерия') ? '🏆 ' + speciality.name : speciality.name);
+ specialitySelect.add(option);
+ });
+
+ let specialityData = localStorage.getItem('speciality');
+ if (specialityData) {
+ specialitySelect.value = specialityData;
+ }
+ validateForm();
+ });
+
// Загрузка данных из хранилища если данные есть
function loadFromLocalStorage() {
const phoneNumber = localStorage.getItem('phoneNumber');
@@ -71,6 +92,7 @@ export function onLoad() {
const isKursSelected = Array.from(kursElements).some(k => k.checked);
const isPhoneNumberValid = phoneNumberInput.value.length === 12;
+ // Блокировка курсов в зависимости от выбранного типа обучения
if (isOptionSelected) {
var typeOfEducation = (Array.from(options).find(option => option.checked).getAttribute('aria-label'));
if (typeOfEducation === "Баклан") {
@@ -100,26 +122,28 @@ export function onLoad() {
kursElement5.disabled = false;
}
}
-
- if (isOptionSelected && isKursSelected && isPhoneNumberValid) {
-
+
+ if (isOptionSelected && isKursSelected && isPhoneNumberValid && specialitySelect.value !== '0') {
continueButton.classList.remove('btn-disabled');
localStorage.setItem('phoneNumber', phoneNumberInput.value);
localStorage.setItem('paid', checkboxPaid.checked);
localStorage.setItem('ochno', !checkboxOchno.checked);
localStorage.setItem('option', typeOfEducation);
localStorage.setItem('kurs', Array.from(kursElements).find(k => k.checked).getAttribute('aria-label'));
+ localStorage.setItem('speciality', specialitySelect.value);
} else {
continueButton.classList.add('btn-disabled');
}
}
+ loadFromLocalStorage();
+
options.forEach(option => option.addEventListener('change', validateForm));
kursElements.forEach(k => k.addEventListener('change', validateForm));
phoneNumberInput.addEventListener('input', validateForm);
checkboxPaid.addEventListener('change', validateForm);
checkboxOchno.addEventListener('change', validateForm);
+ specialitySelect.addEventListener('change', validateForm);
- loadFromLocalStorage();
validateForm();
}
\ No newline at end of file
diff --git a/src/Otchinslator/Components/Pages/Result.razor b/src/Otchinslator/Components/Pages/Result.razor
index 6bdd72e..e93dd3b 100644
--- a/src/Otchinslator/Components/Pages/Result.razor
+++ b/src/Otchinslator/Components/Pages/Result.razor
@@ -1,23 +1,23 @@
-@page "/otchislenie/result"
-@using Microsoft.AspNetCore.Authorization
+@page "/result"
@using Otchinslator.Components.Layout
@layout OtchislenieLayout
+@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
Уже почти | Отчислятор 3000
-
+@*
*@
-
- @*
*@
- @*
*@
- @* $1$ TODO: Сделать адаптив #1# *@
- @*
+
\ No newline at end of file
diff --git a/src/Otchinslator/Components/Pages/Statement.razor.js b/src/Otchinslator/Components/Pages/Statement.razor.js
index b726d25..839ae46 100644
--- a/src/Otchinslator/Components/Pages/Statement.razor.js
+++ b/src/Otchinslator/Components/Pages/Statement.razor.js
@@ -27,13 +27,17 @@ export function onLoad() {
console.log('Начата генерация заявления');
generateStatementModal.showModal();
+ console.log(localStorage.getItem('ochno'))
+
const data = {
"phone": "+7 " + localStorage.getItem('phoneNumber'),
"kurs": localStorage.getItem('kurs'),
"isFreeEducation": localStorage.getItem('paid') === "false",
- "isOchno": localStorage.getItem('ochno') === true,
- "speciality": optionMapping[localStorage.getItem('option')],
- "reason": localStorage.getItem('statement')
+ "isOchno": localStorage.getItem('ochno') === "true",
+ "typeOfEducation": optionMapping[localStorage.getItem('option')],
+ "reason": localStorage.getItem('statement'),
+ "institut": localStorage.getItem('institut'),
+ "direction": localStorage.getItem('speciality')
}
try {
@@ -47,7 +51,7 @@ export function onLoad() {
if (response.ok) {
console.log('Заявление успешно сгенерировано');
- location.href='otchislenie/result';
+ location.href='/result';
} else {
hideLoadingModal();
console.log('Ошибка при генерации заявления');
diff --git a/src/Otchinslator/Controllers/PublicDataController.cs b/src/Otchinslator/Controllers/PublicDataController.cs
new file mode 100644
index 0000000..369ac57
--- /dev/null
+++ b/src/Otchinslator/Controllers/PublicDataController.cs
@@ -0,0 +1,26 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace Otchinslator.Controllers;
+
+[ApiController]
+public class PublicDataController(DatabaseContext db) : Controller
+{
+ [HttpGet("/api/getSpecialities")]
+ public IActionResult GetSpecialities(int institutId)
+ {
+ if (institutId <= 0 || institutId > 4)
+ {
+ return BadRequest("Некорректный институт\nДоступные институты: 1 - ИКТИБ, 2 - ИРТСУ, 3 - ИУЭС, 4 - ИНЭП");
+ }
+
+ var specialities = db.Specialties.Where(s => s.InstitutId == institutId).ToList();
+ var specialitiesDto = specialities.Select(s => new
+ {
+ s.Id,
+ s.Name,
+ s.Code,
+ });
+
+ return Ok(specialitiesDto);
+ }
+}
\ No newline at end of file
diff --git a/src/Otchinslator/Controllers/StatementController.cs b/src/Otchinslator/Controllers/StatementController.cs
index 02361b2..68fd5ba 100644
--- a/src/Otchinslator/Controllers/StatementController.cs
+++ b/src/Otchinslator/Controllers/StatementController.cs
@@ -7,17 +7,17 @@ namespace Otchinslator;
[ApiController]
[Authorize]
-public class StatementController(IStatementGenerator statementGenerator, IConfiguration configuration) : Controller
+public class StatementController(IStatementGenerator statementGenerator, IConfiguration configuration, DatabaseContext db) : Controller
{
[HttpPost("/generateStatement")]
public async Task
GenerateStatement(UserDTO userDto)
{
- var speciality = userDto.speciality switch
+ var speciality = userDto.typeOfEducation switch
{
1 => SpecialityType.Bakalavriat,
2 => SpecialityType.Magistatura,
3 => SpecialityType.Specialitet,
- _ => throw new ArgumentOutOfRangeException()
+ _ => throw new ArgumentOutOfRangeException() // Модель валидации не позволит передать некорректное значение
};
if (speciality == SpecialityType.Bakalavriat && userDto.kurs > 4)
@@ -45,6 +45,13 @@ public class StatementController(IStatementGenerator statementGenerator, IConfig
userFIO = petrovich.InflectFirstNameTo(Case.Genitive) + " " + petrovich.InflectLastNameTo(Case.Genitive) + " " + petrovich.InflectMiddleNameTo(Case.Genitive);
+ var direction = db.Specialties.FirstOrDefault(x => x.Id == userDto.direction);
+ if (direction == null)
+ {
+ Utils.LogToTg("Походу ломают `direction == null`", configuration);
+ return BadRequest("Некорректное направление");
+ }
+
var userData = new UserData
{
reason = userDto.reason,
@@ -54,7 +61,8 @@ public class StatementController(IStatementGenerator statementGenerator, IConfig
kurs = userDto.kurs,
isFreeEducation = userDto.isFreeEducation,
isOchno = userDto.isOchno,
- speciality = speciality
+ speciality = speciality,
+ direction = direction.Code + " " + direction.Name.ToLower()
};
var statement = await statementGenerator.GenerateStatementAsync(userData);
var pdf = await statementGenerator.ConvertToPDFAsync(statement);
@@ -79,12 +87,5 @@ public class StatementController(IStatementGenerator statementGenerator, IConfig
outStream.Position = 0;
return File(outStream, "application/pdf");
}
-
- // [HttpGet("/getUserData")]
- // public async Task getUserdata()
- // {
- // var userFIO = User.Claims.FirstOrDefault(x => x.Type == "name")?.Value;
- // var userdata = User.Identities.FirstOrDefault()?.Claims.Select(x => new {x.Type, x.Value});
- // return Ok(userdata);
- // }
+
}
\ No newline at end of file
diff --git a/src/Otchinslator/DTO/UserDTO.cs b/src/Otchinslator/DTO/UserDTO.cs
index a7a3488..b2bdb1a 100644
--- a/src/Otchinslator/DTO/UserDTO.cs
+++ b/src/Otchinslator/DTO/UserDTO.cs
@@ -20,6 +20,11 @@ public class UserDTO
public bool isOchno { get; set; }
[Required]
[Range(1, 3, ErrorMessage = "Некорректный тип специальности")]
- public int speciality { get; set; }
+ public int typeOfEducation { get; set; }
+ [Required]
+ [Range(1, 4, ErrorMessage = "Некорректный институт")]
+ public int institut { get; set; }
+ [Required]
+ public int direction { get; set; }
}
diff --git a/src/Otchinslator/DatabaseContext.cs b/src/Otchinslator/DatabaseContext.cs
new file mode 100644
index 0000000..79cb0c6
--- /dev/null
+++ b/src/Otchinslator/DatabaseContext.cs
@@ -0,0 +1,49 @@
+using Microsoft.EntityFrameworkCore;
+using Otchinslator.Tables;
+
+namespace Otchinslator;
+
+public class DatabaseContext : DbContext
+{
+ public DbSet Instituts { get; set; }
+ public DbSet Specialties { get; set; }
+ public string DbPath { get; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity().HasKey(i => i.Id);
+ modelBuilder.Entity().HasKey(s => s.Id);
+
+ modelBuilder.Entity().HasData(
+ new Institut() { Id = 1, ShortName = "ИКТИБ", Name = "Институт компьютерных технологий и информационной безопасности" },
+ new Institut() { Id = 2, ShortName = "ИРТСУ", Name = "Институт радиотехнических систем и управления" },
+ new Institut() { Id = 3, ShortName = "ИУЭС", Name = "Институт управления в экономических, экологических и социальных системах" },
+ new Institut() { Id = 4, ShortName = "ИНЭП", Name = "Институт нанотехнологий, электроники и приборостроения" }
+ );
+
+ modelBuilder.Entity().HasData(
+ // ИКТИБ
+ // Бакалавриат
+ new Specialty() { Id = 1, Name = "Математическое обеспечение и администрирование информационных систем", Code = "02.03.03", InstitutId = 1 },
+ new Specialty() { Id = 2, Name = "Информатика и вычислительная техника", Code = "09.03.01", InstitutId = 1 }, // + заочка
+ new Specialty() { Id = 3, Name = "Информационные системы и технологии", Code = "09.03.02", InstitutId = 1 },
+ new Specialty() { Id = 4, Name = "Программная инженерия", Code = "09.03.04", InstitutId = 1 },
+ new Specialty() { Id = 5, Name = "Информационная безопасность", Code = "10.03.01", InstitutId = 1 },
+ new Specialty() { Id = 6, Name = "Системный анализ и управление", Code = "27.03.03", InstitutId = 1 },
+ // Специалитет
+ new Specialty() { Id = 7, Name = "Применение и эксплуатация автоматизированных систем специального назначения", Code = "09.05.01", InstitutId = 1 },
+ new Specialty() { Id = 8, Name = "Информационная безопасность телекоммуникационных систем", Code = "10.05.02", InstitutId = 1 },
+ new Specialty() { Id = 9, Name = "Информационная безопасность автоматизированных систем", Code = "10.05.03", InstitutId = 1 },
+ new Specialty() { Id = 10, Name = "Безопасность информационных технологий в правоохранительной сфере", Code = "10.05.05", InstitutId = 1 }
+ );
+ }
+
+ public DatabaseContext()
+ {
+ var folder = Environment.SpecialFolder.LocalApplicationData;
+ DbPath = System.IO.Path.Join("./", "database.db");
+ }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder options)
+ => options.UseSqlite($"Data Source={DbPath}");
+}
\ No newline at end of file
diff --git a/src/Otchinslator/Program.cs b/src/Otchinslator/Program.cs
index a33b566..3fd6a28 100644
--- a/src/Otchinslator/Program.cs
+++ b/src/Otchinslator/Program.cs
@@ -4,8 +4,10 @@ using Gotenberg.Sharp.API.Client.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Authorization;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
+using Otchinslator;
using Otchinslator.Components;
using Otchinslator.Services;
@@ -26,6 +28,9 @@ builder.Services.Configure(options =>
options.KnownProxies.Clear();
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
+
+builder.Services.AddDbContext();
+
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
diff --git a/src/Otchinslator/Services/IStatementGenerator.cs b/src/Otchinslator/Services/IStatementGenerator.cs
index 8afccc4..6312218 100644
--- a/src/Otchinslator/Services/IStatementGenerator.cs
+++ b/src/Otchinslator/Services/IStatementGenerator.cs
@@ -18,7 +18,7 @@ public class StatementGenerator(GotenbergSharpClient gotenbergSharpClient) : ISt
private const string SpecialitetText = "специалитета по специальности";
private const string BakalavriatText = "бакалавриата по направлению подготовки";
private const string MagistaturaText = "магистратуры по направлению подготовки";
- private const string FreeEducationText = "обучение за счет ассигнований федерального бюджета";
+ private const string FreeEducationText = "за счет ассигнований федерального бюджета";
private const string PaidEducationText = "на договорной (платной) основе";
public async Task GenerateStatementAsync(UserData userData)
@@ -68,7 +68,7 @@ public class StatementGenerator(GotenbergSharpClient gotenbergSharpClient) : ISt
SpecialityType.Magistatura => MagistaturaText,
SpecialityType.Specialitet => SpecialitetText,
_ => throw new ArgumentOutOfRangeException()
- } + " ничего не делания";
+ } + " " + userData.direction;
break;
}
diff --git a/src/Otchinslator/Tables/Institut.cs b/src/Otchinslator/Tables/Institut.cs
new file mode 100644
index 0000000..0193f88
--- /dev/null
+++ b/src/Otchinslator/Tables/Institut.cs
@@ -0,0 +1,10 @@
+namespace Otchinslator.Tables;
+
+public class Institut
+{
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string ShortName { get; set; }
+
+ public List Specialties { get; } = new();
+}
\ No newline at end of file
diff --git a/src/Otchinslator/Tables/Specialty.cs b/src/Otchinslator/Tables/Specialty.cs
new file mode 100644
index 0000000..c5711a2
--- /dev/null
+++ b/src/Otchinslator/Tables/Specialty.cs
@@ -0,0 +1,10 @@
+namespace Otchinslator.Tables;
+
+public class Specialty
+{
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string Code { get; set; }
+ public int InstitutId { get; set; }
+ public Institut Institut { get; set; }
+}
\ No newline at end of file
diff --git a/src/Otchinslator/Templates/ictis.docx b/src/Otchinslator/Templates/ictis.docx
index a539c50..eafdbf8 100644
Binary files a/src/Otchinslator/Templates/ictis.docx and b/src/Otchinslator/Templates/ictis.docx differ
diff --git a/src/Otchinslator/UserData.cs b/src/Otchinslator/UserData.cs
index 8bf9a93..bc14189 100644
--- a/src/Otchinslator/UserData.cs
+++ b/src/Otchinslator/UserData.cs
@@ -12,7 +12,8 @@ public class UserData
int kurs,
bool isFreeEducation,
bool isOchno,
- SpecialityType speciality)
+ SpecialityType speciality,
+ string direction)
{
}
@@ -28,6 +29,7 @@ public class UserData
public bool isFreeEducation { get; set; }
public bool isOchno { get; set; }
public SpecialityType speciality { get; set; }
+ public string direction { get; set; }
}
public enum SpecialityType