Well at least I tried...

This commit is contained in:
Никита Волков 2024-05-27 04:07:47 +04:00
parent 8e2b4503b0
commit a207814faa
112 changed files with 77252 additions and 1 deletions

View File

@ -13,6 +13,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeautyStudioBusinessLogic",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeautyStudioDatabaseImplement", "BeautyStudioDatabaseImplement\BeautyStudioDatabaseImplement.csproj", "{8BEBC76F-F7B5-46CB-A42B-28E133452D52}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeautyStudioRestAPI", "BeautyStudioRestAPI\BeautyStudioRestAPI.csproj", "{F430F87B-4339-47E4-8C23-3FBED1F74867}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StoreKeeperWebApp", "StoreKeeperWebApp\StoreKeeperWebApp.csproj", "{93AF7F9C-675F-444E-BD5D-11FA4D516561}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -39,6 +43,14 @@ Global
{8BEBC76F-F7B5-46CB-A42B-28E133452D52}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8BEBC76F-F7B5-46CB-A42B-28E133452D52}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8BEBC76F-F7B5-46CB-A42B-28E133452D52}.Release|Any CPU.Build.0 = Release|Any CPU
{F430F87B-4339-47E4-8C23-3FBED1F74867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F430F87B-4339-47E4-8C23-3FBED1F74867}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F430F87B-4339-47E4-8C23-3FBED1F74867}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F430F87B-4339-47E4-8C23-3FBED1F74867}.Release|Any CPU.Build.0 = Release|Any CPU
{93AF7F9C-675F-444E-BD5D-11FA4D516561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{93AF7F9C-675F-444E-BD5D-11FA4D516561}.Debug|Any CPU.Build.0 = Debug|Any CPU
{93AF7F9C-675F-444E-BD5D-11FA4D516561}.Release|Any CPU.ActiveCfg = Release|Any CPU
{93AF7F9C-675F-444E-BD5D-11FA4D516561}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -10,7 +10,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeautyStudioBusinessLogic.BusinessLogic
namespace BeautyStudioBusinessLogic.BusinessLogics
{
public class CosmeticLogic : ICosmeticLogic
{

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Log4Net.AspNetCore" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BeautyStudioBusinessLogic\BeautyStudioBusinessLogic.csproj" />
<ProjectReference Include="..\BeautyStudioContracts\BeautyStudioContracts.csproj" />
<ProjectReference Include="..\BeautyStudioDatabaseImplement\BeautyStudioDatabaseImplement.csproj" />
<ProjectReference Include="..\BeautyStudioDataModels\BeautyStudioDataModels.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,107 @@
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace BeautyStudioRestApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class CosmeticController : Controller
{
private readonly ILogger logger;
private readonly ICosmeticLogic cosmetic;
public CosmeticController(ILogger<CosmeticController> logger, ICosmeticLogic cosmetic)
{
this.logger = logger;
this.cosmetic = cosmetic;
}
[HttpGet]
public CosmeticViewModel? Get(int id)
{
try
{
return cosmetic.ReadElement(new CosmeticSearchModel { Id = id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения косметики с id = {Id}", id);
throw;
}
}
[HttpGet]
public List<CosmeticViewModel>? GetAll()
{
try
{
return cosmetic.ReadList(null);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка косметики");
throw;
}
}
[HttpGet]
public List<CosmeticViewModel>? GetMany(int userId, int page)
{
try
{
return cosmetic.ReadList(new CosmeticSearchModel { LaborCostId = userId });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка косметики клиента id = {Id}", userId);
throw;
}
}
[HttpPost]
public void Create(CosmeticBindingModel model)
{
try
{
cosmetic.Create(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка создания косметики");
throw;
}
}
[HttpPost]
public void Update(CosmeticBindingModel model)
{
try
{
cosmetic.Update(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка обновления косметики");
throw;
}
}
[HttpPost]
public void Delete(CosmeticBindingModel model)
{
try
{
cosmetic.Delete(new() { Id = model.Id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка удаления косметики");
throw;
}
}
}
}

View File

@ -0,0 +1,121 @@
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace BeautyStudioRestApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class LaborCostController : Controller
{
private readonly ILogger logger;
private readonly ILaborCostLogic laborCosts;
public LaborCostController(ILogger<LaborCostController> logger, ILaborCostLogic laborCosts)
{
this.logger = logger;
this.laborCosts = laborCosts;
}
[HttpGet]
public LaborCostViewModel? Get(int id)
{
try
{
return laborCosts.ReadElement(new LaborCostSearchModel { Id = id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения трудозатраты с id = {Id}", id);
throw;
}
}
[HttpGet]
public List<LaborCostViewModel>? GetAll()
{
try
{
return laborCosts.ReadList(null);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка трудозатрат");
throw;
}
}
[HttpGet]
public List<LaborCostViewModel>? GetAllByUser(int userId)
{
try
{
return laborCosts.ReadList(new LaborCostSearchModel { StoreKeeperId = userId });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка трудозатрат пользователя");
throw;
}
}
[HttpGet]
public List<LaborCostViewModel>? GetMany(int userId, int page)
{
try
{
return laborCosts.ReadList(new LaborCostSearchModel { StoreKeeperId = userId });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка трудозатрат клиента id = {Id}", userId);
throw;
}
}
[HttpPost]
public void Create(LaborCostBindingModel model)
{
try
{
laborCosts.Create(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка создания трудозатраты");
throw;
}
}
[HttpPost]
public void Update(LaborCostBindingModel model)
{
try
{
laborCosts.Update(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка обновления трудозатраты");
throw;
}
}
[HttpPost]
public void Delete(LaborCostBindingModel model)
{
try
{
laborCosts.Delete(new() { Id = model.Id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка удаления трудозатраты");
throw;
}
}
}
}

View File

@ -0,0 +1,121 @@
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace BeautyStudioRestApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class OrderController : Controller
{
private readonly ILogger logger;
private readonly IOrderLogic order;
public OrderController(ILogger<OrderController> logger, IOrderLogic order)
{
this.logger = logger;
this.order = order;
}
[HttpGet]
public OrderViewModel? Get(int id)
{
try
{
return order.ReadElement(new OrderSearchModel { Id = id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения заказа с id = {Id}", id);
throw;
}
}
[HttpGet]
public List<OrderViewModel>? GetAll()
{
try
{
return order.ReadList(null);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка заказа");
throw;
}
}
[HttpGet]
public List<OrderViewModel>? GetAllByUser(int userId)
{
try
{
return order.ReadList(new OrderSearchModel { });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка заказа пользователя");
throw;
}
}
[HttpGet]
public List<OrderViewModel>? GetMany(int userId, int page)
{
try
{
return order.ReadList(new OrderSearchModel { });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка заказа клиента id = {Id}", userId);
throw;
}
}
[HttpPost]
public void Create(OrderBindingModel model)
{
try
{
order.Create(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка создания заказа");
throw;
}
}
[HttpPost]
public void Update(OrderBindingModel model)
{
try
{
order.Update(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка обновления заказа");
throw;
}
}
[HttpPost]
public void Delete(OrderBindingModel model)
{
try
{
order.Delete(new() { Id = model.Id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка удаления заказа");
throw;
}
}
}
}

View File

@ -0,0 +1,124 @@
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace BeutySalonClientApp.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ProcedureController : Controller
{
private readonly ILogger logger;
private readonly IProcedureLogic procedure;
public ProcedureController(ILogger<ProcedureController> logger, IProcedureLogic procedure)
{
this.logger = logger;
this.procedure = procedure;
}
[HttpGet]
public ProcedureViewModel? Get(int id)
{
try
{
return procedure.ReadElement(new ProcedureSearchModel { Id = id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения процедуры с id = {Id}", id);
throw;
}
}
[HttpGet]
public List<ProcedureViewModel>? GetAll()
{
try
{
return procedure.ReadList(null);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка процедур");
throw;
}
}
[HttpGet]
public List<ProcedureViewModel>? GetAllByUser(int userId)
{
try
{
return procedure.ReadList(new ProcedureSearchModel { });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка процедур пользователя");
throw;
}
}
[HttpGet]
public List<ProcedureViewModel>? GetMany(int userId, int page)
{
try
{
return procedure.ReadList(new ProcedureSearchModel {});
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка процедур клиента id = {Id}", userId);
throw;
}
}
[HttpPost]
public void Create(ProcedureBindingModel model)
{
try
{
procedure.Create(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка создания процедуры");
throw;
}
}
[HttpPost]
public void Update(ProcedureBindingModel model)
{
try
{
procedure.Update(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка обновления процедуры");
throw;
}
}
[HttpPost]
public void Delete(ProcedureBindingModel model)
{
try
{
procedure.Delete(new() { Id = model.Id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка удаления процедуры");
throw;
}
}
}
}

View File

@ -0,0 +1,121 @@
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace BeautyStudioRestApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ServiceController : Controller
{
private readonly ILogger logger;
private readonly IServiceLogic service;
public ServiceController(ILogger<ServiceController> logger, IServiceLogic service)
{
this.logger = logger;
this.service = service;
}
[HttpGet]
public ServiceViewModel? Get(int id)
{
try
{
return service.ReadElement(new ServiceSearchModel { Id = id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения услуги с id = {Id}", id);
throw;
}
}
[HttpGet]
public List<ServiceViewModel>? GetAll()
{
try
{
return service.ReadList(null);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка услуг");
throw;
}
}
[HttpGet]
public List<ServiceViewModel>? GetAllByUser(int userId)
{
try
{
return service.ReadList(new ServiceSearchModel { StoreKeeperId = userId });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка услуг пользователя");
throw;
}
}
[HttpGet]
public List<ServiceViewModel>? GetMany(int userId, int page)
{
try
{
return service.ReadList(new ServiceSearchModel { StoreKeeperId = userId });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка получения списка услуг клиента id = {Id}", userId);
throw;
}
}
[HttpPost]
public void Create(ServiceBindingModel model)
{
try
{
service.Create(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка создания услуги");
throw;
}
}
[HttpPost]
public void Update(ServiceBindingModel model)
{
try
{
service.Update(model);
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка обновления услуги");
throw;
}
}
[HttpPost]
public void Delete(ServiceBindingModel model)
{
try
{
service.Delete(new() { Id = model.Id });
}
catch (Exception ex)
{
logger.LogError(ex, "Ошибка удаления услуги");
throw;
}
}
}
}

View File

@ -0,0 +1,55 @@
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace BeautyStudioRestApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class StoreKeeperController : Controller
{
private readonly ILogger _logger;
private readonly IOrderLogic _order;
private readonly IStoreKeeperLogic _logic;
public StoreKeeperController(IOrderLogic order, IStoreKeeperLogic logic, ILogger<StoreKeeperController> logger)
{
_logger = logger;
_order = order;
_logic = logic;
}
[HttpGet]
public StoreKeeperViewModel? Login(string login, string password)
{
try
{
return _logic.ReadElement(new StoreKeeperSearchModel
{
StoreKeeperLogin = login,
StoreKeeperPassword = password
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка авторизации сотрудника");
throw;
}
}
[HttpPost]
public void Register(StoreKeeperBindingModel model)
{
try
{
_logic.Create(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка регистрации");
throw;
}
}
}
}

View File

@ -0,0 +1,56 @@
using BeautyStudioBusinessLogic.BusinessLogics;
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.StoragesContracts;
using BeautyStudioDatabaseImplement.Implements;
using Microsoft.OpenApi.Models;
using System.Reflection.PortableExecutable;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.Logging.AddLog4Net("log4net.config");
// Add services to the container.
builder.Services.AddTransient<IStoreKeeperStorage, StoreKeeperStorage>();
builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<IProcedureStorage, ProcedureStorage>();
builder.Services.AddTransient<IServiceStorage, ServiceStorage>();
builder.Services.AddTransient<ILaborCostStorage, LaborCostStorage>();
builder.Services.AddTransient<ICosmeticStorage, CosmeticStorage>();
builder.Services.AddTransient<IProcedureStorage, ProcedureStorage>();
builder.Services.AddTransient<IStoreKeeperLogic, StoreKeeperLogic>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IProcedureLogic, ProcedureLogic>();
builder.Services.AddTransient<IServiceLogic, ServiceLogic>();
builder.Services.AddTransient<ILaborCostLogic, LaborCostLogic>();
builder.Services.AddTransient<ICosmeticLogic, CosmeticLogic>();
builder.Services.AddTransient<IProcedureLogic, ProcedureLogic>();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "BeautyStudioRestApi", Version = "v1" });
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "BeautyStudioRestApi v1"));
}
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:26956",
"sslPort": 44315
}
},
"profiles": {
"BeatySalonRestApi": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7004;http://localhost:5277",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="c:/temp/BeautyStudioRestApi.log" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %5level %logger.%method [%line] - MESSAGE: %message%newline %exception" />
</layout>
</appender>
<root>
<level value="TRACE" />
<appender-ref ref="RollingFile" />
</root>
</log4net>

View File

@ -0,0 +1,120 @@
namespace DiningRoomView
{
partial class FormProductComponent
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
labelComponent = new Label();
labelCount = new Label();
textBoxCount = new TextBox();
comboBoxComponent = new ComboBox();
buttonCancel = new Button();
buttonSave = new Button();
SuspendLayout();
//
// labelComponent
//
labelComponent.AutoSize = true;
labelComponent.Location = new Point(12, 9);
labelComponent.Name = "labelComponent";
labelComponent.Size = new Size(72, 15);
labelComponent.TabIndex = 0;
labelComponent.Text = "Компонент:";
labelComponent.Click += labelComponent_Click;
//
// labelCount
//
labelCount.AutoSize = true;
labelCount.Location = new Point(12, 37);
labelCount.Name = "labelCount";
labelCount.Size = new Size(75, 15);
labelCount.TabIndex = 1;
labelCount.Text = "Количество:";
//
// textBoxCount
//
textBoxCount.Location = new Point(90, 34);
textBoxCount.Name = "textBoxCount";
textBoxCount.Size = new Size(235, 23);
textBoxCount.TabIndex = 3;
//
// comboBoxComponent
//
comboBoxComponent.BackColor = SystemColors.Window;
comboBoxComponent.FormattingEnabled = true;
comboBoxComponent.Location = new Point(90, 6);
comboBoxComponent.Name = "comboBoxComponent";
comboBoxComponent.Size = new Size(235, 23);
comboBoxComponent.TabIndex = 4;
//
// buttonCancel
//
buttonCancel.Location = new Point(248, 63);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(75, 23);
buttonCancel.TabIndex = 5;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// buttonSave
//
buttonSave.Location = new Point(167, 63);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(75, 23);
buttonSave.TabIndex = 6;
buttonSave.Text = "Сохранить";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += buttonSave_Click;
//
// FormProductComponent
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(337, 97);
Controls.Add(buttonSave);
Controls.Add(buttonCancel);
Controls.Add(comboBoxComponent);
Controls.Add(textBoxCount);
Controls.Add(labelCount);
Controls.Add(labelComponent);
Name = "FormProductComponent";
Text = "Компонент";
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Label labelComponent;
private System.Windows.Forms.Label labelCount;
private System.Windows.Forms.TextBox textBoxCount;
private System.Windows.Forms.ComboBox comboBoxComponent;
private System.Windows.Forms.Button buttonCancel;
private System.Windows.Forms.Button buttonSave;
}
}

View File

@ -0,0 +1,78 @@
using DiningRoomContracts.BusinessLogicContracts;
using DiningRoomContracts.SearchModels;
using DiningRoomContracts.ViewModels;
using DiningRoomDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DiningRoomView
{
public partial class FormProductComponent : Form
{
private readonly List<ComponentViewModel>? _list;
public int Id { get { return Convert.ToInt32(comboBoxComponent.SelectedValue); } set { comboBoxComponent.SelectedValue = value; } }
public IComponentModel? ComponentModel
{
get
{
if (_list == null)
{
return null;
}
foreach (var elem in _list)
{
if (elem.Id == Id)
{
return elem;
}
}
return null;
}
}
public int Count { get { return Convert.ToInt32(textBoxCount.Text); } set { textBoxCount.Text = value.ToString(); } }
public FormProductComponent(IComponentLogic logic)
{
InitializeComponent();
_list = logic.ReadList(null);
if (_list != null)
{
comboBoxComponent.DisplayMember = "ComponentName";
comboBoxComponent.ValueMember = "Id";
comboBoxComponent.DataSource = _list;
comboBoxComponent.SelectedItem = null;
}
}
private void buttonSave_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBoxCount.Text))
{
MessageBox.Show("Заполните поле Количество", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (comboBoxComponent.SelectedValue == null)
{
MessageBox.Show("Выберите компонент", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
DialogResult = DialogResult.OK;
Close();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void labelComponent_Click(object sender, EventArgs e)
{
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,120 @@
namespace BeautyStudioView
{
partial class FormServiceProcedure
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
labelComponent = new Label();
labelCount = new Label();
textBoxCount = new TextBox();
comboBoxComponent = new ComboBox();
buttonCancel = new Button();
buttonSave = new Button();
SuspendLayout();
//
// labelComponent
//
labelComponent.AutoSize = true;
labelComponent.Location = new Point(12, 9);
labelComponent.Name = "labelComponent";
labelComponent.Size = new Size(72, 15);
labelComponent.TabIndex = 0;
labelComponent.Text = "Компонент:";
labelComponent.Click += labelComponent_Click;
//
// labelCount
//
labelCount.AutoSize = true;
labelCount.Location = new Point(12, 37);
labelCount.Name = "labelCount";
labelCount.Size = new Size(75, 15);
labelCount.TabIndex = 1;
labelCount.Text = "Количество:";
//
// textBoxCount
//
textBoxCount.Location = new Point(90, 34);
textBoxCount.Name = "textBoxCount";
textBoxCount.Size = new Size(235, 23);
textBoxCount.TabIndex = 3;
//
// comboBoxComponent
//
comboBoxComponent.BackColor = SystemColors.Window;
comboBoxComponent.FormattingEnabled = true;
comboBoxComponent.Location = new Point(90, 6);
comboBoxComponent.Name = "comboBoxComponent";
comboBoxComponent.Size = new Size(235, 23);
comboBoxComponent.TabIndex = 4;
//
// buttonCancel
//
buttonCancel.Location = new Point(248, 63);
buttonCancel.Name = "buttonCancel";
buttonCancel.Size = new Size(75, 23);
buttonCancel.TabIndex = 5;
buttonCancel.Text = "Отмена";
buttonCancel.UseVisualStyleBackColor = true;
buttonCancel.Click += buttonCancel_Click;
//
// buttonSave
//
buttonSave.Location = new Point(167, 63);
buttonSave.Name = "buttonSave";
buttonSave.Size = new Size(75, 23);
buttonSave.TabIndex = 6;
buttonSave.Text = "Сохранить";
buttonSave.UseVisualStyleBackColor = true;
buttonSave.Click += buttonSave_Click;
//
// FormProductComponent
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(337, 97);
Controls.Add(buttonSave);
Controls.Add(buttonCancel);
Controls.Add(comboBoxComponent);
Controls.Add(textBoxCount);
Controls.Add(labelCount);
Controls.Add(labelComponent);
Name = "FormProductComponent";
Text = "Компонент";
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Label labelComponent;
private System.Windows.Forms.Label labelCount;
private System.Windows.Forms.TextBox textBoxCount;
private System.Windows.Forms.ComboBox comboBoxComponent;
private System.Windows.Forms.Button buttonCancel;
private System.Windows.Forms.Button buttonSave;
}
}

View File

@ -0,0 +1,78 @@
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using BeautyStudioDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BeautyStudioView
{
public partial class FormServiceProcedure : Form
{
private readonly List<ProcedureViewModel>? _list;
public int Id { get { return Convert.ToInt32(comboBoxComponent.SelectedValue); } set { comboBoxComponent.SelectedValue = value; } }
public IProcedureModel? ComponentModel
{
get
{
if (_list == null)
{
return null;
}
foreach (var elem in _list)
{
if (elem.Id == Id)
{
return elem;
}
}
return null;
}
}
public int Count { get { return Convert.ToInt32(textBoxCount.Text); } set { textBoxCount.Text = value.ToString(); } }
public FormServiceProcedure(IProcedureLogic logic)
{
InitializeComponent();
_list = logic.ReadList(null);
if (_list != null)
{
comboBoxComponent.DisplayMember = "ProcedureName";
comboBoxComponent.ValueMember = "Id";
comboBoxComponent.DataSource = _list;
comboBoxComponent.SelectedItem = null;
}
}
private void buttonSave_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBoxCount.Text))
{
MessageBox.Show("Заполните поле Количество", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (comboBoxComponent.SelectedValue == null)
{
MessageBox.Show("Выберите компонент", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
DialogResult = DialogResult.OK;
Close();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void labelComponent_Click(object sender, EventArgs e)
{
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,224 @@
namespace BeautyStudioView
{
partial class FormServices
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
labelName = new Label();
labelPrice = new Label();
textBoxName = new TextBox();
textBoxPrice = new TextBox();
groupBox1 = new GroupBox();
dataGridView = new DataGridView();
ID = new DataGridViewTextBoxColumn();
ComponentName = new DataGridViewTextBoxColumn();
Count = new DataGridViewTextBoxColumn();
ButtonRef = new Button();
ButtonDel = new Button();
ButtonUpd = new Button();
ButtonAdd = new Button();
ButtonSave = new Button();
ButtonCancel = new Button();
groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
SuspendLayout();
//
// labelName
//
labelName.AutoSize = true;
labelName.Location = new Point(12, 9);
labelName.Name = "labelName";
labelName.Size = new Size(62, 15);
labelName.TabIndex = 0;
labelName.Text = "Название:";
//
// labelPrice
//
labelPrice.AutoSize = true;
labelPrice.Location = new Point(12, 41);
labelPrice.Name = "labelPrice";
labelPrice.Size = new Size(38, 15);
labelPrice.TabIndex = 1;
labelPrice.Text = "Цена:";
//
// textBoxName
//
textBoxName.Location = new Point(94, 6);
textBoxName.Name = "textBoxName";
textBoxName.Size = new Size(247, 23);
textBoxName.TabIndex = 2;
//
// textBoxPrice
//
textBoxPrice.Location = new Point(94, 38);
textBoxPrice.Name = "textBoxPrice";
textBoxPrice.Size = new Size(100, 23);
textBoxPrice.TabIndex = 3;
//
// groupBox1
//
groupBox1.Controls.Add(dataGridView);
groupBox1.Controls.Add(ButtonRef);
groupBox1.Controls.Add(ButtonDel);
groupBox1.Controls.Add(ButtonUpd);
groupBox1.Controls.Add(ButtonAdd);
groupBox1.Location = new Point(12, 67);
groupBox1.Name = "groupBox1";
groupBox1.Size = new Size(510, 338);
groupBox1.TabIndex = 4;
groupBox1.TabStop = false;
groupBox1.Text = "Компонент";
//
// dataGridView
//
dataGridView.BackgroundColor = SystemColors.ButtonHighlight;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.Columns.AddRange(new DataGridViewColumn[] { ID, ComponentName, Count });
dataGridView.Location = new Point(0, 21);
dataGridView.Name = "dataGridView";
dataGridView.RowTemplate.Height = 25;
dataGridView.Size = new Size(394, 311);
dataGridView.TabIndex = 5;
//
// ID
//
ID.HeaderText = "Id";
ID.Name = "ID";
ID.Visible = false;
ID.Width = 250;
//
// ComponentName
//
ComponentName.HeaderText = "Компоненте";
ComponentName.Name = "ComponentName";
ComponentName.Width = 250;
//
// Count
//
Count.HeaderText = "Количество";
Count.Name = "Count";
//
// ButtonRef
//
ButtonRef.Location = new Point(400, 169);
ButtonRef.Name = "ButtonRef";
ButtonRef.Size = new Size(106, 28);
ButtonRef.TabIndex = 4;
ButtonRef.Text = "Обновить";
ButtonRef.UseVisualStyleBackColor = true;
ButtonRef.Click += ButtonRef_Click;
//
// ButtonDel
//
ButtonDel.Location = new Point(400, 135);
ButtonDel.Name = "ButtonDel";
ButtonDel.Size = new Size(106, 28);
ButtonDel.TabIndex = 3;
ButtonDel.Text = "Удалить";
ButtonDel.UseVisualStyleBackColor = true;
ButtonDel.Click += ButtonDel_Click;
//
// ButtonUpd
//
ButtonUpd.Location = new Point(400, 101);
ButtonUpd.Name = "ButtonUpd";
ButtonUpd.Size = new Size(106, 28);
ButtonUpd.TabIndex = 2;
ButtonUpd.Text = "Изменить";
ButtonUpd.UseVisualStyleBackColor = true;
ButtonUpd.Click += ButtonUpd_Click;
//
// ButtonAdd
//
ButtonAdd.Location = new Point(400, 67);
ButtonAdd.Name = "ButtonAdd";
ButtonAdd.Size = new Size(106, 28);
ButtonAdd.TabIndex = 1;
ButtonAdd.Text = "Добавить";
ButtonAdd.UseVisualStyleBackColor = true;
ButtonAdd.Click += ButtonAdd_Click;
//
// ButtonSave
//
ButtonSave.Location = new Point(354, 415);
ButtonSave.Name = "ButtonSave";
ButtonSave.Size = new Size(75, 23);
ButtonSave.TabIndex = 5;
ButtonSave.Text = "Сохранить";
ButtonSave.UseVisualStyleBackColor = true;
ButtonSave.Click += ButtonSave_Click;
//
// ButtonCancel
//
ButtonCancel.Location = new Point(435, 415);
ButtonCancel.Name = "ButtonCancel";
ButtonCancel.Size = new Size(75, 23);
ButtonCancel.TabIndex = 6;
ButtonCancel.Text = "Отмена";
ButtonCancel.UseVisualStyleBackColor = true;
ButtonCancel.Click += ButtonCancel_Click;
//
// FormProduct
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(536, 450);
Controls.Add(ButtonCancel);
Controls.Add(ButtonSave);
Controls.Add(groupBox1);
Controls.Add(textBoxPrice);
Controls.Add(textBoxName);
Controls.Add(labelPrice);
Controls.Add(labelName);
Name = "FormProduct";
Text = "Создание изделия";
Load += FormProduct_Load;
groupBox1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Label labelName;
private System.Windows.Forms.Label labelPrice;
private System.Windows.Forms.TextBox textBoxName;
private System.Windows.Forms.TextBox textBoxPrice;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.DataGridView dataGridView;
private System.Windows.Forms.Button ButtonRef;
private System.Windows.Forms.Button ButtonDel;
private System.Windows.Forms.Button ButtonUpd;
private System.Windows.Forms.Button ButtonAdd;
private System.Windows.Forms.Button ButtonSave;
private System.Windows.Forms.Button ButtonCancel;
private System.Windows.Forms.DataGridViewTextBoxColumn ID;
private System.Windows.Forms.DataGridViewTextBoxColumn ComponentName;
private System.Windows.Forms.DataGridViewTextBoxColumn Count;
}
}

View File

@ -0,0 +1,210 @@
using BeautyStudioContracts.BindingModels;
using BeautyStudioContracts.BusinessLogicContracts;
using BeautyStudioContracts.SearchModels;
using BeautyStudioContracts.ViewModels;
using BeautyStudioDataModels.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BeautyStudioView
{
public partial class FormServices : Form
{
private readonly ILogger _logger;
private readonly IServiceLogic _logic;
private int? _id;
private Dictionary<int, (IProcedureModel, int)> _serviceProcedures;
public int Id { set { _id = value; } }
public int StoreKeeperId { get; set; }
public FormServices(ILogger<FormServices> logger, IServiceLogic logic)
{
InitializeComponent();
_logger = logger;
_logic = logic;
_serviceProcedures = new Dictionary<int, (IProcedureModel, int)>();
}
private void FormProduct_Load(object sender, EventArgs e)
{
if (_id.HasValue)
{
_logger.LogInformation("Загрузка изделия");
try
{
var view = _logic.ReadElement(new ServiceSearchModel { Id = _id.Value });
if (view != null)
{
textBoxName.Text = view.ServiceName;
textBoxPrice.Text = view.ServicePrice.ToString();
_serviceProcedures = view.ServiceProcedures ?? new Dictionary<int, (IProcedureModel, int)>();
LoadData();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка загрузки изделия");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void LoadData()
{
_logger.LogInformation("Загрузка процедур услуги");
try
{
if (_serviceProcedures != null)
{
dataGridView.Rows.Clear();
foreach (var pc in _serviceProcedures)
{
dataGridView.Rows.Add(new object[] { pc.Key, pc.Value.Item1.ProcedureName, pc.Value.Item2 });
}
textBoxPrice.Text = CalcPrice().ToString();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка загрузки компонент изделия");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ButtonAdd_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormServiceProcedure));
if (service is FormServiceProcedure form)
{
if (form.ShowDialog() == DialogResult.OK)
{
if (form.ComponentModel == null)
{
return;
}
_logger.LogInformation("Добавление новой процедуры: {ProcedureName} - {Count}", form.ComponentModel.ProcedureName, form.Count);
if (_serviceProcedures.ContainsKey(form.Id))
{
_serviceProcedures[form.Id] = (form.ComponentModel, form.Count);
}
else
{
_serviceProcedures.Add(form.Id, (form.ComponentModel, form.Count));
}
LoadData();
}
}
}
private void ButtonUpd_Click(object sender, EventArgs e)
{
if (dataGridView.SelectedRows.Count == 1)
{
var service = Program.ServiceProvider?.GetService(typeof(FormServiceProcedure));
if (service is FormServiceProcedure form)
{
int id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells[0].Value);
form.Id = id;
form.Count = _serviceProcedures[id].Item2;
if (form.ShowDialog() == DialogResult.OK)
{
if (form.ComponentModel == null)
{
return;
}
_logger.LogInformation("Изменение процедуры: {ProcedureName} - {Count}", form.ProcedureModel.ProcedureName, form.Count);
_serviceProcedures[form.Id] = (form.ComponentModel, form.Count);
LoadData();
}
}
}
}
private void ButtonDel_Click(object sender, EventArgs e)
{
if (dataGridView.SelectedRows.Count == 1)
{
if (MessageBox.Show("Удалить запись?", "Вопрос", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
try
{
_logger.LogInformation("Удаление процедуры: {ProcedureName} - {Count}", dataGridView.SelectedRows[0].Cells[1].Value); _serviceProcedures?.Remove(Convert.ToInt32(dataGridView.SelectedRows[0].Cells[0].Value));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
LoadData();
}
}
}
private void ButtonRef_Click(object sender, EventArgs e)
{
LoadData();
}
private void ButtonSave_Click(object sender, EventArgs e)
{
if (StoreKeeperId == 0)
{
MessageBox.Show("Ошибка авторизации", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (string.IsNullOrEmpty(textBoxName.Text))
{
MessageBox.Show("Заполните название", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (string.IsNullOrEmpty(textBoxPrice.Text))
{
MessageBox.Show("Заполните цену", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (_serviceProcedures == null || _serviceProcedures.Count == 0)
{
MessageBox.Show("Заполните компоненты", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
_logger.LogInformation("Сохранение изделия");
try
{
var model = new ServiceBindingModel
{
Id = _id ?? 0,
ServiceName = textBoxName.Text,
ServicePrice = Convert.ToDouble(textBoxPrice.Text),
ServiceProcedure = _serviceProcedures,
StoreKeeperId = StoreKeeperId // Передаем UserId
};
var operationResult = _id.HasValue ? _logic.Update(model) : _logic.Create(model);
if (!operationResult)
{
throw new Exception("Ошибка при сохранении. Дополнительная информация в логах.");
}
MessageBox.Show("Сохранение прошло успешно", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information);
DialogResult = DialogResult.OK;
Close();
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка сохранения изделия");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ButtonCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private double CalcPrice()
{
double price = 0;
foreach (var elem in _serviceProcedures)
{
price += ((elem.Value.Item1?.ProcedureCost ?? 0) * elem.Value.Item2);
}
return Math.Round(price * 1.1, 2);
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Mvc;
using StoreKeeperWebApp.Models;
using System.Diagnostics;
namespace StoreKeeperWebApp.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

View File

@ -0,0 +1,9 @@
namespace StoreKeeperWebApp.Models
{
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

View File

@ -0,0 +1,27 @@
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

View File

@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:57735",
"sslPort": 44336
}
},
"profiles": {
"StaffMemberWebApp": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7065;http://localhost:5059",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\BeautyStudioBusinessLogic\BeautyStudioBusinessLogic.csproj" />
<ProjectReference Include="..\BeautyStudioContracts\BeautyStudioContracts.csproj" />
<ProjectReference Include="..\BeautyStudioDatabaseImplement\BeautyStudioDatabaseImplement.csproj" />
<ProjectReference Include="..\BeautyStudioDataModels\BeautyStudioDataModels.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,26 @@
@{
ViewData["Title"] = "Косметика";
}
<h4 class="fw-bold">Создать косметику</h4>
<form method="post" asp-controller="Cosmetic" asp-action="Create">
<p class="mb-0">Бренд:</p>
<input type="text" name="brand" class="form-control mb-3" />
<p class="mb-0">Наименование косметики:</p>
<input type="text" name="cosmeticName" class="form-control mb-3" />
<p class="mb-0">Стоимость:</p>
<input type="number" step="0.01" min="0.01" name="cosmeticPrice" class="form-control mb-3" />
<p class="mb-0">Выбрать трудозатрату для привязки:</p>
<select class="form-select mb-2" name="laborCostsId">
@foreach (var laborCosts in @ViewBag.LaborCostsList)
{
<option value="@laborCosts.Id">
часы: @(laborCosts.NumberHours), сложность: @(laborCosts.Difficulty)
</option>
}
</select>
<button type="submit" class="btn button-primary">
Создать
</button>
</form>

View File

@ -0,0 +1,36 @@
@{
ViewData["Title"] = "Косметика";
}
<h4 class="fw-bold">Обновить косметику</h4>
<form method="post" asp-controller="Cosmetic" asp-action="Update">
<input name="id" value="@ViewBag.Cosmetic.Id" style="display: none;" />
<p class="mb-0">Бренд:</p>
<input type="text" value="@ViewBag.Cosmetic.Brand" name="brand" class="form-control mb-3" />
<p class="mb-0">Наименование косметики:</p>
<input type="text" value="@ViewBag.Cosmetic.CosmeticName" name="cosmeticName" class="form-control mb-3" />
<p class="mb-0">Стоимость:</p>
<input type="number" step="0.01" value="0.01" name="cosmeticPrice" class="form-control mb-3" />
<p class="mb-0">Трудозатраты:</p>
<select class="form-select mb-2" name="laborCostsId">
@foreach (var laborCosts in @ViewBag.LaborCostsList)
{
@if (laborCosts.Id == ViewBag.Service.LaborCostsId)
{
<option value="@laborCosts.Id" selected>
часы: @(laborCosts.NumberHours), специалисты: @(laborCosts.NumberSpecialists)
</option>
}
else
{
<option value="@laborCosts.Id">
часы: @(laborCosts.NumberHours), специалисты: @(laborCosts.NumberSpecialists)
</option>
}
}
</select>
<button type="submit" class="button-primary">
Обновить
</button>
</form>

View File

@ -0,0 +1,53 @@
@using BeautyStudioContracts.ViewModels
@{
ViewData["Title"] = "Косметика";
}
<h4 class="fw-bold">Косметика</h4>
<div class="d-flex flex-wrap align-items-center justify-content-between">
<div class="d-flex mb-2 gap-1">
<a asp-controller="Cosmetic" asp-action="Create" class="btn button-primary">
Создать
</a>
<button id="update-button" class="btn button-primary">
Обновить
</button>
<button id="delete-button" class="btn button-primary me-5">
Удалить
</button>
</div>
<div class="d-flex mb-2 gap-1">
<div class="input-group" style="width: auto;">
<input id="page-input" type="number" min="1" value="@ViewBag.Page" max="@ViewBag.NumberOfPages" class="form-control" style="max-width: 5em">
<span class="input-group-text">/ @ViewBag.NumberOfPages</span>
</div>
<a href="/Home/Cars?page=@ViewBag.Page" id="go-button" class="btn btn-lg button-primary">
Перейти
</a>
</div>
</div>
<div class="border">
<table class="table mb-0">
<thead>
<tr>
<th>Бренд</th>
<th>Наименование косметики</th>
<th>Стоимость</th>
</tr>
</thead>
<tbody>
@foreach (var item in ViewBag.Cosmetic)
{
<tr class="table-row" id="row-@item.Id">
<td>@item.Brand</td>
<td>@item.CosmeticName</td>
<td>@item.CosmeticPrice</td>
</tr>
}
</tbody>
</table>
</div>
<script src="~/js/cosmetic.js" asp-append-version="true"></script>

View File

@ -0,0 +1,19 @@
@{
ViewData["Title"] = "Вход";
}
<h4 class="fw-bold">Вход в приложение</h4>
<form method="post">
<div class="mb-3">
<label for="login" class="form-label">Логин:</label>
<input id="login" name="login" type="text" class="form-control" aria-label="Login">
</div>
<div class="mb-3">
<label for="password" class="form-label">Пароль:</label>
<input id="password" name="password" type="password" class="form-control" aria-label="Password">
</div>
<button type="submit" class="btn button-primary">
Войти
</button>
</form>

View File

@ -0,0 +1,8 @@
@{
ViewData["Title"] = "HomePage";
}
<h1 class="display-4 text-center">текст в центре окей</h1>
<div class="text-center">
<p><img src="https://sun9-39.userapi.com/impg/o2-mQK-4UlJ0wpYtHij7XS_LcKdrXrr4Rs1Yuw/WKELgu4v8do.jpg?size=1200x859&quality=96&sign=447006c6f7985c41d834b01b0d6d7993&type=album" alt="Logo" /></p>
</div>

View File

@ -0,0 +1,51 @@
@using BeautyStudioContracts.ViewModels
@{
ViewData["Title"] = "Трудозатраты";
}
<h4 class="fw-bold">Трудозатраты</h4>
<div class="d-flex flex-wrap align-items-center justify-content-between">
<div class="d-flex mb-2 gap-1">
<a asp-controller="LaborCosts" asp-action="Create" class="button-primary">
Создать
</a>
<a id="update-button" class="button-primary">
Обновить
</a>
<button id="delete-button" class="button-primary me-5">
Удалить
</button>
</div>
<div class="d-flex mb-2 gap-1">
<div class="input-group" style="width: auto;">
<input id="page-input" type="number" min="1" value="@ViewBag.Page" max="@ViewBag.NumberOfPages" class="form-control" style="max-width: 5em">
<span class="input-group-text">/ @ViewBag.NumberOfPages</span>
</div>
<a href="/Home/Cosmetics?page=@ViewBag.Page" id="go-button" class="button-primary">
Перейти
</a>
</div>
</div>
<div class="border">
<table class="table mb-0">
<thead>
<tr>
<th>Количество часов</th>
<th>Сложность</th>
</tr>
</thead>
<tbody>
@foreach (var item in ViewBag.LaborCosts)
{
<tr class="table-row" id="row-@item.Id">
<td>@item.NumberHours</td>
<td>@item.Difficlty</td>
</tr>
}
</tbody>
</table>
</div>
<script src="~/js/laborcosts.js" asp-append-version="true"></script>

View File

@ -0,0 +1,52 @@
@{
ViewData["Title"] = "Список косметики по процедурам";
}
<h4 class="fw-bold">Список косметики по процедурам</h4>
@{
if (ViewBag.IsAllowed == false)
{
<h3 class="display-4">Авторизируйтесь</h3>
return;
}
<div class="mb-2">
<button id="word-button" class="button-primary">
Word
</button>
<button id="excel-button" class="button-primary">
Excel
</button>
</div>
<p class="mb-0">Выбранные процедуры:</p>
<div class="table-shell border">
<table class="table mb-0">
<thead class="table-head">
<tr>
<th>Наименование</th>
<th>Стоимость</th>
<th></th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td>Не выбрано</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<p class="mb-0">Добавить процедуру:</p>
<div class="d-flex gap-1 mb-2">
<select class="form-select mb-0" id="procedure-select"></select>
<button id="add-button" class="button-primary">
Добавить
</button>
</div>
<script src="~/js/list.js" asp-append-version="true"></script>
}

View File

@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@ -0,0 +1,25 @@
@{
ViewData["Title"] = "Регистрация";
}
<h4 class="fw-bold">Регистрация</h4>
<form method="post">
<div class="mb-3">
<label for="login" class="form-label">Логин:</label>
<input id="login" name="login" type="text" class="form-control" aria-label="Login">
</div>
<div class="mb-3">
<label for="password" class="form-label">Пароль:</label>
<input id="password" name="password" type="password" class="form-control" aria-label="Password">
</div>
<div class="mb-3">
<label for="email" class="form-label">Адрес электронной почты:</label>
<input id="email" name="email" type="email" class="form-control" aria-label="Email">
</div>
<div>
<button type="submit" class="btn button-primary">
Регистрация
</button>
</div>
</form>

View File

@ -0,0 +1,48 @@
@{
ViewData["Title"] = "Report";
}
<h4 class="fw-bold">Отчет по услугам</h4>
<div class="d-flex flex-wrap gap-1 align-items-end mb-2">
<div class="mb-2">
<p class="mb-0">Дата начала:</p>
<input id="date-from-input" class="form-control" type="date" />
</div>
<div class="mb-2">
<p class="mb-0">Дата конца:</p>
<input id="date-to-input" class="form-control" type="date" />
</div>
<button id="generate-button" class="button-primary mb-2">
Показать
</button>
<button id="send-by-mail-button" class="button-primary mb-2">
На почту
</button>
</div>
<p class="mb-0">
<span>За период с&nbsp;</span>
<span id="date-from-span" class="fw-bold">...</span>
<span>&nbsp;по&nbsp;</span>
<span id="date-to-span" class="fw-bold">...</span>
</p>
<div class="table-shell mb-2 border">
<table class="table mb-0">
<thead class="table-head">
<tr>
<th>Дата создания</th>
<th>Услуга</th>
<th>Стоимость</th>
<th>Бренд косметики</th>
<th>Наименование</th>
<th>Стоимость косметики</th>
<th>Процедуры</th>
</tr>
</thead>
<tbody id="tbody">
</tbody>
</table>
</div>
<script src="~/js/report.js" asp-append-version="true"></script>

View File

@ -0,0 +1,53 @@
@using BeautyStudioContracts.ViewModels
@{
ViewData["Title"] = "Услуга";
}
<h4 class="fw-bold">Услуги</h4>
<div class="d-flex flex-wrap align-items-center justify-content-between">
<div class="d-flex mb-2 gap-1">
<a asp-controller="Service" asp-action="Create" class="button-primary">
Создать
</a>
<a id="update-button" class="button-primary">
Обновить
</a>
<a id="bind-button" class="button-primary">
Связать с косметикой
</a>
<button id="delete-button" class="button-primary me-5">
Удалить
</button>
</div>
<div class="d-flex mb-2 gap-1">
<div class="input-group" style="width: auto;">
<input id="page-input" type="number" min="1" value="@ViewBag.Page" max="@ViewBag.NumberOfPages" class="form-control" style="max-width: 5em">
<span class="input-group-text">/ @ViewBag.NumberOfPages</span>
</div>
<a href="/Home?page=@ViewBag.Page" id="go-button" class="button-primary">
Перейти
</a>
</div>
</div>
<div class="border">
<table class="table mb-0">
<thead>
<tr>
<th>Наименование</th>
<th>Стоимость</th>
</tr>
</thead>
<tbody>
@foreach (var item in ViewBag.Service)
{
<tr class="table-row" id="row-@item.Id">
<td>@item.ServiceName</td>
<td>@item.ServicePrice</td>
</tr>
}
</tbody>
</table>
</div>
<script src="~/js/service.js" asp-append-version="true"></script>

View File

@ -0,0 +1,15 @@
@{
ViewData["Title"] = "Трудозатраты";
}
<h4 class="fw-bold">Создать трудозатрату</h4>
<form method="post" asp-controller="LaborCosts" asp-action="Create">
<p class="mb-0">Количество часов:</p>
<input type="number" name="numberHours" class="form-control mb-3" />
<p class="mb-0">Сложность:</p>
<input type="text" name="difficulty" class="form-control mb-3" />
<button type="submit" class="btn button-primary">
Создать
</button>
</form>

View File

@ -0,0 +1,16 @@
@{
ViewData["Title"] = "Трудозатраты";
}
<h4 class="fw-bold">Обновить трудозатраты</h4>
<form method="post" asp-controller="LaborCosts" asp-action="Update">
<input name="id" value="@ViewBag.LaborCosts.Id" style="display: none;" />
<p class="mb-0">Количество часов:</p>
<input type="number" value="@ViewBag.LaborCosts.NumberHours" name="numberHours" class="form-control mb-3" />
<p class="mb-0">Сложность:</p>
<input type="text" value="@ViewBag.LaborCosts.Difficulty" name="difficulty" class="form-control mb-3" />
<button type="submit" class="btn button-primary">
Обновить
</button>
</form>

View File

@ -0,0 +1,52 @@
@{
ViewData["Title"] = "Binding";
}
<h4 class="fw-bold">Связать услугу с косметикой</h4>
<p class="mb-0">
<span>Id услуги:&nbsp;</span>
<span id="id">@ViewBag.ServiceId</span>
</p>
<p>
<span>Наименование услуги:&nbsp;</span>
<span id="service-name-span"></span>
</p>
<p class="mb-0">Привязанная косметика:</p>
<div class="table-shell mb-2 border">
<table class="table mb-0">
<thead class="table-head">
<tr>
<th>Бренд</th>
<th>Наименование</th>
<th>Стоимость</th>
<th>Количество</th>
<th></th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td>Не выбрано</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<p class="mb-0">Добавить косметику:</p>
<p class="mb-0">Наименование:</p>
<select class="form-select mb-0" id="cosmetic-select"></select>
<p class="mb-0">Количество:</p>
<input type="number" min="1" value="1" id="count-input" class="form-control mb-2" />
<button id="add-button" class="button-primary">
Добавить
</button>
<button id="bind-button" class="button-primary text-button">
Привязать
</button>
<script src="~/js/bind.js" asp-append-version="true"></script>

View File

@ -0,0 +1,15 @@
@{
ViewData["Title"] = "Услуги";
}
<h4 class="fw-bold">Создать услугу</h4>
<form method="post" asp-controller="Service" asp-action="Create">
<p class="mb-0">Наименование услуги:</p>
<input name="serviceName" class="form-control mb-2" />
<p class="mb-0">Стоимость услуги:</p>
<input type="number" step="0.01" name="servicePrice" class="form-control mb-2" />
<button id="create-button" class="button-primary text-button">
Создать
</button>
</form>

View File

@ -0,0 +1,18 @@
@{
ViewData["Title"] = "Услуга";
}
<h4 class="fw-bold">Обновить услугу</h4>
<form method="post" asp-controller="Service" asp-action="Update">
<input name="id" value="@ViewBag.Service.Id" style="display: none;" />
<p class="mb-0">Наименование услуги:</p>
<input value="@ViewBag.Service.ServiceName" name="serviceName" class="form-control mb-2" />
<p class="mb-0">Стоимость услуги:</p>
<input value="@ViewBag.Service.ServicePrice.ToString("0.00").Replace(",", ".")"
type="number" step="0.01" name="servicePrice" class="form-control mb-2" />
<button class="button-primary">
Обновить
</button>
</form>

View File

@ -0,0 +1,25 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - StoreKeeperApp</title>
<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="~/BeutySalonStaffMemberApp.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<div class="d-flex flex-column">
<a class="navbar-brand fw-weight-bold py-0 px-2" asp-area="" asp-controller="Home" asp-action="Index">Вы Ужасны</a>
<div class="px-2">StoreKeeperApp</div>
</div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Register">Регистрация</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Enter">Авторизация</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Service">Услуги</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="LaborCosts">Трудозатраты</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Cosmetic">Косметика</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2024 - StoreKeeperApp - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<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>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>

View File

@ -0,0 +1,48 @@
/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
a {
color: #0077cc;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}

View File

@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

View File

@ -0,0 +1,3 @@
@using StoreKeeperWebApp
@using StoreKeeperWebApp.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,22 @@
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,4 @@
// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,427 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,424 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More