статистика по вакансии
This commit is contained in:
parent
6d8d423580
commit
cd61162e19
@ -84,11 +84,10 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
Name = u.Name,
|
Name = u.Name,
|
||||||
LastName = u.LastName,
|
LastName = u.LastName,
|
||||||
Email = u.Email,
|
Email = u.Email,
|
||||||
EmailConfirmed = u.EmailConfirmed,
|
|
||||||
AvatarFilePath = u.AvatarFilePath,
|
|
||||||
Password = u.Password,
|
Password = u.Password,
|
||||||
PhoneNumber = u.PhoneNumber,
|
PhoneNumber = u.PhoneNumber,
|
||||||
Role = u.Role
|
Role = u.Role,
|
||||||
|
DateOfBirth = u.DateOfBirth
|
||||||
}).ToList() ?? new List<UserViewModel>();
|
}).ToList() ?? new List<UserViewModel>();
|
||||||
|
|
||||||
var companyViewModel = new CompanyViewModel
|
var companyViewModel = new CompanyViewModel
|
||||||
|
@ -46,5 +46,35 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
Resume = GetResume(model)
|
Resume = GetResume(model)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ResumeViewModel> GetResumesStatistics(ReportBindingModel model)
|
||||||
|
{
|
||||||
|
var list = _resumeStorage.GetFullList().Where(resume =>
|
||||||
|
(!model.DateFrom.HasValue || resume.CreatedAt >= model.DateFrom.Value) &&
|
||||||
|
(!model.DateTo.HasValue || resume.CreatedAt <= model.DateTo.Value)).ToList();
|
||||||
|
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
item.UserName = _userStorage.GetElement(new UserSearchModel { Id = item.UserId }).Surname + " " + _userStorage.GetElement(new UserSearchModel { Id = item.UserId }).Name + " " + _userStorage.GetElement(new UserSearchModel { Id = item.UserId }).LastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list != null)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveResumesStatisticsToPdf(ReportBindingModel model)
|
||||||
|
{
|
||||||
|
_saveToPdf.CreateDocStatistics(new PdfInfo
|
||||||
|
{
|
||||||
|
FileName = model.FileName,
|
||||||
|
Title = "Статистика по откликам на вакансию",
|
||||||
|
Resumes = GetResumesStatistics(model),
|
||||||
|
DateFrom = model.DateFrom,
|
||||||
|
DateTo = model.DateTo
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,10 +79,10 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
Title = element.Title,
|
Title = element.Title,
|
||||||
Experience = element.Experience,
|
Experience = element.Experience,
|
||||||
Education = element.Education,
|
Education = element.Education,
|
||||||
PhotoFilePath = element.PhotoFilePath,
|
|
||||||
Description = element.Description,
|
Description = element.Description,
|
||||||
Skills = element.Skills,
|
Skills = element.Skills,
|
||||||
Status = element.Status,
|
Status = element.Status,
|
||||||
|
CreatedAt = element.CreatedAt,
|
||||||
Assessments = assessmentViewModels
|
Assessments = assessmentViewModels
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,10 +121,10 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
Title = element.Title,
|
Title = element.Title,
|
||||||
Experience = element.Experience,
|
Experience = element.Experience,
|
||||||
Education = element.Education,
|
Education = element.Education,
|
||||||
PhotoFilePath = element.PhotoFilePath,
|
|
||||||
Description = element.Description,
|
Description = element.Description,
|
||||||
Skills = element.Skills,
|
Skills = element.Skills,
|
||||||
Status = element.Status,
|
Status = element.Status,
|
||||||
|
CreatedAt = element.CreatedAt,
|
||||||
Assessments = assessmentViewModels
|
Assessments = assessmentViewModels
|
||||||
};
|
};
|
||||||
result.Add(resumeViewModel);
|
result.Add(resumeViewModel);
|
||||||
|
@ -77,9 +77,9 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
Title = r.Title,
|
Title = r.Title,
|
||||||
Experience = r.Experience,
|
Experience = r.Experience,
|
||||||
Education = r.Education,
|
Education = r.Education,
|
||||||
PhotoFilePath = r.PhotoFilePath,
|
|
||||||
Description = r.Description,
|
Description = r.Description,
|
||||||
Skills = r.Skills,
|
Skills = r.Skills,
|
||||||
|
CreatedAt = r.CreatedAt,
|
||||||
Status = r.Status
|
Status = r.Status
|
||||||
}).ToList() ?? new List<ResumeViewModel>();
|
}).ToList() ?? new List<ResumeViewModel>();
|
||||||
|
|
||||||
@ -97,11 +97,10 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
LastName = element.LastName,
|
LastName = element.LastName,
|
||||||
Email = element.Email,
|
Email = element.Email,
|
||||||
Password = hashedPassword,
|
Password = hashedPassword,
|
||||||
EmailConfirmed = element.EmailConfirmed,
|
|
||||||
AvatarFilePath = element.AvatarFilePath,
|
|
||||||
CompanyId = element.CompanyId,
|
CompanyId = element.CompanyId,
|
||||||
PhoneNumber = element.PhoneNumber,
|
PhoneNumber = element.PhoneNumber,
|
||||||
Role = element.Role,
|
Role = element.Role,
|
||||||
|
DateOfBirth = element.DateOfBirth,
|
||||||
Resumes = resumeViewModels
|
Resumes = resumeViewModels
|
||||||
};
|
};
|
||||||
_logger.LogInformation("ReadElement: User found. Id: {Id}", element.Id);
|
_logger.LogInformation("ReadElement: User found. Id: {Id}", element.Id);
|
||||||
@ -165,6 +164,11 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
throw new ArgumentNullException("Нет имени пользователя", nameof(model.Name));
|
throw new ArgumentNullException("Нет имени пользователя", nameof(model.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (model.DateOfBirth >= DateTime.Now.ToUniversalTime().AddHours(4))
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("Дата рождения не может быть позже текущей", nameof(model.DateOfBirth));
|
||||||
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(model.Email))
|
if (string.IsNullOrEmpty(model.Email))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("Нет почты пользователя", nameof(model.Email));
|
throw new ArgumentNullException("Нет почты пользователя", nameof(model.Email));
|
||||||
|
@ -70,10 +70,10 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
|||||||
Title = r.Title,
|
Title = r.Title,
|
||||||
Experience = r.Experience,
|
Experience = r.Experience,
|
||||||
Education = r.Education,
|
Education = r.Education,
|
||||||
PhotoFilePath = r.PhotoFilePath,
|
|
||||||
Description = r.Description,
|
Description = r.Description,
|
||||||
Skills = r.Skills,
|
Skills = r.Skills,
|
||||||
Status = r.Status
|
Status = r.Status,
|
||||||
|
CreatedAt = r.CreatedAt
|
||||||
}).ToList() ?? new List<ResumeViewModel>();
|
}).ToList() ?? new List<ResumeViewModel>();
|
||||||
|
|
||||||
var vacancyViewModel = new VacancyViewModel
|
var vacancyViewModel = new VacancyViewModel
|
||||||
|
@ -5,11 +5,42 @@ namespace CandidateReviewBusinessLogic.OfficePackage
|
|||||||
{
|
{
|
||||||
public abstract class AbstractSaveToPdf
|
public abstract class AbstractSaveToPdf
|
||||||
{
|
{
|
||||||
|
public void CreateDocStatistics(PdfInfo info)
|
||||||
|
{
|
||||||
|
CreatePdf(info);
|
||||||
|
|
||||||
|
CreateParagraph(new PdfParagraph
|
||||||
|
{
|
||||||
|
Text = info.Title,
|
||||||
|
Style = "NormalTitle",
|
||||||
|
ParagraphAlignment = PdfParagraphAlignmentType.Center
|
||||||
|
});
|
||||||
|
|
||||||
|
int totalResumes = info.Resumes.Count;
|
||||||
|
|
||||||
|
CreateParagraph(new PdfParagraph
|
||||||
|
{
|
||||||
|
Text = $"Общее количество резюме: {totalResumes}",
|
||||||
|
Style = "Normal",
|
||||||
|
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var resume in info.Resumes)
|
||||||
|
{
|
||||||
|
CreateParagraph(new PdfParagraph
|
||||||
|
{
|
||||||
|
Text = $"- Кандидат: {resume.UserName}, Дата создания: {resume.CreatedAt:dd.MM.yyyy}, Статус: {resume.Status}",
|
||||||
|
Style = "Normal",
|
||||||
|
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||||
|
});
|
||||||
|
}
|
||||||
|
SavePdf(info);
|
||||||
|
}
|
||||||
|
|
||||||
public void CreateDocReportResume(PdfInfo info)
|
public void CreateDocReportResume(PdfInfo info)
|
||||||
{
|
{
|
||||||
CreatePdf(info);
|
CreatePdf(info);
|
||||||
|
|
||||||
// Заголовок резюме
|
|
||||||
CreateParagraph(new PdfParagraph
|
CreateParagraph(new PdfParagraph
|
||||||
{
|
{
|
||||||
Text = $"Резюме: {info.Title}",
|
Text = $"Резюме: {info.Title}",
|
||||||
@ -17,7 +48,6 @@ namespace CandidateReviewBusinessLogic.OfficePackage
|
|||||||
ParagraphAlignment = PdfParagraphAlignmentType.Center
|
ParagraphAlignment = PdfParagraphAlignmentType.Center
|
||||||
});
|
});
|
||||||
|
|
||||||
// ФИО и вакансия
|
|
||||||
CreateParagraph(new PdfParagraph
|
CreateParagraph(new PdfParagraph
|
||||||
{
|
{
|
||||||
Text = $"ФИО: {info.Resume.UserName ?? "Не указано"}",
|
Text = $"ФИО: {info.Resume.UserName ?? "Не указано"}",
|
||||||
@ -32,7 +62,6 @@ namespace CandidateReviewBusinessLogic.OfficePackage
|
|||||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||||
});
|
});
|
||||||
|
|
||||||
// Образование
|
|
||||||
CreateParagraph(new PdfParagraph
|
CreateParagraph(new PdfParagraph
|
||||||
{
|
{
|
||||||
Text = "Образование:",
|
Text = "Образование:",
|
||||||
@ -47,7 +76,6 @@ namespace CandidateReviewBusinessLogic.OfficePackage
|
|||||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||||
});
|
});
|
||||||
|
|
||||||
// Опыт работы
|
|
||||||
CreateParagraph(new PdfParagraph
|
CreateParagraph(new PdfParagraph
|
||||||
{
|
{
|
||||||
Text = "Опыт работы:",
|
Text = "Опыт работы:",
|
||||||
@ -62,7 +90,6 @@ namespace CandidateReviewBusinessLogic.OfficePackage
|
|||||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||||
});
|
});
|
||||||
|
|
||||||
// Навыки
|
|
||||||
CreateParagraph(new PdfParagraph
|
CreateParagraph(new PdfParagraph
|
||||||
{
|
{
|
||||||
Text = "Навыки:",
|
Text = "Навыки:",
|
||||||
@ -77,7 +104,6 @@ namespace CandidateReviewBusinessLogic.OfficePackage
|
|||||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||||
});
|
});
|
||||||
|
|
||||||
// Описание
|
|
||||||
CreateParagraph(new PdfParagraph
|
CreateParagraph(new PdfParagraph
|
||||||
{
|
{
|
||||||
Text = "Описание:",
|
Text = "Описание:",
|
||||||
|
@ -6,8 +6,9 @@ namespace CandidateReviewBusinessLogic.OfficePackage.HelperModels
|
|||||||
{
|
{
|
||||||
public string FileName { get; set; } = string.Empty;
|
public string FileName { get; set; } = string.Empty;
|
||||||
public string Title { get; set; } = string.Empty;
|
public string Title { get; set; } = string.Empty;
|
||||||
public DateTime DateFrom { get; set; }
|
public DateTime? DateFrom { get; set; }
|
||||||
public DateTime DateTo { get; set; }
|
public DateTime? DateTo { get; set; }
|
||||||
public ResumeViewModel Resume { get; set; } = new();
|
public ResumeViewModel Resume { get; set; } = new();
|
||||||
|
public List<ResumeViewModel> Resumes { get; set; } = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,9 @@ namespace CandidateReviewClientApp.Controllers
|
|||||||
CompanyId = companyId,
|
CompanyId = companyId,
|
||||||
Email = APIClient.User.Email,
|
Email = APIClient.User.Email,
|
||||||
Password = APIClient.User.Password,
|
Password = APIClient.User.Password,
|
||||||
EmailConfirmed = APIClient.User.EmailConfirmed,
|
|
||||||
Role = APIClient.User.Role,
|
Role = APIClient.User.Role,
|
||||||
AvatarFilePath = APIClient.User.AvatarFilePath,
|
PhoneNumber = APIClient.User.PhoneNumber,
|
||||||
PhoneNumber = APIClient.User.PhoneNumber
|
DateOfBirth = APIClient.User.DateOfBirth
|
||||||
});
|
});
|
||||||
APIClient.Company = APIClient.GetRequest<CompanyViewModel?>($"api/company/profile?id={companyId}");
|
APIClient.Company = APIClient.GetRequest<CompanyViewModel?>($"api/company/profile?id={companyId}");
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ namespace CandidateReviewUserApp.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult Register(string login, string password, string surname, string name, string lastname)
|
public IActionResult Register(string login, string password, string surname, string name, string lastname, DateTime dateOfBirth)
|
||||||
{
|
{
|
||||||
string returnUrl = HttpContext.Request.Headers["Referer"].ToString();
|
string returnUrl = HttpContext.Request.Headers["Referer"].ToString();
|
||||||
try
|
try
|
||||||
@ -90,8 +90,8 @@ namespace CandidateReviewUserApp.Controllers
|
|||||||
LastName = lastname ?? null,
|
LastName = lastname ?? null,
|
||||||
Email = login,
|
Email = login,
|
||||||
Password = password,
|
Password = password,
|
||||||
EmailConfirmed = false,
|
Role = role,
|
||||||
Role = role
|
DateOfBirth = dateOfBirth
|
||||||
});
|
});
|
||||||
|
|
||||||
return RedirectToAction("Enter");
|
return RedirectToAction("Enter");
|
||||||
|
@ -24,7 +24,6 @@ namespace CandidateReviewClientApp.Controllers
|
|||||||
return Redirect("~Home/Enter");
|
return Redirect("~Home/Enter");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Получение данных резюме
|
|
||||||
var resume = APIClient.GetRequest<ResumeViewModel>($"/api/resume/details?id={id}");
|
var resume = APIClient.GetRequest<ResumeViewModel>($"/api/resume/details?id={id}");
|
||||||
if (resume == null)
|
if (resume == null)
|
||||||
{
|
{
|
||||||
@ -44,7 +43,7 @@ namespace CandidateReviewClientApp.Controllers
|
|||||||
return NotFound("Файл отчета не найден.");
|
return NotFound("Файл отчета не найден.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return PhysicalFile(reportFilePath, "application/pdf", $"Resume_{resume.UserName}.pdf");
|
return PhysicalFile(reportFilePath, "application/pdf", $"Резюме_{resume.UserName}.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@ -169,7 +168,7 @@ namespace CandidateReviewClientApp.Controllers
|
|||||||
{
|
{
|
||||||
throw new Exception("Пользователь не найден");
|
throw new Exception("Пользователь не найден");
|
||||||
}
|
}
|
||||||
if (vacancy != null)
|
if (vacancy != null && model.Status != CandidateReviewDataModels.Enums.ResumeStatusEnum.Черновик)
|
||||||
{
|
{
|
||||||
vacancy.Resumes.Add(new ResumeViewModel
|
vacancy.Resumes.Add(new ResumeViewModel
|
||||||
{
|
{
|
||||||
|
@ -85,10 +85,9 @@ namespace CandidateReviewClientApp.Controllers
|
|||||||
CompanyId = APIClient.Company.Id,
|
CompanyId = APIClient.Company.Id,
|
||||||
Email = model.Email,
|
Email = model.Email,
|
||||||
Password = model.Password,
|
Password = model.Password,
|
||||||
EmailConfirmed = model.EmailConfirmed,
|
|
||||||
Role = CandidateReviewDataModels.Enums.RoleEnum.Сотрудник,
|
Role = CandidateReviewDataModels.Enums.RoleEnum.Сотрудник,
|
||||||
AvatarFilePath = model.AvatarFilePath,
|
PhoneNumber = model.PhoneNumber,
|
||||||
PhoneNumber = model.PhoneNumber
|
DateOfBirth = model.DateOfBirth
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Redirect($"~/Company/CompanyProfile/{model.CompanyId}");
|
return Redirect($"~/Company/CompanyProfile/{model.CompanyId}");
|
||||||
|
@ -14,6 +14,63 @@ namespace CandidateReviewClientApp.Controllers
|
|||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult VacancyStatistics(int id)
|
||||||
|
{
|
||||||
|
if (APIClient.User == null)
|
||||||
|
{
|
||||||
|
return Redirect("~Home/Enter");
|
||||||
|
}
|
||||||
|
|
||||||
|
var vacancy = APIClient.GetRequest<VacancyViewModel>($"/api/vacancy/details?id={id}");
|
||||||
|
if (vacancy == null)
|
||||||
|
{
|
||||||
|
return NotFound("Вакансия не найдена.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewModel = new VacancyStatisticsViewModel
|
||||||
|
{
|
||||||
|
DateFrom = DateTime.UtcNow,
|
||||||
|
DateTo = DateTime.UtcNow,
|
||||||
|
VacancyId = vacancy.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetStatistics(int id, DateTime dateFrom, DateTime dateTo)
|
||||||
|
{
|
||||||
|
if (APIClient.User == null)
|
||||||
|
{
|
||||||
|
return Redirect("~Home/Enter");
|
||||||
|
}
|
||||||
|
|
||||||
|
var vacancy = APIClient.GetRequest<VacancyViewModel>($"/api/vacancy/details?id={id}");
|
||||||
|
if (vacancy == null)
|
||||||
|
{
|
||||||
|
return NotFound("Вакансия не найдена.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var reportFilePath = $"C:\\Users\\User\\source\\repos\\CandidateReview\\Статистика_по_вакансии_{vacancy.JobTitle}.pdf";
|
||||||
|
|
||||||
|
APIClient.PostRequest("api/report/statistics", new ReportBindingModel
|
||||||
|
{
|
||||||
|
VacancyId = vacancy.Id,
|
||||||
|
FileName = reportFilePath,
|
||||||
|
DateFrom = dateFrom,
|
||||||
|
DateTo = dateTo
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!System.IO.File.Exists(reportFilePath))
|
||||||
|
{
|
||||||
|
return NotFound("Файл отчета не найден.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return PhysicalFile(reportFilePath, "application/pdf", $"Статистика_по_вакансии_{vacancy.JobTitle}.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult VacancyDetails(int? id)
|
public IActionResult VacancyDetails(int? id)
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,13 @@
|
|||||||
<label for="password">Пароль:</label>
|
<label for="password">Пароль:</label>
|
||||||
<input type="password" class="form-control" id="password" name="password" required>
|
<input type="password" class="form-control" id="password" name="password" required>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="dateOfBirth">Дата рождения:</label>
|
||||||
|
<input type="date" class="form-control" id="dateOfBirth" name="dateOfBirth" required>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
Выберите корректную дату рождения.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group text-center mt-3">
|
<div class="form-group text-center mt-3">
|
||||||
<button type="submit" class="btn btn-primary">Зарегистрироваться</button>
|
<button type="submit" class="btn btn-primary">Зарегистрироваться</button>
|
||||||
</div>
|
</div>
|
||||||
@ -45,6 +52,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const dateOfBirthInput = document.getElementById("dateOfBirth");
|
||||||
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
|
dateOfBirthInput.setAttribute("max", today);
|
||||||
|
|
||||||
|
document.getElementById("submitBtn").addEventListener("click", function (event) {
|
||||||
|
if (!dateOfBirthInput.value || dateOfBirthInput.value > today) {
|
||||||
|
dateOfBirthInput.classList.add("is-invalid");
|
||||||
|
event.preventDefault();
|
||||||
|
} else {
|
||||||
|
dateOfBirthInput.classList.remove("is-invalid");
|
||||||
|
alert("Форма успешно отправлена!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
<dt class="col-sm-4 text-muted">Телефон:</dt>
|
<dt class="col-sm-4 text-muted">Телефон:</dt>
|
||||||
<dd class="col-sm-8">@Model?.PhoneNumber</dd>
|
<dd class="col-sm-8">@Model?.PhoneNumber</dd>
|
||||||
}
|
}
|
||||||
<dt class="col-sm-4 text-muted">Роль:</dt>
|
<dt class="col-sm-4 text-muted">Дата рождения:</dt>
|
||||||
<dd class="col-sm-8">@Model?.Role</dd>
|
<dd class="col-sm-8">@Model?.DateOfBirth.ToString("dd.MM.yyyy")</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<div class="btn-group mt-4" role="group" aria-label="Действия">
|
<div class="btn-group mt-4" role="group" aria-label="Действия">
|
||||||
|
@ -34,6 +34,14 @@
|
|||||||
<input type="email" class="form-control" id="Email" name="Email" value="@Model?.Email" @(Model?.Id < 0 ? "readonly" : "") required />
|
<input type="email" class="form-control" id="Email" name="Email" value="@Model?.Email" @(Model?.Id < 0 ? "readonly" : "") required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="dateOfBirth">Дата рождения:</label>
|
||||||
|
<input type="date" class="form-control" id="dateOfBirth" name="dateOfBirth" value="@Model?.DateOfBirth.ToString("dd.MM.yyyy")" required>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
Выберите корректную дату рождения.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@if (Model?.Id <= 0)
|
@if (Model?.Id <= 0)
|
||||||
{
|
{
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -62,6 +70,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const dateOfBirthInput = document.getElementById("dateOfBirth");
|
||||||
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
|
dateOfBirthInput.setAttribute("max", today);
|
||||||
|
|
||||||
|
document.getElementById("submitBtn").addEventListener("click", function (event) {
|
||||||
|
if (!dateOfBirthInput.value || dateOfBirthInput.value > today) {
|
||||||
|
dateOfBirthInput.classList.add("is-invalid");
|
||||||
|
event.preventDefault();
|
||||||
|
} else {
|
||||||
|
dateOfBirthInput.classList.remove("is-invalid");
|
||||||
|
alert("Форма успешно отправлена!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.inputmask/5.0.7-beta.29/jquery.inputmask.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.inputmask/5.0.7-beta.29/jquery.inputmask.min.js"></script>
|
||||||
|
@ -15,6 +15,22 @@
|
|||||||
<button class="btn btn-secondary" onclick="window.history.back();">
|
<button class="btn btn-secondary" onclick="window.history.back();">
|
||||||
<i class="bi bi-arrow-left"></i> Назад
|
<i class="bi bi-arrow-left"></i> Назад
|
||||||
</button>
|
</button>
|
||||||
|
<form asp-controller="Vacancy" asp-action="GetStatistics" method="get" class="row g-3 needs-validation" novalidate>
|
||||||
|
<input type="hidden" name="id" value="@Model.Id" />
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="dateFrom">Дата начала</label>
|
||||||
|
<input type="date" class="form-control" id="dateFrom" name="dateFrom" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="dateTo">Дата окончания</label>
|
||||||
|
<input type="date" class="form-control" id="dateTo" name="dateTo" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Скачать статистику</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card shadow-sm mb-4">
|
<div class="card shadow-sm mb-4">
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
public DateTime? DateFrom { get; set; }
|
public DateTime? DateFrom { get; set; }
|
||||||
public DateTime? DateTo { get; set; }
|
public DateTime? DateTo { get; set; }
|
||||||
public int ResumeId { get; set; }
|
public int ResumeId { get; set; }
|
||||||
|
public int VacancyId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,14 @@ namespace CandidateReviewContracts.BindingModels
|
|||||||
|
|
||||||
public string Education { get; set; } = string.Empty;
|
public string Education { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? PhotoFilePath { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
public string Skills { get; set; } = string.Empty;
|
public string Skills { get; set; } = string.Empty;
|
||||||
|
|
||||||
public ResumeStatusEnum Status { get; set; }
|
public ResumeStatusEnum Status { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,18 +13,16 @@ namespace CandidateReviewContracts.BindingModels
|
|||||||
|
|
||||||
public string? LastName { get; set; }
|
public string? LastName { get; set; }
|
||||||
|
|
||||||
public string? AvatarFilePath { get; set; }
|
|
||||||
|
|
||||||
public string Email { get; set; } = string.Empty;
|
public string Email { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? PhoneNumber { get; set; }
|
public string? PhoneNumber { get; set; }
|
||||||
|
|
||||||
public bool EmailConfirmed { get; set; }
|
|
||||||
|
|
||||||
public RoleEnum Role { get; set; }
|
public RoleEnum Role { get; set; }
|
||||||
|
|
||||||
|
public DateTime DateOfBirth { get; set; }
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,6 @@ namespace CandidateReviewContracts.BusinessLogicsContracts
|
|||||||
public interface IReportLogic
|
public interface IReportLogic
|
||||||
{
|
{
|
||||||
void SaveResumeToPdf(ReportBindingModel model);
|
void SaveResumeToPdf(ReportBindingModel model);
|
||||||
|
void SaveResumesStatisticsToPdf(ReportBindingModel model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
public DateTime? CreatedAt { get; set; }
|
||||||
|
|
||||||
public int? Id { get; set; }
|
public int? Id { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,14 @@ namespace CandidateReviewContracts.ViewModels
|
|||||||
public string Experience { get; set; } = string.Empty;
|
public string Experience { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Education { get; set; } = string.Empty;
|
public string Education { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? PhotoFilePath { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
public string Skills { get; set; } = string.Empty;
|
public string Skills { get; set; } = string.Empty;
|
||||||
|
|
||||||
public ResumeStatusEnum Status { get; set; }
|
public ResumeStatusEnum Status { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public List<AssessmentViewModel> Assessments { get; set; } = new();
|
public List<AssessmentViewModel> Assessments { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
@ -12,19 +12,15 @@ namespace CandidateReviewContracts.ViewModels
|
|||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? LastName { get; set; }
|
public string? LastName { get; set; }
|
||||||
|
|
||||||
public string? AvatarFilePath { get; set; }
|
|
||||||
|
|
||||||
public string Email { get; set; } = string.Empty;
|
public string Email { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? PhoneNumber { get; set; }
|
public string? PhoneNumber { get; set; }
|
||||||
|
|
||||||
public bool EmailConfirmed { get; set; }
|
|
||||||
|
|
||||||
public RoleEnum Role { get; set; }
|
public RoleEnum Role { get; set; }
|
||||||
|
|
||||||
|
public DateTime DateOfBirth { get; set; }
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
public List<ResumeViewModel> Resumes { get; set; } = new();
|
public List<ResumeViewModel> Resumes { get; set; } = new();
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
namespace CandidateReviewContracts.ViewModels
|
||||||
|
{
|
||||||
|
public class VacancyStatisticsViewModel
|
||||||
|
{
|
||||||
|
public DateTime DateFrom { get; set; }
|
||||||
|
public DateTime DateTo { get; set; }
|
||||||
|
public int VacancyId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -9,9 +9,9 @@ namespace CandidateReviewDataModels.Models
|
|||||||
string Title { get; }
|
string Title { get; }
|
||||||
string Experience { get; }
|
string Experience { get; }
|
||||||
string Education { get; }
|
string Education { get; }
|
||||||
string? PhotoFilePath { get; }
|
|
||||||
string? Description { get; }
|
string? Description { get; }
|
||||||
string Skills { get; }
|
string Skills { get; }
|
||||||
|
DateTime CreatedAt { get; }
|
||||||
ResumeStatusEnum Status { get; }
|
ResumeStatusEnum Status { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,10 @@ namespace CandidateReviewDataModels.Models
|
|||||||
string Surname { get; }
|
string Surname { get; }
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
string? LastName { get; }
|
string? LastName { get; }
|
||||||
string? AvatarFilePath { get; }
|
|
||||||
string Email { get; }
|
string Email { get; }
|
||||||
string Password { get; }
|
string Password { get; }
|
||||||
string? PhoneNumber { get; }
|
string? PhoneNumber { get; }
|
||||||
bool EmailConfirmed { get; }
|
DateTime DateOfBirth { get; }
|
||||||
RoleEnum Role { get; }
|
RoleEnum Role { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace CandidateReviewDatabaseImplement.Migrations
|
namespace CandidateReviewDatabaseImplement.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(CandidateReviewDatabase))]
|
[DbContext(typeof(CandidateReviewDatabase))]
|
||||||
[Migration("20241213205048_InitialCreate")]
|
[Migration("20241215102357_InitialCreate")]
|
||||||
partial class InitialCreate
|
partial class InitialCreate
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -130,6 +130,9 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
@ -141,9 +144,6 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("PhotoFilePath")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Skills")
|
b.Property<string>("Skills")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
@ -178,19 +178,16 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
b.Property<string>("AvatarFilePath")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int?>("CompanyId")
|
b.Property<int?>("CompanyId")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<string>("Email")
|
b.Property<string>("Email")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<string>("LastName")
|
b.Property<string>("LastName")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
@ -68,12 +68,11 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
Surname = table.Column<string>(type: "text", nullable: false),
|
Surname = table.Column<string>(type: "text", nullable: false),
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
LastName = table.Column<string>(type: "text", nullable: true),
|
LastName = table.Column<string>(type: "text", nullable: true),
|
||||||
AvatarFilePath = table.Column<string>(type: "text", nullable: true),
|
|
||||||
Email = table.Column<string>(type: "text", nullable: false),
|
Email = table.Column<string>(type: "text", nullable: false),
|
||||||
Password = table.Column<string>(type: "text", nullable: false),
|
Password = table.Column<string>(type: "text", nullable: false),
|
||||||
PhoneNumber = table.Column<string>(type: "text", nullable: true),
|
PhoneNumber = table.Column<string>(type: "text", nullable: true),
|
||||||
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
|
Role = table.Column<int>(type: "integer", nullable: false),
|
||||||
Role = table.Column<int>(type: "integer", nullable: false)
|
DateOfBirth = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
@ -124,10 +123,10 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
Title = table.Column<string>(type: "text", nullable: false),
|
Title = table.Column<string>(type: "text", nullable: false),
|
||||||
Experience = table.Column<string>(type: "text", nullable: false),
|
Experience = table.Column<string>(type: "text", nullable: false),
|
||||||
Education = table.Column<string>(type: "text", nullable: false),
|
Education = table.Column<string>(type: "text", nullable: false),
|
||||||
PhotoFilePath = table.Column<string>(type: "text", nullable: true),
|
|
||||||
Description = table.Column<string>(type: "text", nullable: true),
|
Description = table.Column<string>(type: "text", nullable: true),
|
||||||
Skills = table.Column<string>(type: "text", nullable: false),
|
Skills = table.Column<string>(type: "text", nullable: false),
|
||||||
Status = table.Column<int>(type: "integer", nullable: false)
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
@ -127,6 +127,9 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
@ -138,9 +141,6 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("PhotoFilePath")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Skills")
|
b.Property<string>("Skills")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
@ -175,19 +175,16 @@ namespace CandidateReviewDatabaseImplement.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
b.Property<string>("AvatarFilePath")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int?>("CompanyId")
|
b.Property<int?>("CompanyId")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<string>("Email")
|
b.Property<string>("Email")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<string>("LastName")
|
b.Property<string>("LastName")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
@ -19,14 +19,13 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
public string Experience { get; set; } = string.Empty;
|
public string Experience { get; set; } = string.Empty;
|
||||||
[Required]
|
[Required]
|
||||||
public string Education { get; set; } = string.Empty;
|
public string Education { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? PhotoFilePath { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public string Skills { get; set; } = string.Empty;
|
public string Skills { get; set; } = string.Empty;
|
||||||
[Required]
|
[Required]
|
||||||
public ResumeStatusEnum Status { get; set; }
|
public ResumeStatusEnum Status { get; set; }
|
||||||
|
[Required]
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
@ -47,10 +46,10 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Title = model.Title,
|
Title = model.Title,
|
||||||
Experience = model.Experience,
|
Experience = model.Experience,
|
||||||
Education = model.Education,
|
Education = model.Education,
|
||||||
PhotoFilePath = model.PhotoFilePath,
|
|
||||||
Description = model.Description,
|
Description = model.Description,
|
||||||
Skills = model.Skills,
|
Skills = model.Skills,
|
||||||
Status = model.Status
|
Status = model.Status,
|
||||||
|
CreatedAt = DateTime.Now.ToUniversalTime().AddHours(4)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static Resume Create(ResumeViewModel model)
|
public static Resume Create(ResumeViewModel model)
|
||||||
@ -63,10 +62,10 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Title = model.Title,
|
Title = model.Title,
|
||||||
Experience = model.Experience,
|
Experience = model.Experience,
|
||||||
Education = model.Education,
|
Education = model.Education,
|
||||||
PhotoFilePath = model.PhotoFilePath,
|
|
||||||
Description = model.Description,
|
Description = model.Description,
|
||||||
Skills = model.Skills,
|
Skills = model.Skills,
|
||||||
Status = model.Status
|
Status = model.Status,
|
||||||
|
CreatedAt = DateTime.Now.ToUniversalTime().AddHours(4)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public void Update(ResumeBindingModel model)
|
public void Update(ResumeBindingModel model)
|
||||||
@ -80,7 +79,6 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Title = model.Title;
|
Title = model.Title;
|
||||||
Experience = model.Experience;
|
Experience = model.Experience;
|
||||||
Education = model.Education;
|
Education = model.Education;
|
||||||
PhotoFilePath = model.PhotoFilePath;
|
|
||||||
Description = model.Description;
|
Description = model.Description;
|
||||||
Skills = model.Skills;
|
Skills = model.Skills;
|
||||||
Status = model.Status;
|
Status = model.Status;
|
||||||
@ -93,10 +91,10 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Title = Title,
|
Title = Title,
|
||||||
Experience = Experience,
|
Experience = Experience,
|
||||||
Education = Education,
|
Education = Education,
|
||||||
PhotoFilePath = PhotoFilePath,
|
|
||||||
Description = Description,
|
Description = Description,
|
||||||
Skills = Skills,
|
Skills = Skills,
|
||||||
Status = Status
|
Status = Status,
|
||||||
|
CreatedAt = CreatedAt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ using CandidateReviewContracts.ViewModels;
|
|||||||
using CandidateReviewDataModels.Enums;
|
using CandidateReviewDataModels.Enums;
|
||||||
using CandidateReviewDataModels.Models;
|
using CandidateReviewDataModels.Models;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace CandidateReviewDatabaseImplement.Models
|
namespace CandidateReviewDatabaseImplement.Models
|
||||||
{
|
{
|
||||||
@ -16,18 +15,18 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? LastName { get; set; }
|
public string? LastName { get; set; }
|
||||||
public string? AvatarFilePath { get; set; }
|
|
||||||
[Required]
|
[Required]
|
||||||
public string Email { get; set; } = string.Empty;
|
public string Email { get; set; } = string.Empty;
|
||||||
[Required]
|
[Required]
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string? PhoneNumber { get; set; }
|
public string? PhoneNumber { get; set; }
|
||||||
[Required]
|
|
||||||
public bool EmailConfirmed { get; set; }
|
|
||||||
[Required]
|
[Required]
|
||||||
public RoleEnum Role { get; set; }
|
public RoleEnum Role { get; set; }
|
||||||
|
|
||||||
|
public DateTime DateOfBirth { get; set; }
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public virtual Company Company { get; set; }
|
public virtual Company Company { get; set; }
|
||||||
|
|
||||||
@ -43,13 +42,12 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Surname = model.Surname,
|
Surname = model.Surname,
|
||||||
Name = model.Name,
|
Name = model.Name,
|
||||||
LastName = model.LastName,
|
LastName = model.LastName,
|
||||||
AvatarFilePath = model.AvatarFilePath,
|
|
||||||
Email = model.Email,
|
Email = model.Email,
|
||||||
Password = model.Password,
|
Password = model.Password,
|
||||||
PhoneNumber = model.PhoneNumber,
|
PhoneNumber = model.PhoneNumber,
|
||||||
EmailConfirmed = model.EmailConfirmed,
|
|
||||||
Role = model.Role,
|
Role = model.Role,
|
||||||
CompanyId = model.CompanyId
|
CompanyId = model.CompanyId,
|
||||||
|
DateOfBirth = model.DateOfBirth.ToUniversalTime().AddHours(4)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static User Create(UserViewModel model)
|
public static User Create(UserViewModel model)
|
||||||
@ -60,13 +58,12 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Surname = model.Surname,
|
Surname = model.Surname,
|
||||||
Name = model.Name,
|
Name = model.Name,
|
||||||
LastName = model.LastName,
|
LastName = model.LastName,
|
||||||
AvatarFilePath = model.AvatarFilePath,
|
|
||||||
Email = model.Email,
|
Email = model.Email,
|
||||||
Password = model.Password,
|
Password = model.Password,
|
||||||
PhoneNumber = model.PhoneNumber,
|
PhoneNumber = model.PhoneNumber,
|
||||||
EmailConfirmed = model.EmailConfirmed,
|
|
||||||
Role = model.Role,
|
Role = model.Role,
|
||||||
CompanyId = model.CompanyId
|
CompanyId = model.CompanyId,
|
||||||
|
DateOfBirth = model.DateOfBirth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public void Update(UserBindingModel model)
|
public void Update(UserBindingModel model)
|
||||||
@ -78,13 +75,10 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Surname = model.Surname;
|
Surname = model.Surname;
|
||||||
Name = model.Name;
|
Name = model.Name;
|
||||||
LastName = model.LastName;
|
LastName = model.LastName;
|
||||||
AvatarFilePath = model.AvatarFilePath;
|
|
||||||
Email = model.Email;
|
Email = model.Email;
|
||||||
Password = model.Password;
|
|
||||||
PhoneNumber = model.PhoneNumber;
|
PhoneNumber = model.PhoneNumber;
|
||||||
EmailConfirmed = model.EmailConfirmed;
|
|
||||||
Role = model.Role;
|
|
||||||
CompanyId = model.CompanyId;
|
CompanyId = model.CompanyId;
|
||||||
|
DateOfBirth = model.DateOfBirth.ToUniversalTime().AddHours(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserViewModel GetViewModel => new()
|
public UserViewModel GetViewModel => new()
|
||||||
@ -93,13 +87,12 @@ namespace CandidateReviewDatabaseImplement.Models
|
|||||||
Name = Name,
|
Name = Name,
|
||||||
Surname = Surname,
|
Surname = Surname,
|
||||||
LastName = LastName,
|
LastName = LastName,
|
||||||
AvatarFilePath = AvatarFilePath,
|
|
||||||
Email = Email,
|
Email = Email,
|
||||||
Password = Password,
|
Password = Password,
|
||||||
PhoneNumber = PhoneNumber,
|
PhoneNumber = PhoneNumber,
|
||||||
EmailConfirmed = EmailConfirmed,
|
|
||||||
Role = Role,
|
Role = Role,
|
||||||
CompanyId = CompanyId
|
CompanyId = CompanyId,
|
||||||
|
DateOfBirth = DateOfBirth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,5 +26,18 @@ namespace CandidateReviewRestApi.Controllers
|
|||||||
throw new Exception(ex.Message);
|
throw new Exception(ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public void Statistics(ReportBindingModel model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_reportLogic.SaveResumesStatisticsToPdf(model);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
481
Статистика_по_вакансии_Аналитик.pdf
Normal file
481
Статистика_по_вакансии_Аналитик.pdf
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
%PDF-1.4
|
||||||
|
%ÓôÌá
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/CreationDate(D:20241215153146+04'00')
|
||||||
|
/Creator(empira MigraDoc 1.50.4740 \(www.migradoc.com\))
|
||||||
|
/Producer(PDFsharp 1.50.4740 \(www.pdfsharp.com\))
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Catalog
|
||||||
|
/Pages 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Pages
|
||||||
|
/Count 1
|
||||||
|
/Kids[4 0 R]
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Page
|
||||||
|
/MediaBox[0 0 595.276 841.89]
|
||||||
|
/Parent 3 0 R
|
||||||
|
/Contents 5 0 R
|
||||||
|
/Resources
|
||||||
|
<<
|
||||||
|
/ProcSet [/PDF/Text/ImageB/ImageC/ImageI]
|
||||||
|
/ExtGState
|
||||||
|
<<
|
||||||
|
/GS0 6 0 R
|
||||||
|
>>
|
||||||
|
/Font
|
||||||
|
<<
|
||||||
|
/F0 10 0 R
|
||||||
|
/F1 14 0 R
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
/Group
|
||||||
|
<<
|
||||||
|
/CS/DeviceRGB
|
||||||
|
/S/Transparency
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/Length 937
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
q
|
||||||
|
q
|
||||||
|
BT
|
||||||
|
0 0 0 rg
|
||||||
|
/GS0 gs
|
||||||
|
/F0 16 Tf
|
||||||
|
157.9659 756.0862 Td <024B026C025A026C0262026B026C02620264025A> Tj
|
||||||
|
89.8906 0 Td <02690268> Tj
|
||||||
|
21.2188 0 Td <0268026C0264026502620264025A0266> Tj
|
||||||
|
75.3906 0 Td <0267025A> Tj
|
||||||
|
21.2188 0 Td <025C025A0264025A0267026B02620278> Tj
|
||||||
|
/F1 14 Tf
|
||||||
|
-308.9918 -44.8777 Td <0248025B0273025F025F> Tj
|
||||||
|
43.9414 0 Td <02640268026502620271025F026B026C025C0268> Tj
|
||||||
|
70.9775 0 Td <026A025F026102780266025F001D> Tj
|
||||||
|
51.666 0 Td <0014> Tj
|
||||||
|
-166.585 -44.4451 Td <0010> Tj
|
||||||
|
8.1621 0 Td <0244025A0267025E0262025E025A026C001D> Tj
|
||||||
|
64.5039 0 Td <023A026A026C025A0266026802670268025C025A> Tj
|
||||||
|
76.1182 0 Td <024C025A026C027602790267025A> Tj
|
||||||
|
50.9141 0 Td <000F> Tj
|
||||||
|
7 0 Td <023E025A026C025A> Tj
|
||||||
|
31.5957 0 Td <026B02680261025E025A026702620279001D> Tj
|
||||||
|
60.8945 0 Td <0014001800110014001500110015001300150017000F> Tj
|
||||||
|
70 0 Td <024B026C025A026C026D026B001D> Tj
|
||||||
|
-369.1885 -16.0986 Td <0248025B026A025A025B025A026C0275025C025A025F026C026B0279> Tj
|
||||||
|
ET
|
||||||
|
Q
|
||||||
|
Q
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Type/ExtGState
|
||||||
|
/ca 1
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Type/FontDescriptor
|
||||||
|
/Ascent 891
|
||||||
|
/CapHeight 662
|
||||||
|
/Descent 216
|
||||||
|
/Flags 32
|
||||||
|
/FontBBox[-558 -328 2000 1056]
|
||||||
|
/ItalicAngle 0
|
||||||
|
/StemV 0
|
||||||
|
/XHeight 457
|
||||||
|
/FontName/LZDZRO+Times#20New#20Roman,Bold
|
||||||
|
/FontFile2 15 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Length 587
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
/CIDInit /ProcSet findresource begin
|
||||||
|
12 dict begin
|
||||||
|
begincmap
|
||||||
|
/CIDSystemInfo << /Registry (Adobe)/Ordering (UCS)/Supplement 0>> def
|
||||||
|
/CMapName /Adobe-Identity-UCS def /CMapType 2 def
|
||||||
|
1 begincodespacerange
|
||||||
|
<024B><0278>
|
||||||
|
endcodespacerange
|
||||||
|
13 beginbfrange
|
||||||
|
<024B><024B><0421>
|
||||||
|
<026C><026C><0442>
|
||||||
|
<025A><025A><0430>
|
||||||
|
<0262><0262><0438>
|
||||||
|
<026B><026B><0441>
|
||||||
|
<0264><0264><043A>
|
||||||
|
<0269><0269><043F>
|
||||||
|
<0268><0268><043E>
|
||||||
|
<0265><0265><043B>
|
||||||
|
<0266><0266><043C>
|
||||||
|
<0267><0267><043D>
|
||||||
|
<025C><025C><0432>
|
||||||
|
<0278><0278><044E>
|
||||||
|
endbfrange
|
||||||
|
endcmap CMapName currentdict /CMap defineresource pop end end
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
9 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Font
|
||||||
|
/Subtype/CIDFontType2
|
||||||
|
/CIDSystemInfo
|
||||||
|
<<
|
||||||
|
/Ordering(Identity)
|
||||||
|
/Registry(Adobe)
|
||||||
|
/Supplement 0
|
||||||
|
>>
|
||||||
|
/FontDescriptor 7 0 R
|
||||||
|
/BaseFont/LZDZRO+Times#20New#20Roman,Bold
|
||||||
|
/W [587[722]602[500]604[540]610[576]612[576]613[561]614[681]615[576]616[500]617[576]619[443]620[491]632[764]]
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
10 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Font
|
||||||
|
/Subtype/Type0
|
||||||
|
/Encoding/Identity-H
|
||||||
|
/ToUnicode 8 0 R
|
||||||
|
/BaseFont/LZDZRO+Times#20New#20Roman,Bold
|
||||||
|
/DescendantFonts[9 0 R]
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
11 0 obj
|
||||||
|
<<
|
||||||
|
/Type/FontDescriptor
|
||||||
|
/Ascent 891
|
||||||
|
/CapHeight 662
|
||||||
|
/Descent 216
|
||||||
|
/Flags 32
|
||||||
|
/FontBBox[-568 -307 2046 1040]
|
||||||
|
/ItalicAngle 0
|
||||||
|
/StemV 0
|
||||||
|
/XHeight 447
|
||||||
|
/FontName/YPJNPN+Times#20New#20Roman
|
||||||
|
/FontFile2 16 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
12 0 obj
|
||||||
|
<<
|
||||||
|
/Length 1067
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
/CIDInit /ProcSet findresource begin
|
||||||
|
12 dict begin
|
||||||
|
begincmap
|
||||||
|
/CIDSystemInfo << /Registry (Adobe)/Ordering (UCS)/Supplement 0>> def
|
||||||
|
/CMapName /Adobe-Identity-UCS def /CMapType 2 def
|
||||||
|
1 begincodespacerange
|
||||||
|
<000F><0279>
|
||||||
|
endcodespacerange
|
||||||
|
37 beginbfrange
|
||||||
|
<0248><0248><041E>
|
||||||
|
<025B><025B><0431>
|
||||||
|
<0273><0273><0449>
|
||||||
|
<025F><025F><0435>
|
||||||
|
<0264><0264><043A>
|
||||||
|
<0268><0268><043E>
|
||||||
|
<0265><0265><043B>
|
||||||
|
<0262><0262><0438>
|
||||||
|
<0271><0271><0447>
|
||||||
|
<026B><026B><0441>
|
||||||
|
<026C><026C><0442>
|
||||||
|
<025C><025C><0432>
|
||||||
|
<026A><026A><0440>
|
||||||
|
<0261><0261><0437>
|
||||||
|
<0278><0278><044E>
|
||||||
|
<0266><0266><043C>
|
||||||
|
<001D><001D><003A>
|
||||||
|
<0014><0014><0031>
|
||||||
|
<0010><0010><002D>
|
||||||
|
<0244><0244><041A>
|
||||||
|
<025A><025A><0430>
|
||||||
|
<0267><0267><043D>
|
||||||
|
<025E><025E><0434>
|
||||||
|
<023A><023A><0410>
|
||||||
|
<024C><024C><0422>
|
||||||
|
<0276><0276><044C>
|
||||||
|
<0279><0279><044F>
|
||||||
|
<000F><000F><002C>
|
||||||
|
<023E><023E><0414>
|
||||||
|
<0018><0018><0035>
|
||||||
|
<0011><0011><002E>
|
||||||
|
<0015><0015><0032>
|
||||||
|
<0013><0013><0030>
|
||||||
|
<0017><0017><0034>
|
||||||
|
<024B><024B><0421>
|
||||||
|
<026D><026D><0443>
|
||||||
|
<0275><0275><044B>
|
||||||
|
endbfrange
|
||||||
|
endcmap CMapName currentdict /CMap defineresource pop end end
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
13 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Font
|
||||||
|
/Subtype/CIDFontType2
|
||||||
|
/CIDSystemInfo
|
||||||
|
<<
|
||||||
|
/Ordering(Identity)
|
||||||
|
/Registry(Adobe)
|
||||||
|
/Supplement 0
|
||||||
|
>>
|
||||||
|
/FontDescriptor 11 0 R
|
||||||
|
/BaseFont/YPJNPN+Times#20New#20Roman
|
||||||
|
/W [15[250]16[333]17[250]19[500]20[500]21[500]23[500]24[500]29[277]570[722]574[682]580[666]584[722]587[666]588[610]602[443]603[508]604[472]606[508]607[443]609[395]610[535]612[485]613[499]614[632]615[535]616[500]618[500]619[443]620[437]621[500]625[502]627[770]629[671]630[456]632[747]633[459]]
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
14 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Font
|
||||||
|
/Subtype/Type0
|
||||||
|
/Encoding/Identity-H
|
||||||
|
/ToUnicode 12 0 R
|
||||||
|
/BaseFont/YPJNPN+Times#20New#20Roman
|
||||||
|
/DescendantFonts[13 0 R]
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
15 0 obj
|
||||||
|
<<
|
||||||
|
/Length1 51848
|
||||||
|
/Filter/FlateDecode
|
||||||
|
/Length 18487
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
xœí½ |TEÖ7|ê.½díì{º“î,¤: I $<24>•%$DL<44>HØ"ˆJXDq#îŠ:2:àMG1àŽŽè(:ƒû*î"ÌêŒBßï_uo‡PœçyÞï}Ï/þ÷Ô¾œ:uêTÝê†Y©‡d²ÍY¾Ì±ì£ß‹<C39F>{ˆ,ù]ÝgžSvß6¸_&2UŸyöŠ®·³RÎ!Š´Å
Ÿ?oÖܯ]m¹Ê‘gä|Ä(ÉÈïê†ß5ÿœeL¼È÷;8C4Þsö¢9³Øìé/<11>ƒòÆ—Ÿ3ë‚î”ÛLk‰žBrrt/™×-ÍìÌ…ßA3_ýÙÕ‰©òo(…HûØ|˜ V’3p–¶WŽ!b.Æ'‹®$}N·ÑVê W%™Øpj#…%RI¬‚š˜<C5A1>He!”KNj¢VŠ£ ô §
4‚¾d<C2BE>tË¢IàD&µP<ÕЯi-«}A—Ñ_ØZ<>Ü<EFBFBD>2/åÐD6NÛC“©U{
|
||||||
|
u<10>¦Ûé.AvÄ„0§öJXJ×Ðz“4šNw¨kQJ+M¡sµ§h½Î¦³ÓµTOçÒ¥tý–ž¥}ìZ¶MQµN*¥Ù´„™YË•/×¥rõmë“Ú‹Ú.²!ýoQê×’[iÔ¾!/}®0m>F2†Šñw.ÝO›è}–ÈJå:Š ÔÕAÓ9mGסo[ØElƒ¡=ˆÞ”ÑZI{Ùl›”¡¾Ô.¤hô¯-]EÒóô}…ÒÙTùœ@µÖÙ±<C399>›PÓ•t5ýœûþ^d‘,ƒ<>GÉϳ؇ò¹ò§(ùÚOßÑ¿X.[À.•ª¥ËUÏ‘Ë´')=ô¢Œñt<1A>M<EFBFBD>³læe§#ï=ÒùÒ¥ÒJy“ü¾’«ÐʵÈD…H{9C¿þL¡·0^<5E>¬™½)]*÷ªWk¡½…4½¸’¢Íô-S™•…±Xæ`Ŭ=»ˆmcJi’Sj“gËÔ´Ú<>”Yé yÈy]AWAwÒGôígÉÈYˆœÕ¬•ÝÈnb/J;åÓäòmŠW¹MY¯üA9¬F©¼Ø®órŠ¨ÔE‚×}ø{<7B>Þe2Kaé(i›€’f².v1[Íne°‡Ù&¶<>íb_°ìßR¢tƒôéié<69>ÒNi—œ&çÉõòù5%CyWùÑ<ëHZ`kà€ª¹µbmµv<C2B5>öž¶_ŒB*$¾šê ]1—¯¤Õt+Ýž?A;h7än<C3A4>øÛG1?2¤) -ÊdN–ÃòÑ»ÓX;Ÿb·°ÙKìC¶<43>–H
|
||||||
|
“2ñ—'<27>”&H3¤Ë¥¯¥Ãrˆì”kääÛå7䔪ëÕ'Õƒ¦}æ,Ëk‡ï>òA€·îÖJ!‹&H^æ\ ÕBæ&`”çÒbü-¡åt>xt!8~$gùéiz™^ïwÒ{ô¾h/ÿû#qˆŽP€IO•Y𧷽#Siédó0¶úßEìrv»w³ûØoÁß×Ùì/lû˜}‹>‘T ÕHcÑ£Vét©3¥9ÒeÒõÒøû³ô¦ôžô‘ôƒl“£d»œ#7ÈgÊ×Ê«dŸü„üWy·’Ô(ã”…Êvåuô|œ:^<5E>©ÎQ¯W«> þAý“ºOÕL·˜î7õ™>7‡˜Gš[ÍSÍ×™3?m~߬Yr OÍhý0:ú¹…<C2B9>®J«™&õ¡ßÏIËäW¥ß°õR<>º
|
||||||
|
-˜K3¥>ùYéÞ‹WËÉ<>K—)õ"z´Økô½¦þE‰S?§íR2}}øy–ôœt§”ÈFÊ£•«”× uV <56>H{$³´)¾Âh̤SYýC™FÀÿ<C380>ê*ð´Qú€—^’&@’ߦ¥§éNZKóXZ7—ž¤è×l³ì`› w+i}M{<7B>¶V)<R+U›¥å¦Q¡Íl²¶]¦}…Yÿ!»ŠÞ“€ìOc-¬<>¦<>1ê»Y ³+%…^‡æK§»!µŸQ/æàŸfз´Y.¡éÊ^Œyá‘Wõê2ù
|
||||||
|
ö<EFBFBD>TƒáLš{×ÆÐÁw@Wq=A Ð"bFE;X&¸øÓ»tÝD[ä8Ê’’z$M~YqÐÍ´WžˆZ/<2F>~Je%(éZ€~8´O¢„³¨œÊÙl6<6C>ê3ŽÒµsÐò‡¡‹¼ÚíNµ]uÓŸÙDG[¡½ÁÅÛTk`?R><3E>yø<1E>c×So`.mú’Ȳ˜Ò´_]®®VשO¨Ï©;L#èÌÚ»1ŠÑ!¬6¼ø’¾‡¬×böäcþÔ ã°†<C2B0>-µËÏRK¦nèÀ\èíZð`:Fr)J¹œnÀ|zkÈŸé ³±ô½<>™“€y>õ[PN<13>ŠQ_JC;^Áz2—Ò)|ú<>E°riêãzö6èÙmhÓûô)4‡&Ú•ÏF³zŒÞúžÏeÔ0’ZÙF¬É›¨+e½ü}B.¬®µ˜£"_'d#‚Ò¨Bý˜I”hÑÊ¥ò³,«a¤j*Vö1l1Z‰~¡86‰JcQÚzè²Võ!¬¾n¬qRœršz*Úý.V²?Ó<>Ýe®—ß’*ÝÞÚS§z««ÆTŽUQ^VZRìQT8¼ ß<>7,7';ËåÌÌpØÓÓRS’“âãbc¢£l‘áa¡!V‹Ù¤*²Ä(¿ÁÙØéðewú”lç¸qÜ€Y:}5›ÆçèÉǦô"e× ”^=¥·?%³9*©² ßÑàtøvÔ;}lúä6¸o¬w¶;|û…»Y¸Ww8ÜÈàhHœ_ïð±NGƒ¯qùüU
<0A>õ(nchH<68>³n^HA>m …3._‚³{#K¨bÂ!%4ŒÚ(‘%<1C>ò%;ë|IÎzÞŸœÕ0k®¯ur[C}JFF{A¾<41>ÕÍqÎö‘³ÖéI¨NTã3ÕùÌ¢ÇÞºÞ±1Ûªúl4»Ó6×9wÖŒ6Ÿ<«<>×åF½õ¾„÷%õ¢ð躶kƦȫ8¸wÕªk¾µ“ÛÆfðg{;Ê@^)«±sU#ª¾Ll:Å<>Ú¤«ÚÛ|ì*Téà=á½Òû7ÏÙÀC:Ïrø¬ÎZçüUgubh’WùhÊŠr²w³¶—’«¦¶93|Õ)ÎöYõ©ciÕ”½I^GÒ±1ùmQ:c7FDŽ°ð<C2B0>ŽyýqÂ%’sWÓ”~Î2Þ"çx„Ï1Ç<31>–´9ѧrþ˜WN«æ”#>í¹|s1"|ÖºÎU¶Q<œç÷©Y6§cÕ· pîÿúØ<C3BA>YFˆ)Ëö-q'—“~QC|Ðís»}yy\DÌuS´±JøKò—÷IkœÝ6ØGàí¬öQ…`Fàëû¼4_Ïä6Ýï Ù)~òºÛ}R'<27>ÙŒ‰;•Çôcú³w:!ÉOˆ]HœÏ’Ýÿ/ÒÓ0”<7F>ÅÿLô<=¾égÓäémŽ†U<E280A0>o›¦ãÓãËûã—/¦®MN‘—”"‹XåŒþÄÜÓæS²ðÏ$„znŸÙ©!ÌÑè³uŽÓŸí!¿0SŸv<C5B8>çäh6£™¾Qîcý£<C3BD>ñÓ¼°U2¬dKMS§¯ZrL\#4ЪU<C2AA>NGãªÎU³ú´žÙN‡Í¹j3lšœUÝ
<0A>ÁíÓ¶\Ÿâk¼¡<1D>˜ÏFAZ%ªÝèd×NÞèeמ2½m36€Žk§¶ù%&ÕuÖ¶ot!®m3¶h^*ñPÈ=îÁæ
|
||||||
|
‚î—,"}Êf/Q<>ˆUD€ðÏéc$Â,Á0Fsú$=̦W”-*òb•ŸÓ§è1Þ`ja=¬GO<47>k¤¶ ÆÆc¶`£G$"õ×uSÛʃ˜díHÆRa!¤ª›ÕLµOH쓹O¶xcHU^<5E>)Ĭ¼À(ÉbR_<52>ägX
Y±<59>O£D·í»Ê#•-¶C•ÍG*©nÛa<FeDeDeáÁR:ì<>·öªô#9”m0»h²ö¡zö¯.–¶™âµž^kHIjŸNM
õ¶Ã–lMÓœ|uüõÉ7¥\—jYµ0zEÔŠèë¢1=þPÂö„WSBLñ”]_“ÚUÂÕ)W¦>¥<<3C>R˜=ß~¾iyøò”«c¶DšË"¢¢]i4]Jc¬<63>ÅzáÌx,*:B=+MŽ8+ÎÊfF±¨äîl–<1D>uîfæAÿZlum^kdˆ=D
|
||||||
|
iNJ:ÔüEGJ¯îÚßÞbëø®£yUï¯ÞUQñõ¡ý̶ÿÐ~²½2¢¨é”=–º^W|ª)<,;!Ëb5[%SJvx|H™RñMŒÈ"k²šÅÜnüsç¹Ý—]Æ:SÇbîu³(gv¶3Ód6ÅÅFÇ{F–Å™LÎL—TZí*ö$ˆ õ´œüƒw¬üëˆê/ÞÓ³{ù’ïz'°á©WYûnZ3#ÉQhVòú^¼yùí›7vßÙ}Ýyç/ü=kìû›±ÊUXŒÑ§Ú?åä°÷¯”fxãL6[…â°Ux¼•õ%×—Þb¾»T®êÓ¶yg5•nª`—š.x¼ò©‚—
|
||||||
|
ÞÎx«àíÒO¬¥æó„˜ ãKÛº,·ÒÝ¥ak·ÉVlf=Uw*wÜ3B¡ªÖª9ñ<39>UKn‹ÛÀµ•í
|
||||||
|
±Ä·V--<2D>³HqÑqÒh^KyBÅ<42>ÑÌSl<53>uâÎÏuçg¹ó‡U¯/~ºXVŠÇ7_R|cñšâß?[üçâ¿ï/í.fÅ£-}ÚkÞÛVéÔXK†ežå<‹"YF[&Z.´\gYcyØò²å‹5Ô’bé¶È±Ñ91<ÛîFÙú
|
||||||
|
G<EFBFBD>“<·SGa¡”èæ.‰L´'ÎL\”¸&qCâÖDóžÄ¯'ʉ‰Þ[I¢d7K¡‘ùöüÂüê|%¿~X]d–=KÊú’Țȫ/´V[WZ·ZˆDV›U²ö±§½6oUO•äꬒª<1E>cq)¼·¹¹ÕZ
|
||||||
|
KqS™L*ó¨^gVÉ"õ *©^µUíT5iLù©‰}lÄUÈC‹ÝÍûZì~¾ÃÖ±øPGÇw¥íHÇwû:¨º:ºÂ]ˆ¶JÛ¡ý¶ý¶#‡öÙöG%Tt,^âŽæOÈ)‹Š®¨°½b±UFTVR‡›-Ùhâšá‰°Ä´D‰:ÚGAn=å£R<C2A3>!6Y‰ÌJËÎÈ
|
||||||
|
ͮȎH<EFBFBD>J§0‡5<EFBFBD>e:GÉeédK
Og!™x”+£Ó‰¸Ì¢j·þ¹¶dql±›#,ò›]Z22«´„‹6—ln<6C>¡#‹=ñðFÅÆC´Ë¸°gçD™ôTÅiüúk[Ïêc¥ ÞÜš¼äÔìñ£«O]òÚ¹WÝ<57>žœ’îYXß:=dÅ蜌¤ÏªÛLZ¸þWgœU6,-:1ÎîÎÑ0±xÜ<15>‹kónÜêÍ°e%N¨kº•UŒ<55><²l¸3…ë¦mŸ<3ÁI÷žó‰¹¬¬Ýúpú¥?:ßf_²<5F>$sˆ…åKy±§Ù»¬gÚ—[—‡,I¿=æñ˜Çcû¤-±›Ò·8ÿ˜¾3+ŠX\É©»`ÿK´‹íe’Âb±Éˆ‰KLJ<MóUbv¨9cœÁ"ܲÐëIªæÔ›b<E280BA>*‰dl-ó!Gò†¬<03>®ÈT{ª”ê1é8Ý”ë.ÙefÜ鵆E”˜“\å¿âJë<4A>»Ã
!é
|
||||||
|
|oÞ·Dh©ý‹m•<6D>€(HBÅbÈAB×U¬ƒ0BKg ŽC»”ñ<E2809D>ÐG%ú8Å}#{íµ\ôôÞ®‹Þþõú†òÑÍVSB‚½(³dêø²¦mO¼xK~ië¯7Ü<½¢¾enuRRqóš+ÿ>Ú=œë™ àîSàn8e°©ÞÄíÉ,'ŒEŸf‰ÈgdNÈ6[-¡i^…÷'}T¼Ù˜Š
|
||||||
|
S’<EFBFBD>ò7•
|
||||||
|
2V'Õ‚ôVŒ)áÔë/¶9w9%rz<72><7A>NîÄLZ㔜‘Ñöh)Ú»+”…¼Esº |MÊD=Oä”–/Ntþ¹Ý:ÿ0qøç;ÎÅýXâ*÷sˆ)RÏ BR–=Ý‘.™bcâb$“);%595)U6E†Gç —ié,Þ<1A>N‰æ´‘ÃÒåˆt’<>N©jB EïÚ?<3F>/ |