профиль компании со списком вакансий, профиль пользователя и редактирование
This commit is contained in:
parent
5528e3db15
commit
525668cb62
@ -12,10 +12,12 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ICompanyStorage _сompanyStorage;
|
||||
public CompanyLogic(ILogger<CompanyLogic> logger, ICompanyStorage сompanyStorage)
|
||||
private readonly IVacancyStorage _vacancyStorage;
|
||||
public CompanyLogic(ILogger<CompanyLogic> logger, ICompanyStorage сompanyStorage, IVacancyStorage vacancyStorage)
|
||||
{
|
||||
_logger = logger;
|
||||
_сompanyStorage = сompanyStorage;
|
||||
_vacancyStorage = vacancyStorage;
|
||||
}
|
||||
public int Create(CompanyBindingModel model)
|
||||
{
|
||||
@ -40,7 +42,7 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
||||
return true;
|
||||
}
|
||||
|
||||
public CompanyViewModel? ReadElement(CompanySearchModel model)
|
||||
/*public CompanyViewModel? ReadElement(CompanySearchModel model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
@ -54,8 +56,55 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
||||
}
|
||||
_logger.LogInformation("ReadElement find. Id: {Id}", element.Id);
|
||||
return element;
|
||||
}*/
|
||||
|
||||
public CompanyViewModel? ReadElement(CompanySearchModel model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
var company = _сompanyStorage.GetElement(model);
|
||||
if (company == null)
|
||||
{
|
||||
_logger.LogWarning("ReadElement: Company not found for Id: {Id}", model.Id);
|
||||
return null;
|
||||
}
|
||||
var vacancies = _vacancyStorage.GetFilteredList(new VacancySearchModel { CompanyId = company.Id});
|
||||
|
||||
var vacancyViewModels = vacancies?.Select(v => new VacancyViewModel
|
||||
{
|
||||
Id = v.Id,
|
||||
CompanyId = v.CompanyId,
|
||||
JobTitle = v.JobTitle,
|
||||
Requirements = v.Requirements,
|
||||
Responsibilities = v.Responsibilities,
|
||||
JobType = v.JobType,
|
||||
Salary = v.Salary,
|
||||
Description = v.Description,
|
||||
Status = v.Status,
|
||||
CreatedAt = v.CreatedAt,
|
||||
Tags = v.Tags
|
||||
}).ToList() ?? new List<VacancyViewModel>();
|
||||
|
||||
var companyViewModel = new CompanyViewModel
|
||||
{
|
||||
Id = company.Id,
|
||||
Name = company.Name,
|
||||
Description = company.Description,
|
||||
Contacts = company.Contacts,
|
||||
Address = company.Address,
|
||||
Website = company.Website,
|
||||
LogoFilePath = company.LogoFilePath,
|
||||
Vacancies = vacancyViewModels
|
||||
};
|
||||
|
||||
_logger.LogInformation("ReadElement: Company found. Id: {Id}", company.Id);
|
||||
return companyViewModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<CompanyViewModel>? ReadList(CompanySearchModel? model)
|
||||
{
|
||||
var list = model == null ? _сompanyStorage.GetFullList() : _сompanyStorage.GetFilteredList(model);
|
||||
|
@ -41,7 +41,6 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
|
||||
public bool Delete(UserBindingModel model)
|
||||
{
|
||||
CheckModel(model, false);
|
||||
CheckPassword(model);
|
||||
_logger.LogInformation("Delete. Id: {Id}", model.Id);
|
||||
if (_userStorage.Delete(model) == null)
|
||||
{
|
||||
|
@ -10,6 +10,7 @@ namespace CandidateReviewClientApp
|
||||
private static readonly HttpClient _user = new();
|
||||
public static UserViewModel? User { get; set; } = null;
|
||||
public static CompanyViewModel? Company { get; set; } = null;
|
||||
public static VacancyViewModel? Vacancy { get; set; } = null;
|
||||
public static void Connect(IConfiguration configuration)
|
||||
{
|
||||
_user.BaseAddress = new Uri(configuration["IPAddress"]);
|
||||
|
@ -41,7 +41,19 @@ namespace CandidateReviewClientApp.Controllers
|
||||
var model = APIClient.GetRequest<CompanyViewModel?>($"api/company/profile?id={id}");
|
||||
if (model != null)
|
||||
{
|
||||
APIClient.PostRequest($"api/user/update", new UserBindingModel { Id = APIClient.User.Id, CompanyId = model.Id });
|
||||
APIClient.PostRequest($"api/user/update", new UserBindingModel {
|
||||
Id = APIClient.User.Id,
|
||||
CompanyId = model.Id,
|
||||
Surname = APIClient.User.Surname,
|
||||
Name = APIClient.User.Name,
|
||||
LastName = APIClient.User.LastName,
|
||||
Email = APIClient.User.Email,
|
||||
Password = APIClient.User.Password,
|
||||
EmailConfirmed = APIClient.User.EmailConfirmed,
|
||||
Role = APIClient.User.Role,
|
||||
AvatarFilePath = APIClient.User.AvatarFilePath,
|
||||
PhoneNumber = APIClient.User.PhoneNumber
|
||||
});
|
||||
}
|
||||
return View(model);
|
||||
}
|
||||
@ -61,7 +73,7 @@ namespace CandidateReviewClientApp.Controllers
|
||||
{
|
||||
APIClient.PostRequest("api/company/create", model);
|
||||
}
|
||||
Response.Redirect("/Home/Index");
|
||||
Response.Redirect($"/Company/CompanyProfile/{model.Id}");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
|
@ -41,6 +41,10 @@ namespace CandidateReviewUserApp.Controllers
|
||||
throw new Exception("Ââåäèòå ëîãèí è ïàðîëü");
|
||||
}
|
||||
APIClient.User = APIClient.GetRequest<UserViewModel>($"api/user/login?login={login}&password={password}");
|
||||
if (APIClient.User.CompanyId != null)
|
||||
{
|
||||
APIClient.Company = APIClient.GetRequest<CompanyViewModel>($"api/company/profile?id={APIClient.User?.CompanyId}");
|
||||
}
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Íåâåðíûé ëîãèí/ïàðîëü");
|
||||
|
@ -24,7 +24,7 @@ namespace CandidateReviewClientApp.Controllers
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
return RedirectToAction("Index");
|
||||
return RedirectToAction("/Home/Index");
|
||||
}
|
||||
|
||||
return View(model);
|
||||
@ -37,7 +37,12 @@ namespace CandidateReviewClientApp.Controllers
|
||||
{
|
||||
return Redirect("/Home/Enter");
|
||||
}
|
||||
return View(APIClient.User);
|
||||
var model = APIClient.GetRequest<UserViewModel?>($"api/user/profile?id={APIClient.User.Id}");
|
||||
if (model == null)
|
||||
{
|
||||
return RedirectToAction("/Home/Index");
|
||||
}
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@ -48,17 +53,17 @@ namespace CandidateReviewClientApp.Controllers
|
||||
Id = model.Id,
|
||||
Surname = model.Surname,
|
||||
Name = model.Name,
|
||||
LastName = model.LastName ?? null,
|
||||
CompanyId = model.CompanyId ?? null,
|
||||
LastName = model.LastName,
|
||||
CompanyId = model.CompanyId,
|
||||
Email = model.Email,
|
||||
Password = model.Password,
|
||||
EmailConfirmed = model.EmailConfirmed,
|
||||
Role = model.Role,
|
||||
AvatarFilePath = model.AvatarFilePath ?? null,
|
||||
PhoneNumber = model.PhoneNumber ?? null
|
||||
AvatarFilePath = model.AvatarFilePath,
|
||||
PhoneNumber = model.PhoneNumber
|
||||
});
|
||||
|
||||
Response.Redirect("/User/UserProfile");
|
||||
Response.Redirect($"/User/UserProfile/{model.Id}");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@ -68,6 +73,31 @@ namespace CandidateReviewClientApp.Controllers
|
||||
Response.Redirect("/Home/Enter");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void Delete(UserBindingModel model)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Доступно только авторизованным пользователям");
|
||||
}
|
||||
|
||||
APIClient.PostRequest($"api/user/delete", new UserBindingModel {
|
||||
Id = model.Id,
|
||||
Surname = model.Surname,
|
||||
Name = model.Name,
|
||||
LastName = model.LastName,
|
||||
CompanyId = model.CompanyId,
|
||||
Email = model.Email,
|
||||
Password = model.Password,
|
||||
EmailConfirmed = model.EmailConfirmed,
|
||||
Role = model.Role,
|
||||
AvatarFilePath = model.AvatarFilePath,
|
||||
PhoneNumber = model.PhoneNumber
|
||||
});
|
||||
|
||||
Response.Redirect("/Home/Enter");
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
|
92
CandidateReviewClientApp/Controllers/VacancyController.cs
Normal file
92
CandidateReviewClientApp/Controllers/VacancyController.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using CandidateReviewContracts.BindingModels;
|
||||
using CandidateReviewContracts.ViewModels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CandidateReviewClientApp.Controllers
|
||||
{
|
||||
public class VacancyController : Controller
|
||||
{
|
||||
private readonly ILogger<VacancyController> _logger;
|
||||
|
||||
public VacancyController(ILogger<VacancyController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult Vacancy(int? id)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
if (id.HasValue)
|
||||
{
|
||||
APIClient.Vacancy = APIClient.GetRequest<VacancyViewModel?>($"api/vacancy/details?id={id}");
|
||||
}
|
||||
var model = APIClient.Vacancy;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult EditVacancy(int? id)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
if (!id.HasValue)
|
||||
{
|
||||
return View(new VacancyViewModel());
|
||||
}
|
||||
var model = APIClient.GetRequest<VacancyViewModel?>($"api/vacancy/details?id={id}");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void EditVacancy(VacancyBindingModel model)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Доступно только авторизованным пользователям");
|
||||
}
|
||||
if (model.Id != 0)
|
||||
{
|
||||
APIClient.PostRequest("api/vacancy/update", model);
|
||||
}
|
||||
else
|
||||
{
|
||||
APIClient.PostRequest("api/vacancy/create", model);
|
||||
if (APIClient.Company != null)
|
||||
{
|
||||
APIClient.Company?.Vacancies.Add(new VacancyViewModel
|
||||
{
|
||||
Id = model.Id,
|
||||
CompanyId = model.CompanyId,
|
||||
CreatedAt = model.CreatedAt,
|
||||
Description = model.Description,
|
||||
JobTitle = model.JobTitle,
|
||||
JobType = model.JobType,
|
||||
Requirements = model.Requirements,
|
||||
Responsibilities = model.Responsibilities,
|
||||
Salary = model.Salary,
|
||||
Status = model.Status,
|
||||
Tags = model.Tags
|
||||
});
|
||||
}
|
||||
}
|
||||
Response.Redirect($"/Company/CompanyProfile/{model.CompanyId}");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void Delete(int id)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Доступно только авторизованным пользователям");
|
||||
}
|
||||
|
||||
APIClient.PostRequest($"api/vacancy/delete", new VacancyBindingModel { Id = id });
|
||||
Response.Redirect("/Home/Index");
|
||||
}
|
||||
}
|
||||
}
|
@ -3,54 +3,86 @@
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Профиль компании";
|
||||
var userRole = APIClient.User?.Role == CandidateReviewDataModels.Enums.RoleEnum.Сотрудник ? true : false;
|
||||
}
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
@if (!string.IsNullOrEmpty(Model.LogoFilePath))
|
||||
{
|
||||
<img src="@Model.LogoFilePath" class="card-img-top img-fluid" alt="Логотип компании">
|
||||
}
|
||||
<img src="@(Model.LogoFilePath ?? "https://static.thenounproject.com/png/2504969-200.png")"
|
||||
class="card-img-top img-fluid rounded" alt="Логотип компании">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">@Model.Name</h5>
|
||||
<p class="card-text text-truncate" style="max-height: 100px; overflow: hidden;">@Model.Description</p>
|
||||
<a href="@Model.Website" target="_blank" class="btn btn-primary mt-2">@Model.Website</a>
|
||||
<p class="card-text">@(Model.Description == null ? "Описание отсутствует" : Model.Description) </p>
|
||||
<a href="@(Model.Website ?? "#")" target="_blank" class="btn btn-primary mt-2">@(Model.Website ?? "Веб-сайт отсутствует")</a> </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h2>Информация о компании</h2>
|
||||
<a asp-action="EditCompanyProfile" asp-controller="Company" asp-route-id="@Model.Id" class="btn btn-primary float-end">Редактировать</a>
|
||||
@if (userRole)
|
||||
{
|
||||
<a asp-action="EditCompanyProfile" asp-controller="Company" asp-route-id="@Model.Id" class="btn btn-primary">Редактировать</a>
|
||||
}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Название</th>
|
||||
<td>@Model.Name</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Описание</th>
|
||||
<td>@Model.Description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Официальный сайт</th>
|
||||
<td><a href="@Model.Website" target="_blank">@Model.Website</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Адрес</th>
|
||||
<td>@Model.Address</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Контакты</th>
|
||||
<td>@Model.Contacts</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-3">Адрес:</dt>
|
||||
<dd class="col-sm-9">@(Model.Address?.ToString() ?? "Адрес не указан")</dd>
|
||||
|
||||
<dt class="col-sm-3">Контакты:</dt>
|
||||
<dd class="col-sm-9">@(Model.Contacts?.ToString() ?? "Контакты не указаны")</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h2>Вакансии компании</h2>
|
||||
@if (userRole)
|
||||
{
|
||||
<a asp-action="EditVacancy" asp-controller="Vacancy" asp-route-companyId="@Model.Id" class="btn btn-success">Добавить вакансию</a>
|
||||
}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (@Model.Vacancies != null && @Model.Vacancies.Any())
|
||||
{
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Название</th>
|
||||
<th>Тип занятости</th>
|
||||
<th>Зарплата</th>
|
||||
<th>Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var vacancy in @Model.Vacancies)
|
||||
{
|
||||
<tr>
|
||||
<td>@vacancy.JobTitle</td>
|
||||
<td>@vacancy.JobType</td>
|
||||
<td>@vacancy.Salary</td>
|
||||
<td>
|
||||
<a asp-action="VacancyDetails" asp-controller="Vacancy" asp-route-id="@vacancy.Id" class="btn btn-sm btn-info">Просмотр</a>
|
||||
@if (userRole)
|
||||
{
|
||||
<a asp-action="EditVacancy" asp-controller="Vacancy" asp-route-id="@vacancy.Id" class="btn btn-sm btn-warning">Редактировать</a>
|
||||
<a asp-action="DeleteVacancy" asp-controller="Vacancy" asp-route-id="@vacancy.Id" class="btn btn-sm btn-danger" onclick="return confirm('Вы уверены, что хотите удалить вакансию?');">Удалить</a>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>Вакансий нет.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +0,0 @@
|
||||
@{
|
||||
ViewData["Title"] = "Privacy Policy";
|
||||
}
|
||||
<h1>@ViewData["Title"]</h1>
|
||||
|
||||
<p>Use this page to detail your site's privacy policy.</p>
|
@ -8,7 +8,6 @@
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/CandidateReviewClientApp.styles.css" asp-append-version="true" />
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
</head>
|
||||
@ -17,7 +16,7 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Candidate Review</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mainNav" aria-controls="mainNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<button class="navbar-toggler" type="button" onclick="toggleNavbar()" aria-controls="mainNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="mainNav">
|
||||
@ -31,6 +30,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="User" asp-action="UserProfile" asp-route-id="@(APIClient.User?.Id)">Профиль</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Vacancy" asp-action="SearchVacancies">Поиск вакансий</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -48,5 +50,11 @@
|
||||
</div>
|
||||
</footer>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
<script>
|
||||
function toggleNavbar() {
|
||||
var navbar = document.getElementById('mainNav');
|
||||
navbar.classList.toggle('show');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
@ -9,41 +9,43 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card">
|
||||
@if (!string.IsNullOrEmpty(@Model.AvatarFilePath))
|
||||
@if (!string.IsNullOrEmpty(@Model?.AvatarFilePath))
|
||||
{
|
||||
<img src="@Model.AvatarFilePath" class="card-img-top img-fluid rounded-circle mx-auto d-block" style="max-width: 150px; max-height: 150px;" alt="Аватар пользователя">
|
||||
<img src="@Model?.AvatarFilePath" class="card-img-top img-fluid rounded-circle mx-auto d-block" style="max-width: 150px; max-height: 150px;" alt="Аватар пользователя">
|
||||
}
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title mb-0">
|
||||
@Model.Name @(string.IsNullOrEmpty(@Model.Surname) ? "" : @Model.Surname) @(string.IsNullOrEmpty(@Model.LastName) ? "" : @Model.LastName)
|
||||
@Model?.Name @(string.IsNullOrEmpty(@Model?.Surname) ? "" : @Model?.Surname) @(string.IsNullOrEmpty(@Model?.LastName) ? "" : @Model?.LastName)
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="mb-0">Контактная информация</h2>
|
||||
<div class="btn-group float-end mt-2" role="group" aria-label="Действия">
|
||||
<a asp-action="UserProfileEdit" asp-controller="User" asp-route-id="@Model?.Id" class="btn btn-primary">Редактировать</a>
|
||||
<a asp-action="Delete" asp-controller="User" asp-route-id="@Model?.Id" class="btn btn-danger" onclick="return confirm('Вы уверены, что хотите удалить профиль?');">Удалить</a>
|
||||
<dl class="row mt-3">
|
||||
<dt class="col-sm-4">Email:</dt>
|
||||
<dd class="col-sm-8">@Model?.Email</dd>
|
||||
@if (!string.IsNullOrEmpty(@Model?.PhoneNumber))
|
||||
{
|
||||
<dt class="col-sm-4">Телефон:</dt>
|
||||
<dd class="col-sm-8">@Model?.PhoneNumber</dd>
|
||||
}
|
||||
<dt class="col-sm-4">Роль:</dt>
|
||||
<dd class="col-sm-8">@Model?.Role</dd>
|
||||
</dl>
|
||||
<div class="btn-group mt-3" role="group" aria-label="Действия">
|
||||
<a asp-action="UserProfileEdit" asp-controller="User" asp-route-id="@Model?.Id" class="btn btn-primary">Редактировать профиль</a>
|
||||
<form asp-action="Delete" asp-controller="User" method="post" onsubmit="return confirm('Вы уверены, что хотите удалить профиль?');">
|
||||
<input type="hidden" name="id" value="@Model?.Id" />
|
||||
<button type="submit" class="btn btn-danger">Удалить профиль</button>
|
||||
</form>
|
||||
<a asp-action="Logout" asp-controller="User" class="btn btn-secondary">Выйти</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2>Мои резюме</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-3">Email</dt>
|
||||
<dd class="col-sm-9">@Model.Email</dd>
|
||||
|
||||
@if (!string.IsNullOrEmpty(@Model.PhoneNumber))
|
||||
{
|
||||
<dt class="col-sm-3">Телефон</dt>
|
||||
<dd class="col-sm-9">@Model.PhoneNumber</dd>
|
||||
}
|
||||
|
||||
<dt class="col-sm-3">Роль</dt>
|
||||
<dd class="col-sm-9">@Model.Role</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
90
CandidateReviewClientApp/Views/Vacancy/EditVacancy.cshtml
Normal file
90
CandidateReviewClientApp/Views/Vacancy/EditVacancy.cshtml
Normal file
@ -0,0 +1,90 @@
|
||||
@using CandidateReviewContracts.ViewModels
|
||||
@using CandidateReviewDataModels.Enums
|
||||
@model VacancyViewModel
|
||||
|
||||
@{
|
||||
var title = @Model.Id <= 0 ? "Создать вакансию" : "Редактировать вакансию";
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<h1>@title</h1>
|
||||
<form method="post" class="row g-3 needs-validation" novalidate>
|
||||
<input type="hidden" name="id" value="@Model?.Id" />
|
||||
<input type="hidden" name="companyId" value="@(APIClient.User?.CompanyId)" />
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="JobTitle" class="form-label">Название должности <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="JobTitle" name="JobTitle" value="@Model?.JobTitle" required placeholder="Введите название должности">
|
||||
<div class="invalid-feedback">Пожалуйста, введите название должности.</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="requirements" class="form-label">Требования <span class="text-danger">*</span></label>
|
||||
<textarea class="form-control" id="requirements" name="requirements" rows="3" placeholder="Введите требования к вакансии">@Model?.Requirements</textarea>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="Responsibilities" class="form-label">Обязанности <span class="text-danger">*</span></label>
|
||||
<textarea class="form-control" id="Responsibilities" name="Responsibilities" rows="3" placeholder="Введите обязанности">@Model?.Responsibilities</textarea>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="JobType" class="form-label">Тип занятости</label>
|
||||
<select id="JobType" name="JobType" class="form-control" asp-items="@(new SelectList(Enum.GetValues(typeof(JobTypeEnum)).Cast<JobTypeEnum>()))"></select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="salary" class="form-label">Заработная плата (руб.)</label>
|
||||
<input type="text" class="form-control" id="salary" name="salary" value="@Model?.Salary" placeholder="Введите заработную плату или поставьте '-'">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="description" class="form-label">Описание</label>
|
||||
<input type="text" class="form-control" id="description" name="description" value="@Model?.Description" placeholder="Введите описание вакансии">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="Status" class="form-label">Статус вакансии</label>
|
||||
<select id="Status" name="Status" class="form-control" asp-items="@(new SelectList(Enum.GetValues(typeof(VacancyStatusEnum)).Cast<VacancyStatusEnum>()))"></select>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="createdAt" value="@Model?.CreatedAt" />
|
||||
|
||||
@{
|
||||
var tagsString = @Model?.Tags;
|
||||
var displayedTags = string.IsNullOrEmpty(tagsString) ? "" : string.Join(", ", tagsString.Split(',').Select(t => t.Trim()));
|
||||
}
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="tags" class="form-label">Тэги</label>
|
||||
<input type="text" class="form-control" id="tags" name="tags" value="@displayedTags" placeholder="Введите тэги через запятую">
|
||||
</div>
|
||||
|
||||
@* <input type="hidden" name="createdAt" value="@(APIClient.Company?.Vacancies.Add(Model))" />
|
||||
*@
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-primary">Сохранить</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
'use strict'
|
||||
|
||||
var forms = document.querySelectorAll('.needs-validation')
|
||||
|
||||
Array.prototype.slice.call(forms)
|
||||
.forEach(function (form) {
|
||||
form.addEventListener('submit', function (event) {
|
||||
if (!form.checkValidity()) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
form.classList.add('was-validated')
|
||||
}, false)
|
||||
})
|
||||
})()
|
||||
</script>
|
||||
|
@ -0,0 +1,40 @@
|
||||
@* @using CandidateReviewContracts.ViewModels
|
||||
@model VacancyViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Поиск вакансий";
|
||||
}
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1>Поиск вакансий</h1>
|
||||
<form asp-action="Search" asp-controller="Vacancy" method="get">
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" name="searchTerm" placeholder="Введите поисковый запрос" value="@Model?.SearchTerm">
|
||||
<button class="btn btn-primary" type="submit">Поиск</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if (@Model != null && @Model.Vacancies != null)
|
||||
{
|
||||
<h2>Результаты поиска:</h2>
|
||||
@if (Model.Vacancies.Count > 0)
|
||||
{
|
||||
<ul>
|
||||
@foreach (var vacancy in Model.Vacancies)
|
||||
{
|
||||
<li>@vacancy.JobTitle</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>Вакансий не найдено.</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
*@
|
54
CandidateReviewClientApp/Views/Vacancy/VacancyDetails.cshtml
Normal file
54
CandidateReviewClientApp/Views/Vacancy/VacancyDetails.cshtml
Normal file
@ -0,0 +1,54 @@
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using CandidateReviewContracts.ViewModels
|
||||
@model VacancyViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Информация о вакансии";
|
||||
}
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2>@Model.JobTitle</h2>
|
||||
<input type="hidden" name="id" value="@Model?.Id" />
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-4">Компания:</dt>
|
||||
<dd class="col-sm-8">@Model.CompanyId</dd>
|
||||
|
||||
<dt class="col-sm-4">Тип занятости:</dt>
|
||||
<dd class="col-sm-8">@Model.JobType</dd>
|
||||
|
||||
<dt class="col-sm-4">Зарплата:</dt>
|
||||
<dd class="col-sm-8">@Model.Salary</dd>
|
||||
|
||||
<dt class="col-sm-4">Дата публикации:</dt>
|
||||
<dd class="col-sm-8">@Model.CreatedAt.ToShortDateString()</dd>
|
||||
|
||||
<dt class="col-sm-4">Статус:</dt>
|
||||
<dd class="col-sm-8">@Model.Status</dd>
|
||||
|
||||
<dt class="col-sm-4">Теги:</dt>
|
||||
<dd class="col-sm-8">@Model.Tags</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-4">Требования:</dt>
|
||||
<dd class="col-sm-8">@Html.Raw(Model.Requirements)</dd>
|
||||
|
||||
<dt class="col-sm-4">Обязанности:</dt>
|
||||
<dd class="col-sm-8">@Html.Raw(Model.Responsibilities)</dd>
|
||||
|
||||
<dt class="col-sm-4">Описание:</dt>
|
||||
<dd class="col-sm-8">@Html.Raw(Model.Description)</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
BIN
CandidateReviewClientApp/images/default-company-logo.png
Normal file
BIN
CandidateReviewClientApp/images/default-company-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -1,4 +1,5 @@
|
||||
using CandidateReviewDataModels.Models;
|
||||
using CandidateReviewContracts.ViewModels;
|
||||
using CandidateReviewDataModels.Models;
|
||||
|
||||
namespace CandidateReviewContracts.BindingModels
|
||||
{
|
||||
@ -16,5 +17,7 @@ namespace CandidateReviewContracts.BindingModels
|
||||
public string? Contacts { get; set; }
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public List<IVacancyModel> Vacancies { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
@ -16,5 +16,7 @@ namespace CandidateReviewContracts.ViewModels
|
||||
public string? Contacts { get; set; }
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public List<VacancyViewModel> Vacancies { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace CandidateReviewDatabaseImplement.Models
|
||||
Salary = model.Salary,
|
||||
Description = model.Description,
|
||||
Status = model.Status,
|
||||
CreatedAt = model.CreatedAt,
|
||||
CreatedAt = DateTime.Now.ToUniversalTime(),
|
||||
Tags = model.Tags
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
using CandidateReviewContracts.BusinessLogicsContracts;
|
||||
using CandidateReviewContracts.SearchModels;
|
||||
using CandidateReviewContracts.ViewModels;
|
||||
using CandidateReviewDataModels.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Linq;
|
||||
|
||||
namespace CandidateReviewRestApi.Controllers
|
||||
{
|
||||
@ -12,10 +14,12 @@ namespace CandidateReviewRestApi.Controllers
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ICompanyLogic _logic;
|
||||
public CompanyController(ICompanyLogic logic, ILogger<CompanyController> logger)
|
||||
private readonly IVacancyLogic _vacancyLogic;
|
||||
public CompanyController(ICompanyLogic logic, IVacancyLogic vacancyLogic, ILogger<CompanyController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_logic = logic;
|
||||
_vacancyLogic = vacancyLogic;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@ -77,5 +81,17 @@ namespace CandidateReviewRestApi.Controllers
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/*private CompanyBindingModel GetCompanyWithVacancies(CompanyBindingModel model)
|
||||
{
|
||||
var vacancies = _vacancyLogic.ReadList(new VacancySearchModel { CompanyId = model.Id });
|
||||
if (vacancies != null)
|
||||
{
|
||||
model.Vacancies = vacancies.Where(v => v.CompanyId == model.Id)
|
||||
.Select(v => (IVacancyModel)v)
|
||||
.ToList();
|
||||
}
|
||||
return model;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
@ -80,5 +80,19 @@ namespace CandidateReviewRestApi.Controllers
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void Delete(UserBindingModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logic.Delete(model);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ошибка удаления профиля пользователя");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
80
CandidateReviewRestApi/Controllers/VacancyController.cs
Normal file
80
CandidateReviewRestApi/Controllers/VacancyController.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using CandidateReviewContracts.BindingModels;
|
||||
using CandidateReviewContracts.BusinessLogicsContracts;
|
||||
using CandidateReviewContracts.SearchModels;
|
||||
using CandidateReviewContracts.ViewModels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CandidateReviewRestApi.Controllers
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class VacancyController : Controller
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IVacancyLogic _logic;
|
||||
public VacancyController(IVacancyLogic logic, ILogger<VacancyController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_logic = logic;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public VacancyViewModel? Details(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _logic.ReadElement(new VacancySearchModel
|
||||
{
|
||||
Id = id
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ошибка получения вакансии");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void Create(VacancyBindingModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logic.Create(model);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ошибка создания вакансии");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void Update(VacancyBindingModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logic.Update(model);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ошибка обновления вакансии");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public void Delete(VacancyBindingModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logic.Delete(model);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ошибка удаления вакансии");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user