Add user management and business units
This commit is contained in:
176
backend/src/MyBiz.Core/AuthService.cs
Normal file
176
backend/src/MyBiz.Core/AuthService.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
namespace MyBiz.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Результат аутентификации
|
||||
/// </summary>
|
||||
public class AuthResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Успешна ли аутентификация
|
||||
/// </summary>
|
||||
public bool Success { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Пользователь (если успешно)
|
||||
/// </summary>
|
||||
public User? User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Токен доступа (заглушка)
|
||||
/// </summary>
|
||||
public string? Token { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Сообщение об ошибке
|
||||
/// </summary>
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сервис аутентификации (заглушка для MVP)
|
||||
/// </summary>
|
||||
public class AuthService
|
||||
{
|
||||
private readonly Dictionary<string, User> _usersByUsername = new();
|
||||
private readonly Dictionary<Guid, User> _usersById = new();
|
||||
private readonly Dictionary<string, Guid> _tokens = new(); // token -> userId
|
||||
|
||||
/// <summary>
|
||||
/// Зарегистрировать нового пользователя
|
||||
/// </summary>
|
||||
public AuthResult Register(string username, string email, string password, string companyName)
|
||||
{
|
||||
if (_usersByUsername.ContainsKey(username))
|
||||
{
|
||||
return new AuthResult
|
||||
{
|
||||
Success = false,
|
||||
ErrorMessage = "Пользователь с таким именем уже существует"
|
||||
};
|
||||
}
|
||||
|
||||
var user = new User
|
||||
{
|
||||
Username = username,
|
||||
Email = email,
|
||||
PasswordHash = HashPassword(password),
|
||||
Company = new Company
|
||||
{
|
||||
Name = companyName,
|
||||
Cash = 100000m, // Стартовый капитал
|
||||
Assets = 0,
|
||||
Liabilities = 0
|
||||
}
|
||||
};
|
||||
|
||||
user.CompanyId = user.Company.Id;
|
||||
|
||||
_usersByUsername[username] = user;
|
||||
_usersById[user.Id] = user;
|
||||
|
||||
var token = GenerateToken(user.Id);
|
||||
_tokens[token] = user.Id; // Сохраняем токен
|
||||
|
||||
return new AuthResult
|
||||
{
|
||||
Success = true,
|
||||
User = user,
|
||||
Token = token
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Войти в систему
|
||||
/// </summary>
|
||||
public AuthResult Login(string username, string password)
|
||||
{
|
||||
if (!_usersByUsername.TryGetValue(username, out var user))
|
||||
{
|
||||
return new AuthResult
|
||||
{
|
||||
Success = false,
|
||||
ErrorMessage = "Пользователь не найден"
|
||||
};
|
||||
}
|
||||
|
||||
if (!VerifyPassword(password, user.PasswordHash))
|
||||
{
|
||||
return new AuthResult
|
||||
{
|
||||
Success = false,
|
||||
ErrorMessage = "Неверный пароль"
|
||||
};
|
||||
}
|
||||
|
||||
user.LastLoginAt = DateTime.UtcNow;
|
||||
|
||||
return new AuthResult
|
||||
{
|
||||
Success = true,
|
||||
User = user,
|
||||
Token = GenerateToken(user.Id)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выйти из системы
|
||||
/// </summary>
|
||||
public void Logout(string token)
|
||||
{
|
||||
if (_tokens.ContainsKey(token))
|
||||
{
|
||||
_tokens.Remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверить токен и получить пользователя
|
||||
/// </summary>
|
||||
public User? ValidateToken(string token)
|
||||
{
|
||||
if (_tokens.TryGetValue(token, out var userId))
|
||||
{
|
||||
return _usersById.TryGetValue(userId, out var user) ? user : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить пользователя по ID
|
||||
/// </summary>
|
||||
public User? GetUserById(Guid userId)
|
||||
{
|
||||
return _usersById.TryGetValue(userId, out var user) ? user : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить пользователя по имени
|
||||
/// </summary>
|
||||
public User? GetUserByUsername(string username)
|
||||
{
|
||||
return _usersByUsername.TryGetValue(username, out var user) ? user : null;
|
||||
}
|
||||
|
||||
#region Helpers (заглушки)
|
||||
|
||||
private static string HashPassword(string password)
|
||||
{
|
||||
// TODO: Использовать реальное хеширование (BCrypt, PBKDF2)
|
||||
return $"hash_{password}";
|
||||
}
|
||||
|
||||
private static bool VerifyPassword(string password, string hash)
|
||||
{
|
||||
// TODO: Использовать реальную проверку пароля
|
||||
return hash == $"hash_{password}";
|
||||
}
|
||||
|
||||
private static string GenerateToken(Guid userId)
|
||||
{
|
||||
// TODO: Использовать JWT или аналогичный механизм
|
||||
var token = $"token_{userId}_{Guid.NewGuid()}";
|
||||
return token;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
437
backend/src/MyBiz.Core/BusinessUnit.cs
Normal file
437
backend/src/MyBiz.Core/BusinessUnit.cs
Normal file
@@ -0,0 +1,437 @@
|
||||
namespace MyBiz.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Тип бизнес-единицы
|
||||
/// </summary>
|
||||
public enum BusinessUnitType
|
||||
{
|
||||
/// <summary>
|
||||
/// Магазин (розничная торговля)
|
||||
/// </summary>
|
||||
Shop,
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика (производство)
|
||||
/// </summary>
|
||||
Factory,
|
||||
|
||||
/// <summary>
|
||||
/// Склад (хранение)
|
||||
/// </summary>
|
||||
Warehouse,
|
||||
|
||||
/// <summary>
|
||||
/// Офис (управление)
|
||||
/// </summary>
|
||||
Office,
|
||||
|
||||
/// <summary>
|
||||
/// Научный центр (исследования)
|
||||
/// </summary>
|
||||
ResearchLab
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Базовая бизнес-единица (магазин, фабрика и т.д.)
|
||||
/// </summary>
|
||||
public class BusinessUnit
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// Название единицы
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Тип бизнес-единицы
|
||||
/// </summary>
|
||||
public BusinessUnitType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ID компании-владельца
|
||||
/// </summary>
|
||||
public Guid CompanyId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Город, где находится единица
|
||||
/// </summary>
|
||||
public string CityId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Координаты на карте
|
||||
/// </summary>
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Уровень развития (1-max)
|
||||
/// </summary>
|
||||
public int Level { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Максимальный уровень
|
||||
/// </summary>
|
||||
public int MaxLevel { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Количество сотрудников
|
||||
/// </summary>
|
||||
public int Employees { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Максимальное количество сотрудников
|
||||
/// </summary>
|
||||
public int MaxEmployees { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Эффективность работы (0-100)
|
||||
/// </summary>
|
||||
public int Efficiency { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Стоимость постройки
|
||||
/// </summary>
|
||||
public decimal BuildCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Содержание в тик (зарплаты, аренда и т.д.)
|
||||
/// </summary>
|
||||
public decimal UpkeepCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Доход за последний период
|
||||
/// </summary>
|
||||
public decimal LastPeriodIncome { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Расходы за последний период
|
||||
/// </summary>
|
||||
public decimal LastPeriodExpenses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата постройки
|
||||
/// </summary>
|
||||
public int BuiltAtTick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Активна ли единица (работает)
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Ссылка на здание (если есть)
|
||||
/// </summary>
|
||||
public Building? Building { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Запасы на складе (для магазинов/складов)
|
||||
/// </summary>
|
||||
public Dictionary<string, int> Inventory { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Производственная цепочка (для фабрик)
|
||||
/// </summary>
|
||||
public ActiveProductionChain? ActiveProduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Рассчитать прибыль за период
|
||||
/// </summary>
|
||||
public decimal PeriodProfit => LastPeriodIncome - LastPeriodExpenses;
|
||||
|
||||
/// <summary>
|
||||
/// Рассчитать рентабельность (%)
|
||||
/// </summary>
|
||||
public decimal Profitability => LastPeriodExpenses > 0
|
||||
? (PeriodProfit / LastPeriodExpenses) * 100
|
||||
: 0;
|
||||
|
||||
/// <summary>
|
||||
/// Обновить эффективность на основе сотрудников
|
||||
/// </summary>
|
||||
public void UpdateEfficiency()
|
||||
{
|
||||
if (MaxEmployees == 0)
|
||||
{
|
||||
Efficiency = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Базовая эффективность зависит от заполненности рабочих мест
|
||||
var staffRate = (decimal)Employees / MaxEmployees;
|
||||
Efficiency = (int)(100 * staffRate);
|
||||
|
||||
// Бонус за уровень
|
||||
Efficiency += (Level - 1) * 5;
|
||||
|
||||
// Ограничение 0-100
|
||||
Efficiency = Math.Clamp(Efficiency, 0, 100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновить состояние (вызывается каждый тик)
|
||||
/// </summary>
|
||||
public virtual void Tick()
|
||||
{
|
||||
// Обновление производства (если есть)
|
||||
ActiveProduction?.Tick();
|
||||
|
||||
// Обновление эффективности
|
||||
UpdateEfficiency();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Нанять сотрудника
|
||||
/// </summary>
|
||||
public bool HireEmployee()
|
||||
{
|
||||
if (Employees < MaxEmployees)
|
||||
{
|
||||
Employees++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Уволить сотрудника
|
||||
/// </summary>
|
||||
public bool FireEmployee()
|
||||
{
|
||||
if (Employees > 0)
|
||||
{
|
||||
Employees--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Повысить уровень
|
||||
/// </summary>
|
||||
public bool Upgrade()
|
||||
{
|
||||
if (Level < MaxLevel)
|
||||
{
|
||||
Level++;
|
||||
MaxEmployees += 10; // Бонус за уровень
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Магазин (розничная торговля)
|
||||
/// </summary>
|
||||
public class Shop : BusinessUnit
|
||||
{
|
||||
public Shop()
|
||||
{
|
||||
Type = BusinessUnitType.Shop;
|
||||
MaxEmployees = 20;
|
||||
BuildCost = 50000m;
|
||||
UpkeepCost = 1000m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Торгуемые продукты
|
||||
/// </summary>
|
||||
public List<string> SoldProductTypes { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Выручка за сегодня
|
||||
/// </summary>
|
||||
public decimal DailyRevenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Количество клиентов за сегодня
|
||||
/// </summary>
|
||||
public int DailyCustomers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Средний чек
|
||||
/// </summary>
|
||||
public decimal AverageCheck => DailyCustomers > 0 ? DailyRevenue / DailyCustomers : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика (производство)
|
||||
/// </summary>
|
||||
public class Factory : BusinessUnit
|
||||
{
|
||||
public Factory()
|
||||
{
|
||||
Type = BusinessUnitType.Factory;
|
||||
MaxEmployees = 100;
|
||||
BuildCost = 200000m;
|
||||
UpkeepCost = 5000m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Производимый продукт
|
||||
/// </summary>
|
||||
public string? OutputProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Требуемые ресурсы (входные продукты)
|
||||
/// </summary>
|
||||
public Dictionary<string, int> RequiredInputs { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Произведено за последний тик
|
||||
/// </summary>
|
||||
public int LastTickOutput { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Простой (нет ресурсов)
|
||||
/// </summary>
|
||||
public bool IsIdle => ActiveProduction == null || !ActiveProduction.IsActive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Склад (хранение)
|
||||
/// </summary>
|
||||
public class Warehouse : BusinessUnit
|
||||
{
|
||||
public Warehouse()
|
||||
{
|
||||
Type = BusinessUnitType.Warehouse;
|
||||
MaxEmployees = 10;
|
||||
BuildCost = 30000m;
|
||||
UpkeepCost = 500m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вместимость склада (единиц товара)
|
||||
/// </summary>
|
||||
public int Capacity { get; set; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Использовано места
|
||||
/// </summary>
|
||||
public int UsedCapacity => Inventory.Values.Sum();
|
||||
|
||||
/// <summary>
|
||||
/// Свободно места
|
||||
/// </summary>
|
||||
public int FreeCapacity => Capacity - UsedCapacity;
|
||||
|
||||
/// <summary>
|
||||
/// Добавить товар на склад
|
||||
/// </summary>
|
||||
public bool AddToInventory(string productId, int quantity)
|
||||
{
|
||||
if (quantity > FreeCapacity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Inventory.ContainsKey(productId))
|
||||
{
|
||||
Inventory[productId] += quantity;
|
||||
}
|
||||
else
|
||||
{
|
||||
Inventory[productId] = quantity;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Взять товар со склада
|
||||
/// </summary>
|
||||
public int RemoveFromInventory(string productId, int quantity)
|
||||
{
|
||||
if (!Inventory.ContainsKey(productId))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var actualQuantity = Math.Min(quantity, Inventory[productId]);
|
||||
Inventory[productId] -= actualQuantity;
|
||||
|
||||
if (Inventory[productId] == 0)
|
||||
{
|
||||
Inventory.Remove(productId);
|
||||
}
|
||||
|
||||
return actualQuantity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Офис (управление компанией)
|
||||
/// </summary>
|
||||
public class Office : BusinessUnit
|
||||
{
|
||||
public Office()
|
||||
{
|
||||
Type = BusinessUnitType.Office;
|
||||
MaxEmployees = 50;
|
||||
BuildCost = 100000m;
|
||||
UpkeepCost = 3000m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Бонус к управлению (влияет на эффективность других зданий)
|
||||
/// </summary>
|
||||
public int ManagementBonus { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Количество управляемых зданий
|
||||
/// </summary>
|
||||
public int ManagedBuildings { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Научный центр (исследования)
|
||||
/// </summary>
|
||||
public class ResearchLab : BusinessUnit
|
||||
{
|
||||
public ResearchLab()
|
||||
{
|
||||
Type = BusinessUnitType.ResearchLab;
|
||||
MaxEmployees = 30;
|
||||
BuildCost = 150000m;
|
||||
UpkeepCost = 4000m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Текущее исследование
|
||||
/// </summary>
|
||||
public string? CurrentResearch { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Прогресс исследования (0-100%)
|
||||
/// </summary>
|
||||
public int ResearchProgress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Наука за тик
|
||||
/// </summary>
|
||||
public int SciencePerTick => Employees * 10 * Efficiency / 100;
|
||||
|
||||
/// <summary>
|
||||
/// Начать исследование
|
||||
/// </summary>
|
||||
public void StartResearch(string technologyId)
|
||||
{
|
||||
CurrentResearch = technologyId;
|
||||
ResearchProgress = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновление исследования
|
||||
/// </summary>
|
||||
public override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
|
||||
if (CurrentResearch != null && ResearchProgress < 100)
|
||||
{
|
||||
ResearchProgress = Math.Min(100, ResearchProgress + SciencePerTick);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,44 +7,124 @@ public class Company
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ID владельца (пользователя)
|
||||
/// </summary>
|
||||
public Guid OwnerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Доступные деньги
|
||||
/// </summary>
|
||||
public decimal Cash { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Активы компании
|
||||
/// </summary>
|
||||
public decimal Assets { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Пассивы (долги)
|
||||
/// </summary>
|
||||
public decimal Liabilities { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Прибыль за последний период
|
||||
/// </summary>
|
||||
public decimal LastPeriodProfit { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Список зданий компании
|
||||
/// </summary>
|
||||
public List<Building> Buildings { get; set; } = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Бизнес-единицы компании (магазины, фабрики и т.д.)
|
||||
/// </summary>
|
||||
public List<BusinessUnit> BusinessUnits { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Складские запасы
|
||||
/// </summary>
|
||||
public Dictionary<ProductType, int> Inventory { get; set; } = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Открытые технологии
|
||||
/// </summary>
|
||||
public HashSet<string> UnlockedTechnologies { get; set; } = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Дата основания
|
||||
/// </summary>
|
||||
public DateTime FoundedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// Рассчитать чистую стоимость
|
||||
/// </summary>
|
||||
public decimal NetWorth => Assets - Liabilities + Cash;
|
||||
|
||||
/// <summary>
|
||||
/// Получить все магазины
|
||||
/// </summary>
|
||||
public IEnumerable<Shop> Shops => BusinessUnits.OfType<Shop>();
|
||||
|
||||
/// <summary>
|
||||
/// Получить все фабрики
|
||||
/// </summary>
|
||||
public IEnumerable<Factory> Factories => BusinessUnits.OfType<Factory>();
|
||||
|
||||
/// <summary>
|
||||
/// Получить все склады
|
||||
/// </summary>
|
||||
public IEnumerable<Warehouse> Warehouses => BusinessUnits.OfType<Warehouse>();
|
||||
|
||||
/// <summary>
|
||||
/// Добавить бизнес-единицу
|
||||
/// </summary>
|
||||
public void AddBusinessUnit(BusinessUnit unit)
|
||||
{
|
||||
unit.CompanyId = Id;
|
||||
BusinessUnits.Add(unit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удалить бизнес-единицу
|
||||
/// </summary>
|
||||
public void RemoveBusinessUnit(Guid unitId)
|
||||
{
|
||||
var unit = BusinessUnits.FirstOrDefault(u => u.Id == unitId);
|
||||
if (unit != null)
|
||||
{
|
||||
BusinessUnits.Remove(unit);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновить состояние всех единиц (вызывается каждый тик)
|
||||
/// </summary>
|
||||
public void Tick()
|
||||
{
|
||||
foreach (var unit in BusinessUnits)
|
||||
{
|
||||
unit.Tick();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Рассчитать общую прибыль за период
|
||||
/// </summary>
|
||||
public decimal CalculateTotalProfit()
|
||||
{
|
||||
return BusinessUnits.Sum(u => u.PeriodProfit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Рассчитать общую стоимость активов
|
||||
/// </summary>
|
||||
public decimal CalculateAssets()
|
||||
{
|
||||
return Buildings.Sum(b => b.TypeConfig?.BuildCost ?? 0) +
|
||||
BusinessUnits.Sum(u => u.BuildCost) +
|
||||
Inventory.Sum(i => i.Key.BasePrice * i.Value);
|
||||
}
|
||||
}
|
||||
|
||||
90
backend/src/MyBiz.Core/User.cs
Normal file
90
backend/src/MyBiz.Core/User.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
namespace MyBiz.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Пользователь системы
|
||||
/// </summary>
|
||||
public class User
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// Имя пользователя (логин)
|
||||
/// </summary>
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Email
|
||||
/// </summary>
|
||||
public string Email { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Хеш пароля (не хранит сам пароль)
|
||||
/// </summary>
|
||||
public string PasswordHash { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Дата регистрации
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// Дата последнего входа
|
||||
/// </summary>
|
||||
public DateTime? LastLoginAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Активен ли пользователь
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Компания, принадлежащая пользователю
|
||||
/// </summary>
|
||||
public Company? Company { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ID компании (для быстрого доступа)
|
||||
/// </summary>
|
||||
public Guid? CompanyId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Статистика игры
|
||||
/// </summary>
|
||||
public UserStats Stats { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Статистика пользователя
|
||||
/// </summary>
|
||||
public class UserStats
|
||||
{
|
||||
/// <summary>
|
||||
/// Всего игр сыграно
|
||||
/// </summary>
|
||||
public int GamesPlayed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Всего часов в игре
|
||||
/// </summary>
|
||||
public int TotalHoursPlayed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Максимальная чистая стоимость за всё время
|
||||
/// </summary>
|
||||
public decimal MaxNetWorth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Всего зданий построено
|
||||
/// </summary>
|
||||
public int TotalBuildingsBuilt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата начала первой игры
|
||||
/// </summary>
|
||||
public DateTime? FirstGameDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата последней игры
|
||||
/// </summary>
|
||||
public DateTime? LastGameDate { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user