This commit is contained in:
ker73rus 2023-06-21 21:38:05 +04:00
parent 9a6f9e100b
commit 71de67e722
16 changed files with 716 additions and 47 deletions

View File

@ -13,10 +13,7 @@ namespace UniversityContracts.BusinessLogicContracts
List<ReportDisciplineViewModel> GetDiscipline(ReportBindingModel model);
List<ReportStreamEducationStatusViewModel> StreamEducationStatus(List<StreamViewModel> streams);
void SaveBlanksToWordFile(ReportBindingModel model);
void SaveDocumentBlankToExcelFile(ReportBindingModel model);
void SaveOrdersToPdfFile(ReportBindingModel model);
byte[] SaveListFile(StreamStudentBindingModel model);
void SendByMailStatusReport(ReportBindingModel reportModel);
}
}

View File

@ -129,7 +129,7 @@ namespace UniversityProvider.Controllers
return Array.Empty<int>();
}
byte[]? file = APIClient.PostRequestWithResult<StreamStudentBindingModel, byte[]>
("api/reportprovider/streamstudentlist", listModel);
("api/reportcustomer/streamstudentlist", listModel);
return file!.Select(b => (int)b).ToArray();
}

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using UniversityContracts.BindingModels;
using UniversityContracts.BusinessLogicContracts;
using UniversityContracts.ViewModels;
namespace UniversityRestAPI.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ReportCustomerController : Controller
{
private readonly IReportCustomerLogic reportLogic;
public ReportCustomerController(IReportCustomerLogic reportLogic)
{
this.reportLogic = reportLogic;
}
[HttpPost]
public byte[] StreamStudentList(StreamStudentBindingModel listModel)
{
byte[] file = reportLogic.SaveListFile(listModel);
return file;
}
[HttpPost]
public List<ReportDisciplineViewModel> GetReportData(ReportBindingModel reportModel)
{
var list = reportLogic.GetDiscipline(reportModel);
return list;
}
[HttpPost]
public void SendByMailStatusReport(ReportBindingModel reportModel)
{
reportLogic.SendByMailStatusReport(reportModel);
}
}
}

View File

@ -14,4 +14,11 @@
<ProjectReference Include="..\UniversityContracts\UniversityContracts.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="Views\EducationGroup\Update.cshtml">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>

View File

@ -1 +1,41 @@

@{
ViewData["Title"] = "Группа обучения";
}
@{
<div class="text-center" id="document-data" data-id="@ViewBag.Document.Id">
<h1 class="display-4">Обновление приказа</h1>
</div>
<div id="error-div-shell" class="error-div-shell mb-2">
<div>
<p id="error-p" class="error-p text-danger"></p>
</div>
</div>
<p class="mb-0">Название:</p>
<input type="text" value="@ViewBag.Document.Name" id="name-input" name="name" class="form-control mb-3" />
<button id="create-button" type="button" class="btn btn-primary text-button">
Сохранить изменения
</button>
<div class="mt-4">
<div class="scrollable-table">
<table class="table table-bordered">
<thead class="thead-light">
<tr>
<th>Имя</th>
<th>Фамилия</th>
<th>Дата рождения</th>
<th>Номер студ. билета</th>
<th>Статус обучения</th>
</tr>
</thead>
<tbody id="scrollable-table__tbody">
</tbody>
</table>
</div>
</div>
}
<script src="~/js/document/document-update.js" asp-append-version="true"></script>

View File

@ -17,7 +17,14 @@
<option>docx</option>
<option>xlsx</option>
</select>
<div class="row">
<div class="col-md-6">
<label for="streamsSelect">Потоки:</label>
<select id="streamsSelect">
</select>
</div>
</div>
<button id="create-button" type="button" class="btn btn-primary mt-4">
Получить список по выбранным записям
</button>

View File

@ -1 +1,109 @@

const createBtn = document.getElementById("create-button");
const tbody = document.getElementById("scrollable-table__tbody");
const nameInput = document.getElementById("name-input");
const currentDocumentId = document.getElementById("document-data").dataset.id;
var students = [];
var dataArray = [];
var currentDocument = null;
const errorP = document.getElementById("error-p");
const errorDivShell = document.getElementById("error-div-shell");
const correctData = () => {
return true;
};
const validate = () => {
if (nameInput.value === "") {
errorDivShell.style.gridTemplateRows = "1fr";
errorP.innerHTML = "Заполните поле 'Название'";
return false;
}
if (dataArray.length === 0) {
errorDivShell.style.gridTemplateRows = "1fr";
errorP.innerHTML = "Заполните список 'Студенты'";
return false;
}
return true;
};
window.addEventListener('load', async () => {
await $.ajax({
url: "/student/getallbyuser",
type: "GET",
contentType: "json"
}).done((result) => {
students = result;
});
await $.ajax({
url: `/document/get?id=${currentDocumentId}`,
type: "GET",
contentType: "json"
}).done((result) => {
currentDocument = result;
});
students.forEach((student) => createRowForStudentsTable(student));
})
createBtn.addEventListener('click', () => {
if (!correctData()) {
return;
}
if (!validate()) {
return;
}
var documentGroupsUpdate = {
"Id": currentDocument.id,
"Name": nameInput.value,
"Date": currentDocument.date,
"StreamStudents": dataArray,
"DocumentGroups": currentDocument.documentEdGroups,
}
$.ajax({
url: "/document/update",
type: "POST",
contentType: "application/json",
data: JSON.stringify(documentGroupsUpdate)
}).done(() => {
window.location.href = "/Home/Documents";
});
})
const createRowForStudentsTable = (student) => {
const { id, name, surname, dateOfBirth, studentCard, educationStatusName } = student;
const row = tbody.insertRow();
row.setAttribute("data-id", id);
const cells = [name, surname, formatDate(dateOfBirth), studentCard, educationStatusName];
cells.forEach((value) => {
const cell = row.insertCell();
cell.textContent = value;
});
if (currentDocument.documentStudents.find(x => parseInt(x.id) === parseInt(student.id))) {
row.classList.add("bg-success");
dataArray.push(student);
}
row.addEventListener('click', () => addAndRemoveFromList(row));
};
const formatDate = (dateString) => {
const date = new Date(dateString);
const year = date.getFullYear();
const month = ('0' + (date.getMonth() + 1)).slice(-2);
const day = ('0' + date.getDate()).slice(-2);
return `${year}-${month}-${day}`;
};
const addAndRemoveFromList = (row) => {
var id = parseInt(row.dataset.id);
var index = dataArray.indexOf(students.find(x => x.id === id));
if (index === -1) {
dataArray.push(students.find(x => x.id === id));
row.classList.add("bg-success");
} else {
dataArray.splice(index, 1);
row.classList.remove("bg-success");
}
}

View File

@ -2,23 +2,42 @@
const tbody = document.getElementById("scrollable-table__tbody")
const nameInput = document.getElementById("name-input")
var fileType = document.getElementById("file-type")
const select = document.getElementById("streamsSelect")
var students = []
var streams = []
var dataArray = [];
const wordMIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
const excelMIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
window.addEventListener('load', () => {
$.ajax({
url: "/student/getallbyuser",
window.addEventListener('load', async() => {
const streamsResponse = await $.ajax({
url: `/stream/getallbyuser`,
type: "GET",
contentType: "json"
}).done((result) => {
students = result;
students.forEach((student) => createRowForStudentsTable(student));
});
streams = streamsResponse;
streams.forEach((stream) => {
createStreamOption(stream);
});
})
createBtn.addEventListener('click', () => {
const createStreamOption = (stream) => {
const option = document.createElement("option");
option.value = stream.id;
option.innerHTML = stream.name;
select.appendChild(option);
select.selectedIndex = -1;
}
createBtn.addEventListener('click', async () => {
const st = await $.ajax({
url: `/stream/get?id=${parseInt(select.value)}`,
type: "GET",
contentType: "json"
});
students = st.studentStream;
students.forEach((student) => {
createRowForStudentsTable(student);
})
let listModel = {
"Students": Array.from(dataArray),
"FileType": fileType.value

View File

@ -10,7 +10,7 @@ namespace UniversityDataBaseImplemet
{
if (optionsBuilder.IsConfigured == false)
{
optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=UniversityCourseWork;Username=postgres;Password=123");
optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=UniversityCourseWork;Username=postgres;Password=4757");
}
base.OnConfiguring(optionsBuilder);
}

View File

@ -1,22 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace UniversityDataBaseImplemet.Migrations
{
/// <inheritdoc />
public partial class ccc : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@ -12,8 +12,8 @@ using UniversityDataBaseImplemet;
namespace UniversityDataBaseImplemet.Migrations
{
[DbContext(typeof(Database))]
[Migration("20230520013404_ccc")]
partial class ccc
[Migration("20230520061807_init")]
partial class init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)

View File

@ -0,0 +1,389 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace UniversityDataBaseImplemet.Migrations
{
/// <inheritdoc />
public partial class init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "User",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Login = table.Column<string>(type: "text", nullable: false),
Password = table.Column<string>(type: "text", nullable: false),
Role = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_User", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Documents",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UserId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Documents", x => x.Id);
table.ForeignKey(
name: "FK_Documents_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "EducationGroups",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
NumberOfStudent = table.Column<int>(type: "integer", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EducationGroups", x => x.Id);
table.ForeignKey(
name: "FK_EducationGroups_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "EducationStatuses",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EducationStatuses", x => x.Id);
table.ForeignKey(
name: "FK_EducationStatuses_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Streams",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
Course = table.Column<int>(type: "integer", nullable: false),
UserId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Streams", x => x.Id);
table.ForeignKey(
name: "FK_Streams_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "EducationGroupsDocuments",
columns: table => new
{
EducationGroupId = table.Column<int>(type: "integer", nullable: false),
DocumentId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EducationGroupsDocuments", x => new { x.EducationGroupId, x.DocumentId });
table.ForeignKey(
name: "FK_EducationGroupsDocuments_Documents_DocumentId",
column: x => x.DocumentId,
principalTable: "Documents",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_EducationGroupsDocuments_EducationGroups_EducationGroupId",
column: x => x.EducationGroupId,
principalTable: "EducationGroups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Students",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
Surname = table.Column<string>(type: "text", nullable: false),
DateOfBirth = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DateOfAddmission = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
StudentCard = table.Column<int>(type: "integer", nullable: false),
EducationStatusId = table.Column<int>(type: "integer", nullable: true),
UserId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Students", x => x.Id);
table.ForeignKey(
name: "FK_Students_EducationStatuses_EducationStatusId",
column: x => x.EducationStatusId,
principalTable: "EducationStatuses",
principalColumn: "Id");
table.ForeignKey(
name: "FK_Students_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Discipline",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<int>(type: "integer", nullable: false),
StreamId = table.Column<int>(type: "integer", nullable: false),
Hours = table.Column<int>(type: "integer", nullable: false),
MarkType = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Discipline", x => x.Id);
table.ForeignKey(
name: "FK_Discipline_Streams_StreamId",
column: x => x.StreamId,
principalTable: "Streams",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Discipline_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "EducationGroupsStreams",
columns: table => new
{
EducationGroupId = table.Column<int>(type: "integer", nullable: false),
StreamId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EducationGroupsStreams", x => new { x.EducationGroupId, x.StreamId });
table.ForeignKey(
name: "FK_EducationGroupsStreams_EducationGroups_EducationGroupId",
column: x => x.EducationGroupId,
principalTable: "EducationGroups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_EducationGroupsStreams_Streams_StreamId",
column: x => x.StreamId,
principalTable: "Streams",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "EducationGroupViewModel",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
NumberOfStudent = table.Column<int>(type: "integer", nullable: false),
UserId = table.Column<int>(type: "integer", nullable: false),
StreamId = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_EducationGroupViewModel", x => x.Id);
table.ForeignKey(
name: "FK_EducationGroupViewModel_Streams_StreamId",
column: x => x.StreamId,
principalTable: "Streams",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "StudentDocuments",
columns: table => new
{
StudentId = table.Column<int>(type: "integer", nullable: false),
DocumentId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_StudentDocuments", x => new { x.StudentId, x.DocumentId });
table.ForeignKey(
name: "FK_StudentDocuments_Documents_DocumentId",
column: x => x.DocumentId,
principalTable: "Documents",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_StudentDocuments_Students_StudentId",
column: x => x.StudentId,
principalTable: "Students",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "StudentStreams",
columns: table => new
{
StudentId = table.Column<int>(type: "integer", nullable: false),
StreamId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_StudentStreams", x => new { x.StudentId, x.StreamId });
table.ForeignKey(
name: "FK_StudentStreams_Streams_StreamId",
column: x => x.StreamId,
principalTable: "Streams",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_StudentStreams_Students_StudentId",
column: x => x.StudentId,
principalTable: "Students",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Discipline_StreamId",
table: "Discipline",
column: "StreamId");
migrationBuilder.CreateIndex(
name: "IX_Discipline_UserId",
table: "Discipline",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Documents_UserId",
table: "Documents",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_EducationGroups_UserId",
table: "EducationGroups",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_EducationGroupsDocuments_DocumentId",
table: "EducationGroupsDocuments",
column: "DocumentId");
migrationBuilder.CreateIndex(
name: "IX_EducationGroupsStreams_StreamId",
table: "EducationGroupsStreams",
column: "StreamId");
migrationBuilder.CreateIndex(
name: "IX_EducationGroupViewModel_StreamId",
table: "EducationGroupViewModel",
column: "StreamId");
migrationBuilder.CreateIndex(
name: "IX_EducationStatuses_UserId",
table: "EducationStatuses",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Streams_UserId",
table: "Streams",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_StudentDocuments_DocumentId",
table: "StudentDocuments",
column: "DocumentId");
migrationBuilder.CreateIndex(
name: "IX_Students_EducationStatusId",
table: "Students",
column: "EducationStatusId");
migrationBuilder.CreateIndex(
name: "IX_Students_UserId",
table: "Students",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_StudentStreams_StreamId",
table: "StudentStreams",
column: "StreamId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Discipline");
migrationBuilder.DropTable(
name: "EducationGroupsDocuments");
migrationBuilder.DropTable(
name: "EducationGroupsStreams");
migrationBuilder.DropTable(
name: "EducationGroupViewModel");
migrationBuilder.DropTable(
name: "StudentDocuments");
migrationBuilder.DropTable(
name: "StudentStreams");
migrationBuilder.DropTable(
name: "EducationGroups");
migrationBuilder.DropTable(
name: "Documents");
migrationBuilder.DropTable(
name: "Streams");
migrationBuilder.DropTable(
name: "Students");
migrationBuilder.DropTable(
name: "EducationStatuses");
migrationBuilder.DropTable(
name: "User");
}
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using UniversityContracts.BindingModels;
using UniversityContracts.BusinessLogicContracts;
using UniversityContracts.ViewModels;
namespace UniversityRestAPI.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ReportProviderController : Controller
{
private readonly IReportProviderLogic reportLogic;
public ReportProviderController(IReportProviderLogic reportLogic)
{
this.reportLogic = reportLogic;
}
[HttpPost]
public byte[] StudentDisciplineList(StudentDisciplineListBindingModel listModel)
{
byte[] file = reportLogic.SaveListFile(listModel);
return file;
}
[HttpPost]
public List<ReportStreamStudentEdStatPeriodViewModel> GetReportData(ReportBindingModel reportModel)
{
var list = reportLogic.GetStreamStudentEdStatPeriod(reportModel);
return list;
}
[HttpPost]
public void SendByMailStatusReport(ReportBindingModel reportModel)
{
reportLogic.SendByMailStatusReport(reportModel);
}
}
}

View File

@ -58,12 +58,6 @@ const validate = () => {
};
createBtn.addEventListener("click", () => {
if (!validate()) {
return;
}
if (!correctData()) {
return;
}
let student = {
"Name": nameInput.value,
"Surname": surnameInput.value,

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using UniversityContracts.BindingModels;
using UniversityContracts.BusinessLogicContracts;
using UniversityContracts.ViewModels;
namespace UniversityRestAPI.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ReportCustomerController : Controller
{
private readonly IReportCustomerLogic reportLogic;
public ReportCustomerController(IReportCustomerLogic reportLogic)
{
this.reportLogic = reportLogic;
}
[HttpPost]
public byte[] StreamStudentList(StreamStudentBindingModel listModel)
{
byte[] file = reportLogic.SaveListFile(listModel);
return file;
}
[HttpPost]
public List<ReportDisciplineViewModel> GetReportData(ReportBindingModel reportModel)
{
var list = reportLogic.GetDiscipline(reportModel);
return list;
}
[HttpPost]
public void SendByMailStatusReport(ReportBindingModel reportModel)
{
reportLogic.SendByMailStatusReport(reportModel);
}
}
}

View File

@ -68,6 +68,19 @@ namespace UniversityRestAPI.Controllers
throw;
}
}
[HttpGet]
public List<StudentViewModel>? GetAllByUserAndStream(int userId, int streamId)
{
try
{
return _studentLogic.ReadList(new StudentSearchModel { UserId = userId});
}
catch (Exception ex)
{
throw;
}
}
[HttpGet]
public List<StudentViewModel>? GetMany(int userId, int page)