From 4f5b7f80d47e120e75d37061ff3161cc3d9204c5 Mon Sep 17 00:00:00 2001 From: ck_yeun9 Date: Sat, 31 May 2025 02:00:25 +0800 Subject: [PATCH] Fixed the issue of automatic database and table creation failure in some scenarios. Fixed the issue of CRUD the DateOnly data type. add dashboard controller and app service. --- .../Business/Asset/AssetService.cs | 4 +- .../Business/Customer/CustomerService.cs | 28 -- .../Business/Customer/ICustomerService.cs | 12 - .../PromotionContentService.cs | 29 +- .../Dashboard/DashboardService.cs | 402 ++++++++++++++++++ .../Dashboard/IDashboardService.cs | 36 ++ .../Employee/EmployeeService.cs | 20 +- .../Administrator/AdminService.cs | 16 + .../Dto/Customer/UpdateCustomerInputDto.cs | 2 +- .../Dto/CreatePromotionContentInputDto.cs | 1 + .../Dto/DeletePromotionContentInputDto.cs | 1 + .../Dto/ReadPromotionContentOutputDto.cs | 2 +- .../Dto/UpdatePromotionContentInputDto.cs | 1 + .../Dto/Employee/CreateEmployeeInputDto.cs | 4 +- .../Dto/Employee/UpdateEmployeeInputDto.cs | 4 +- .../Dashboard/BusinessStatisticsOutputDto.cs | 58 +++ .../Dto/Dashboard/HumanResourcesOutputDto.cs | 38 ++ .../Dto/Dashboard/LogisticsDataOutputDto.cs | 59 +++ .../Dto/Dashboard/RoomStatisticsOutputDto.cs | 57 +++ .../PromotionContent/PromotionContent.cs | 12 + .../Helper/EntityMapper.cs | 50 ++- .../EntityBuilder.cs | 113 ++++- .../Business/Customer/CustomerController.cs | 20 - ...oller.cs => PromotionContentController.cs} | 4 +- .../Dashboard/DashboardController.cs | 57 +++ .../Controllers/Util/UtilityController.cs | 2 +- .../EOM.TSHotelManagement.WebApi.csproj | 2 +- .../Factory/SqlSugarClientFactory.cs | 8 +- .../MigrationConfig/InitializeConfig.cs | 160 ++++++- 29 files changed, 1072 insertions(+), 130 deletions(-) create mode 100644 EOM.TSHotelManagement.Application/Dashboard/DashboardService.cs create mode 100644 EOM.TSHotelManagement.Application/Dashboard/IDashboardService.cs create mode 100644 EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/BusinessStatisticsOutputDto.cs create mode 100644 EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/HumanResourcesOutputDto.cs create mode 100644 EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/LogisticsDataOutputDto.cs create mode 100644 EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/RoomStatisticsOutputDto.cs rename EOM.TSHotelManagement.WebApi/Controllers/Business/PromotionContent/{FontsController.cs => PromotionContentController.cs} (94%) create mode 100644 EOM.TSHotelManagement.WebApi/Controllers/Dashboard/DashboardController.cs diff --git a/EOM.TSHotelManagement.Application/Business/Asset/AssetService.cs b/EOM.TSHotelManagement.Application/Business/Asset/AssetService.cs index cfcc1f2..bb586dd 100644 --- a/EOM.TSHotelManagement.Application/Business/Asset/AssetService.cs +++ b/EOM.TSHotelManagement.Application/Business/Asset/AssetService.cs @@ -92,10 +92,10 @@ namespace EOM.TSHotelManagement.Application { //查询所有部门信息 List depts = new List(); - depts = deptRepository.GetList(a => a.IsDelete != 1); + depts = deptRepository.GetList(); //查询所有员工信息 List employees = new List(); - employees = employeeRepository.GetList(a => a.IsDelete != 1); + employees = employeeRepository.GetList(); ListOutputDto cs = new ListOutputDto(); diff --git a/EOM.TSHotelManagement.Application/Business/Customer/CustomerService.cs b/EOM.TSHotelManagement.Application/Business/Customer/CustomerService.cs index cb9976b..152d77f 100644 --- a/EOM.TSHotelManagement.Application/Business/Customer/CustomerService.cs +++ b/EOM.TSHotelManagement.Application/Business/Customer/CustomerService.cs @@ -209,34 +209,6 @@ namespace EOM.TSHotelManagement.Application } } - /// - /// 查询酒店盈利情况(用于报表) - /// - /// - public List SelectAllMoney() - { - List custoSpends = new List(); - var listSource = spendRepository.GetList(a => a.SettlementStatus.Equals(SpendConsts.Settled)).OrderBy(a => a.ConsumptionTime).ToList(); - var listDates = new List(); - listSource.ForEach(source => - { - var year = Convert.ToDateTime(source.ConsumptionTime).ToString("yyyy"); - if (!custoSpends.Select(a => a.Years).ToList().Contains(year)) - { - var startDate = new DateTime(Convert.ToDateTime(source.ConsumptionTime).Year, 1, 1, 0, 0, 0); - var endDate = new DateTime(Convert.ToDateTime(source.ConsumptionTime).Year, 12, 31, 23, 59, 59); - custoSpends.Add(new CustoSpend - { - Years = year, - Money = listSource.Where(a => a.ConsumptionTime >= startDate && a.ConsumptionTime <= endDate).Sum(a => a.ConsumptionAmount) - }); - } - }); - - custoSpends = custoSpends.OrderBy(a => a.Years).ToList(); - return custoSpends; - } - /// /// 查询所有客户信息 /// diff --git a/EOM.TSHotelManagement.Application/Business/Customer/ICustomerService.cs b/EOM.TSHotelManagement.Application/Business/Customer/ICustomerService.cs index 081e485..9d98946 100644 --- a/EOM.TSHotelManagement.Application/Business/Customer/ICustomerService.cs +++ b/EOM.TSHotelManagement.Application/Business/Customer/ICustomerService.cs @@ -58,18 +58,6 @@ namespace EOM.TSHotelManagement.Application /// BaseOutputDto UpdCustomerTypeByCustoNo(UpdateCustomerInputDto updateCustomerInputDto); - /// - /// 查询酒店盈利情况(用于报表) - /// - /// - List SelectAllMoney(); - - /// - /// 查询所有客户信息 - /// - /// - //ListOutputDto SelectCustoAll(int? pageIndex, int? pageSize, bool onlyVip = false); - /// /// 查询所有客户信息 /// diff --git a/EOM.TSHotelManagement.Application/Business/PromotionContent/PromotionContentService.cs b/EOM.TSHotelManagement.Application/Business/PromotionContent/PromotionContentService.cs index e310c8c..4ffe9a0 100644 --- a/EOM.TSHotelManagement.Application/Business/PromotionContent/PromotionContentService.cs +++ b/EOM.TSHotelManagement.Application/Business/PromotionContent/PromotionContentService.cs @@ -25,6 +25,8 @@ using EOM.TSHotelManagement.Common.Contract; using EOM.TSHotelManagement.Common.Core; using EOM.TSHotelManagement.Common.Util; using EOM.TSHotelManagement.EntityFramework; +using jvncorelib.EntityLib; +using SqlSugar; namespace EOM.TSHotelManagement.Application { @@ -55,8 +57,22 @@ namespace EOM.TSHotelManagement.Application { ListOutputDto fonts = new ListOutputDto(); var count = 0; - - var listSource = fontsRepository.AsQueryable().ToPageList(readPromotionContentInputDto.Page, readPromotionContentInputDto.PageSize, ref count); + var where = Expressionable.Create(); + if (!readPromotionContentInputDto.IsDelete.IsNullOrEmpty()) + { + where = where.And(a => a.IsDelete == readPromotionContentInputDto.IsDelete); + } + var listSource = new List(); + if (!readPromotionContentInputDto.IgnorePaging && readPromotionContentInputDto.Page != 0 && readPromotionContentInputDto.PageSize != 0) + { + listSource = fontsRepository.AsQueryable() + .Where(where.ToExpression()) + .ToPageList(readPromotionContentInputDto.Page, readPromotionContentInputDto.PageSize, ref count); + } + else + { + listSource = fontsRepository.AsQueryable().ToList(); + } fonts.listSource = EntityMapper.MapList(listSource); fonts.total = count; @@ -70,7 +86,7 @@ namespace EOM.TSHotelManagement.Application public ListOutputDto SelectPromotionContents() { ListOutputDto fonts = new ListOutputDto(); - var listSource = fontsRepository.AsQueryable().ToList(); + var listSource = fontsRepository.AsQueryable().Where(a => a.IsDelete != 1).ToList(); fonts.listSource = EntityMapper.MapList(listSource); return fonts; } @@ -104,7 +120,12 @@ namespace EOM.TSHotelManagement.Application { try { - fontsRepository.Update(EntityMapper.Map(deletePromotionContentInputDto)); + fontsRepository.Update(a => new PromotionContent + { + IsDelete = deletePromotionContentInputDto.IsDelete, + DataChgUsr = deletePromotionContentInputDto.DataChgUsr, + DataChgDate = deletePromotionContentInputDto.DataChgDate + }, a => a.PromotionContentNumber == deletePromotionContentInputDto.PromotionContentNumber); } catch (Exception ex) { diff --git a/EOM.TSHotelManagement.Application/Dashboard/DashboardService.cs b/EOM.TSHotelManagement.Application/Dashboard/DashboardService.cs new file mode 100644 index 0000000..9f05dd3 --- /dev/null +++ b/EOM.TSHotelManagement.Application/Dashboard/DashboardService.cs @@ -0,0 +1,402 @@ +using EOM.TSHotelManagement.Common.Contract; +using EOM.TSHotelManagement.Common.Core; +using EOM.TSHotelManagement.Common.Util; +using EOM.TSHotelManagement.EntityFramework; +using EOM.TSHotelManagement.Shared; +using jvncorelib.EntityLib; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EOM.TSHotelManagement.Application +{ + public class DashboardService: IDashboardService + { + /// + /// 房间 + /// + private readonly GenericRepository roomRepository; + + /// + /// 房间 + /// + private readonly GenericRepository roomTypeRepository; + + /// + /// 预约 + /// + private readonly GenericRepository reserRepository; + + /// + /// 客户 + /// + private readonly GenericRepository customerRepository; + + /// + /// 客户类型 + /// + private readonly GenericRepository custoTypeRepository; + + /// + /// 消费信息 + /// + private readonly GenericRepository spendRepository; + + /// + /// 商品 + /// + private readonly GenericRepository sellThingRepository; + + /// + /// 员工 + /// + private readonly GenericRepository employeeRepository; + + /// + /// 部门 + /// + private readonly GenericRepository departmentRepository; + + /// + /// 考勤打卡 + /// + private readonly GenericRepository employeeCheckRepository; + + /// + /// 数据保护 + /// + private readonly IDataProtector dataProtector; + + public DashboardService(GenericRepository roomRepository, GenericRepository roomTypeRepository, GenericRepository reserRepository, GenericRepository customerRepository, GenericRepository custoTypeRepository, GenericRepository spendRepository, GenericRepository sellThingRepository, GenericRepository employeeRepository, GenericRepository departmentRepository, GenericRepository employeeCheckRepository, IDataProtectionProvider dataProtectionProvider) + { + this.roomRepository = roomRepository; + this.roomTypeRepository = roomTypeRepository; + this.reserRepository = reserRepository; + this.customerRepository = customerRepository; + this.custoTypeRepository = custoTypeRepository; + this.spendRepository = spendRepository; + this.sellThingRepository = sellThingRepository; + this.employeeRepository = employeeRepository; + this.departmentRepository = departmentRepository; + this.employeeCheckRepository = employeeCheckRepository; + this.dataProtector = dataProtectionProvider.CreateProtector("ReserInfoProtector"); + } + + /// + /// 获取房间统计信息 + /// + /// + public RoomStatisticsOutputDto RoomStatistics() + { + RoomStatisticsOutputDto roomStatisticsOutputDto = new RoomStatisticsOutputDto(); + + try + { + var helper = new EnumHelper(); + var roomStates = Enum.GetValues(typeof(RoomState)) + .Cast() + .Select(e => new EnumDto + { + Id = (int)e, + Name = e.ToString(), + Description = helper.GetEnumDescription(e) + }) + .ToList(); + var roomTypes = roomTypeRepository.AsQueryable().Where(a => a.IsDelete != 1).ToList(); + + var resers = reserRepository.AsQueryable() + .Where(a => a.ReservationEndDate.ToDateTime(TimeOnly.MinValue) >= DateTime.Now.AddDays(-3) && a.IsDelete != 1).ToList(); + + var roomStateData = roomRepository.AsQueryable().Where(a => roomStates.Select(b => b.Id).ToList().Contains(a.RoomStateId)).ToList(); + + var roomTypeIds = roomTypes.Select(a => a.RoomTypeId).ToList(); + var roomTypeData = roomRepository.AsQueryable().Where(a => roomTypeIds.Contains(a.RoomTypeId) && a.IsDelete != 1).ToList(); + + roomStatisticsOutputDto.Status = new TempRoomStatus + { + Vacant = roomStateData.Count(a => a.RoomStateId == (int)RoomState.Vacant), + Occupied = roomStateData.Count(a => a.RoomStateId == (int)RoomState.Occupied), + Maintenance = roomStateData.Count(a => a.RoomStateId == (int)RoomState.Maintenance), + Dirty = roomStateData.Count(a => a.RoomStateId == (int)RoomState.Dirty), + Reserved = roomStateData.Count(a => a.RoomStateId == (int)RoomState.Reserved) + }; + + var roomTypeDict = roomTypes.ToDictionary(rt => rt.RoomTypeId, rt => rt.RoomTypeName); + roomStatisticsOutputDto.Types = roomTypes.GroupBy(a => a.RoomTypeId) + .Select(g => new TempRoomType + { + Name = roomTypeDict.GetValueOrDefault(g.Key, "未知房型"), + Total = roomTypeData.Count(a => a.RoomTypeId == g.Key), + Remaining = roomTypeData.Count(a => a.RoomTypeId == g.Key && a.RoomStateId == (int)RoomState.Vacant) + }).ToList(); + + roomStatisticsOutputDto.ReservationAlerts = roomStateData + .Where(a => a.RoomStateId == (int)RoomState.Reserved) + .Select(a => + { + var reservation = resers.SingleOrDefault(b => b.ReservationRoomNumber == a.RoomNumber); + var roomType = roomTypes.SingleOrDefault(b => b.RoomTypeId == a.RoomTypeId); + return new TempReservationAlert + { + RoomType = roomType.RoomTypeName, + GuestName = reservation?.CustomerName, + GuestPhoneNo = reservation != null && !reservation.ReservationPhoneNumber.IsNullOrEmpty() + ? dataProtector.Unprotect(reservation.ReservationPhoneNumber) + : string.Empty, + EndDate = reservation?.ReservationEndDate.ToDateTime(TimeOnly.MinValue) ?? DateTime.MinValue + }; + }).ToList(); + } + catch (Exception ex) + { + roomStatisticsOutputDto.Status = new TempRoomStatus + { + Vacant = 0, + Occupied = 0, + Maintenance = 0, + Dirty = 0, + Reserved = 0 + }; + roomStatisticsOutputDto.Types = new List(); + roomStatisticsOutputDto.ReservationAlerts = new List(); + roomStatisticsOutputDto.Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message); + roomStatisticsOutputDto.StatusCode = StatusCodeConstants.InternalServerError; + } + + return roomStatisticsOutputDto; + } + + /// + /// 获取业务统计信息 + /// + /// + public BusinessStatisticsOutputDto BusinessStatistics() + { + var businessStatisticsOutputDto = new BusinessStatisticsOutputDto(); + + var nowUtc = DateTime.UtcNow; + var today = nowUtc.Date; + var weekStart = today.AddDays(-6); + var yearStart = today.AddDays(-365); + + try + { + var customerTypes = custoTypeRepository.AsQueryable().Where(a => a.IsDelete != 1).ToList(); + var customers = customerRepository.AsQueryable().Where(a => a.IsDelete != 1).ToList(); + var startDate = today.AddYears(-1); + var allSpends = spendRepository.AsQueryable() + .Where(a => a.ConsumptionTime >= startDate && a.IsDelete != 1) + .ToList(); + + businessStatisticsOutputDto.GenderRatio = new TempGenderRatio + { + Male = customers.Count(a => a.CustomerGender == (int)GenderType.Male), + Female = customers.Count(a => a.CustomerGender == (int)GenderType.Female) + }; + + var memberTypeDict = customerTypes.ToDictionary(rt => rt.CustomerType, rt => rt.CustomerTypeName); + businessStatisticsOutputDto.MemberTypes = customerTypes + .GroupBy(a => a.CustomerType) + .Select(g => new TempMemberType + { + Type = customerTypes.Any(ct => ct.CustomerType == g.Key) + ? memberTypeDict[g.Key] + : "未知类型", + Count = customers.Count(a => a.CustomerType == g.Key) + }) + .ToList(); + + businessStatisticsOutputDto.DailyConsumption = new TempDailyConsumption + { + Total = allSpends.Where(a => a.ConsumptionTime.Date == today) + .Sum(a => a.ConsumptionAmount), + Settled = allSpends.Where(a => a.ConsumptionTime.Date == today && + a.SettlementStatus == SpendConsts.Settled) + .Sum(a => a.ConsumptionAmount) + }; + + businessStatisticsOutputDto.WeeklyConsumption = new TempDailyConsumption + { + Total = allSpends.Where(a => a.ConsumptionTime.Date >= weekStart) + .Sum(a => a.ConsumptionAmount), + Settled = allSpends.Where(a => a.ConsumptionTime.Date >= weekStart && + a.SettlementStatus == SpendConsts.Settled) + .Sum(a => a.ConsumptionAmount) + }; + + businessStatisticsOutputDto.YearConsumption = new TempDailyConsumption + { + Total = allSpends.Where(a => a.ConsumptionTime.Date >= yearStart) + .Sum(a => a.ConsumptionAmount), + Settled = allSpends.Where(a => a.ConsumptionTime.Date >= yearStart && + a.SettlementStatus == SpendConsts.Settled) + .Sum(a => a.ConsumptionAmount) + }; + + businessStatisticsOutputDto.TotalConsumption = new TempDailyConsumption + { + Total = allSpends.Sum(a => a.ConsumptionAmount), + Settled = allSpends.Where(a => a.SettlementStatus == SpendConsts.Settled) + .Sum(a => a.ConsumptionAmount) + }; + } + catch (Exception ex) + { + businessStatisticsOutputDto.Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message); + businessStatisticsOutputDto.StatusCode = StatusCodeConstants.InternalServerError; + } + + return businessStatisticsOutputDto; + } + + /// + /// 获取后勤统计信息 + /// + /// + public LogisticsDataOutputDto LogisticsStatistics() + { + var dto = new LogisticsDataOutputDto(); + try + { + var sellThings = sellThingRepository.AsQueryable() + .Where(a => a.IsDelete != 1) + .ToList(); + + var totalCount = sellThings.Count; + if (totalCount == 0) + { + dto.TotalProducts = 0; + dto.InventoryWarning = new TempInventoryWarning + { + Percent = 0, + Status = "success", + Text = LocalizationHelper.GetLocalizedString("No products", "暂无商品") + }; + return dto; + } + + var dangerProducts = sellThings + .Where(a => a.Stock <= 50) + .Select(a => a.ProductName) + .ToList(); + + var warningProducts = sellThings + .Where(a => a.Stock > 50 && a.Stock <= 100) + .Select(a => a.ProductName) + .ToList(); + + var statusBuilder = new StringBuilder(); + var lowStockList = new List(); + + if (dangerProducts.Any()) + { + dto.InventoryWarning = new TempInventoryWarning + { + Status = "error", + Percent = (int)Math.Round((dangerProducts.Count * 100.0) / totalCount), + Text = LocalizationHelper.GetLocalizedString( + $"{dangerProducts.Count} products in critical stock", + $"{dangerProducts.Count}种商品库存告急"), + LowStockProducts = dangerProducts + }; + } + else if (warningProducts.Any()) + { + dto.InventoryWarning = new TempInventoryWarning + { + Status = "warning", + Percent = (int)Math.Round((warningProducts.Count * 100.0) / totalCount), + Text = LocalizationHelper.GetLocalizedString( + $"{warningProducts.Count} products in low stock", + $"{warningProducts.Count}种商品库存预警"), + LowStockProducts = warningProducts + }; + } + else + { + dto.InventoryWarning = new TempInventoryWarning + { + Status = "success", + Percent = 0, + Text = LocalizationHelper.GetLocalizedString("Stock normal","库存正常"), + LowStockProducts = new List() + }; + } + + dto.TotalProducts = (int)sellThings.Sum(a => a.Stock); + dto.RecentRecords = spendRepository.AsQueryable() + .Where(a => a.IsDelete != 1) + .OrderByDescending(a => a.ConsumptionTime) + .Take(3) + .Select(a => new TempInventoryRecord + { + RecordId = a.SpendNumber, + OperationType = TempInventoryOperationType.出库, + ProductName = a.ProductName, + Quantity = a.ConsumptionQuantity + }).ToList(); + + dto.StatusCode = StatusCodeConstants.Success; + } + catch (Exception ex) + { + dto.StatusCode = StatusCodeConstants.InternalServerError; + dto.Message = LocalizationHelper.GetLocalizedString( + "System error, please try again later", + "系统繁忙,请稍后重试" + ); + } + return dto; + } + + /// + /// 获取人事统计信息 + /// + /// + public HumanResourcesOutputDto HumanResourcesStatistics() + { + var humanResourcesOutputDto = new HumanResourcesOutputDto(); + + try + { + var employees = employeeRepository.AsQueryable().Where(a => a.IsDelete != 1).ToList(); + var departments = departmentRepository.AsQueryable().Where(a => a.IsDelete != 1).ToList(); + var employeeIds = employees.Select(a => a.EmployeeId).ToList(); + var employeeChecks = employeeCheckRepository.AsQueryable().Where(a => employeeIds.Contains(a.EmployeeId) && a.IsDelete != 1).ToList(); + + humanResourcesOutputDto.TotalEmployees = employees.Count; + humanResourcesOutputDto.TotalDepartments = departments.Count; + humanResourcesOutputDto.Attendance = new TempAttendanceRecord + { + Present = employeeChecks.Count(a => a.CheckTime.Hour <= 9 && a.CheckTime.Hour >= 18), + Late = employeeChecks.Count(a => a.CheckTime.Hour > 9), + Absent = employees.Count - employeeChecks.Count(a => a.CheckTime.Date == DateTime.Now.Date) + }; + + } + catch (Exception ex) + { + humanResourcesOutputDto.Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message); + humanResourcesOutputDto.StatusCode = StatusCodeConstants.InternalServerError; + } + + return humanResourcesOutputDto; + } + + private string GetWarningText(int lowStockCount) + { + return lowStockCount switch + { + 0 => LocalizationHelper.GetLocalizedString("Stock normal", "库存正常"), + > 0 and <= 5 => LocalizationHelper.GetLocalizedString("Low stock warning", "库存偏低"), + > 5 => LocalizationHelper.GetLocalizedString("Critical stock", "库存告急"), + _ => LocalizationHelper.GetLocalizedString("Stock abnormal", "库存异常") + }; + } + + } +} diff --git a/EOM.TSHotelManagement.Application/Dashboard/IDashboardService.cs b/EOM.TSHotelManagement.Application/Dashboard/IDashboardService.cs new file mode 100644 index 0000000..18af8b8 --- /dev/null +++ b/EOM.TSHotelManagement.Application/Dashboard/IDashboardService.cs @@ -0,0 +1,36 @@ +using EOM.TSHotelManagement.Common.Contract; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EOM.TSHotelManagement.Application +{ + public interface IDashboardService + { + /// + /// 获取房间统计信息 + /// + /// + RoomStatisticsOutputDto RoomStatistics(); + + /// + /// 获取业务统计信息 + /// + /// + BusinessStatisticsOutputDto BusinessStatistics(); + + /// + /// 获取后勤统计信息 + /// + /// + LogisticsDataOutputDto LogisticsStatistics(); + + /// + /// 获取人事统计信息 + /// + /// + HumanResourcesOutputDto HumanResourcesStatistics(); + } +} diff --git a/EOM.TSHotelManagement.Application/Employee/EmployeeService.cs b/EOM.TSHotelManagement.Application/Employee/EmployeeService.cs index d00621c..86d50e0 100644 --- a/EOM.TSHotelManagement.Application/Employee/EmployeeService.cs +++ b/EOM.TSHotelManagement.Application/Employee/EmployeeService.cs @@ -26,6 +26,7 @@ using EOM.TSHotelManagement.Common.Core; using EOM.TSHotelManagement.Common.Util; using EOM.TSHotelManagement.EntityFramework; using EOM.TSHotelManagement.Shared; +using jvncorelib.EncryptorLib; using jvncorelib.EntityLib; using Microsoft.AspNetCore.DataProtection; using SqlSugar; @@ -51,7 +52,8 @@ namespace EOM.TSHotelManagement.Application /// /// /// - public class EmployeeService(GenericRepository workerRepository, GenericRepository photoRepository, GenericRepository educationRepository, GenericRepository nationRepository, GenericRepository deptRepository, GenericRepository positionRepository, GenericRepository passportTypeRepository, IDataProtectionProvider dataProtectionProvider, JWTHelper jWTHelper, MailHelper mailHelper) : IEmployeeService + /// + public class EmployeeService(GenericRepository workerRepository, GenericRepository photoRepository, GenericRepository educationRepository, GenericRepository nationRepository, GenericRepository deptRepository, GenericRepository positionRepository, GenericRepository passportTypeRepository, IDataProtectionProvider dataProtectionProvider, JWTHelper jWTHelper, MailHelper mailHelper, EncryptLib encryptLib) : IEmployeeService { /// /// 员工信息 @@ -103,6 +105,11 @@ namespace EOM.TSHotelManagement.Application /// private readonly MailHelper mailHelper = mailHelper; + /// + /// 自主加密库 + /// + private readonly EncryptLib encryptLib = encryptLib; + /// /// 修改员工信息 /// @@ -416,8 +423,15 @@ namespace EOM.TSHotelManagement.Application w = null; return new SingleOutputDto { Source = null,Message = LocalizationHelper.GetLocalizedString("Employee does not exist or entered incorrectly", "员工不存在或输入有误") }; } - - var dbPwd = dataProtector.Unprotect(w.Password); + var dbPwd = string.Empty; + try + { + dbPwd = dataProtector.Unprotect(w.Password); + } + catch (Exception) + { + dbPwd = encryptLib.Decryption(w.Password); + } if (dbPwd != readEmployeeInputDto.Password) { diff --git a/EOM.TSHotelManagement.Application/SystemManagement/Administrator/AdminService.cs b/EOM.TSHotelManagement.Application/SystemManagement/Administrator/AdminService.cs index 445e234..9ef4c30 100644 --- a/EOM.TSHotelManagement.Application/SystemManagement/Administrator/AdminService.cs +++ b/EOM.TSHotelManagement.Application/SystemManagement/Administrator/AdminService.cs @@ -296,6 +296,17 @@ namespace EOM.TSHotelManagement.Application { try { + var haveSuperAdmin = adminRepository.IsAny(a => a.IsSuperAdmin == createAdministratorInputDto.IsSuperAdmin && a.IsDelete != 1); + if (haveSuperAdmin) + { + return new BaseOutputDto { Message = LocalizationHelper.GetLocalizedString("Super Administrator already exists", "超级管理员已存在"), StatusCode = StatusCodeConstants.InternalServerError }; + } + var haveAdmin = adminRepository.IsAny(a => a.Account == createAdministratorInputDto.Account); + if (haveAdmin) + { + return new BaseOutputDto { Message = LocalizationHelper.GetLocalizedString("Administrator already exists", "管理员已存在"), StatusCode = StatusCodeConstants.InternalServerError }; + } + createAdministratorInputDto.Password = dataProtector.Protect(createAdministratorInputDto.Password); adminRepository.Insert(EntityMapper.Map(createAdministratorInputDto)); } @@ -334,6 +345,11 @@ namespace EOM.TSHotelManagement.Application { try { + var isSuperAdmin = adminRepository.IsAny(a => a.Number == deleteAdministratorInputDto.Number && a.IsSuperAdmin == 1); + if (isSuperAdmin) + { + return new BaseOutputDto { Message = LocalizationHelper.GetLocalizedString("Super Administrator cannot be deleted", "超级管理员无法删除"), StatusCode = StatusCodeConstants.InternalServerError }; + } adminRepository.Delete(EntityMapper.Map(deleteAdministratorInputDto)); } catch (Exception ex) diff --git a/EOM.TSHotelManagement.Common.Contract/Business/Customer/Dto/Customer/UpdateCustomerInputDto.cs b/EOM.TSHotelManagement.Common.Contract/Business/Customer/Dto/Customer/UpdateCustomerInputDto.cs index f733cc7..06f8c36 100644 --- a/EOM.TSHotelManagement.Common.Contract/Business/Customer/Dto/Customer/UpdateCustomerInputDto.cs +++ b/EOM.TSHotelManagement.Common.Contract/Business/Customer/Dto/Customer/UpdateCustomerInputDto.cs @@ -7,7 +7,7 @@ namespace EOM.TSHotelManagement.Common.Contract public int? CustomerGender { get; set; } public int PassportId { get; set; } public string CustomerPhoneNumber { get; set; } - public DateTime DateOfBirth { get; set; } + public DateOnly DateOfBirth { get; set; } public string IdCardNumber { get; set; } public string CustomerAddress { get; set; } public int CustomerType { get; set; } diff --git a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/CreatePromotionContentInputDto.cs b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/CreatePromotionContentInputDto.cs index 3d714ae..0e35854 100644 --- a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/CreatePromotionContentInputDto.cs +++ b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/CreatePromotionContentInputDto.cs @@ -2,6 +2,7 @@ namespace EOM.TSHotelManagement.Common.Contract { public class CreatePromotionContentInputDto : BaseInputDto { + public string PromotionContentNumber { get; set; } public string PromotionContentMessage { get; set; } } } diff --git a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/DeletePromotionContentInputDto.cs b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/DeletePromotionContentInputDto.cs index 6ca169e..0ce9477 100644 --- a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/DeletePromotionContentInputDto.cs +++ b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/DeletePromotionContentInputDto.cs @@ -2,6 +2,7 @@ namespace EOM.TSHotelManagement.Common.Contract { public class DeletePromotionContentInputDto : BaseInputDto { + public string PromotionContentNumber { get; set; } } } diff --git a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/ReadPromotionContentOutputDto.cs b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/ReadPromotionContentOutputDto.cs index 71d65e2..13fdc67 100644 --- a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/ReadPromotionContentOutputDto.cs +++ b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/ReadPromotionContentOutputDto.cs @@ -3,7 +3,7 @@ namespace EOM.TSHotelManagement.Common.Contract public class ReadPromotionContentOutputDto { public int Id { get; set; } - public int PromotionContentId { get; set; } + public string PromotionContentNumber { get; set; } public string PromotionContentMessage { get; set; } } } diff --git a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/UpdatePromotionContentInputDto.cs b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/UpdatePromotionContentInputDto.cs index b2b847a..477a9b1 100644 --- a/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/UpdatePromotionContentInputDto.cs +++ b/EOM.TSHotelManagement.Common.Contract/Business/PromotionContent/Dto/UpdatePromotionContentInputDto.cs @@ -2,6 +2,7 @@ namespace EOM.TSHotelManagement.Common.Contract { public class UpdatePromotionContentInputDto : BaseInputDto { + public string PromotionContentNumber { get; set; } public string PromotionContentMessage { get; set; } } } diff --git a/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/CreateEmployeeInputDto.cs b/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/CreateEmployeeInputDto.cs index 5613b7d..6eef3ba 100644 --- a/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/CreateEmployeeInputDto.cs +++ b/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/CreateEmployeeInputDto.cs @@ -5,7 +5,7 @@ namespace EOM.TSHotelManagement.Common.Contract public string EmployeeId { get; set; } public string EmployeeName { get; set; } public int Gender { get; set; } - public DateTime DateOfBirth { get; set; } + public DateOnly DateOfBirth { get; set; } public string Ethnicity { get; set; } public string PhoneNumber { get; set; } public string Department { get; set; } @@ -14,7 +14,7 @@ namespace EOM.TSHotelManagement.Common.Contract public int IdCardType { get; set; } public string IdCardNumber { get; set; } public string Password { get; set; } - public DateTime HireDate { get; set; } + public DateOnly HireDate { get; set; } public string PoliticalAffiliation { get; set; } public string EducationLevel { get; set; } public string EmailAddress { get; set; } diff --git a/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/UpdateEmployeeInputDto.cs b/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/UpdateEmployeeInputDto.cs index e70734d..04d47a5 100644 --- a/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/UpdateEmployeeInputDto.cs +++ b/EOM.TSHotelManagement.Common.Contract/Employee/Dto/Employee/UpdateEmployeeInputDto.cs @@ -5,7 +5,7 @@ namespace EOM.TSHotelManagement.Common.Contract public string EmployeeId { get; set; } public string EmployeeName { get; set; } public int Gender { get; set; } - public DateTime DateOfBirth { get; set; } + public DateOnly DateOfBirth { get; set; } public string Ethnicity { get; set; } public string PhoneNumber { get; set; } public string Department { get; set; } @@ -13,7 +13,7 @@ namespace EOM.TSHotelManagement.Common.Contract public string Position { get; set; } public int IdCardType { get; set; } public string IdCardNumber { get; set; } - public DateTime HireDate { get; set; } + public DateOnly HireDate { get; set; } public string PoliticalAffiliation { get; set; } public string EducationLevel { get; set; } public string OldPassword { get; set; } diff --git a/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/BusinessStatisticsOutputDto.cs b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/BusinessStatisticsOutputDto.cs new file mode 100644 index 0000000..10347f7 --- /dev/null +++ b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/BusinessStatisticsOutputDto.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace EOM.TSHotelManagement.Common.Contract +{ + public class BusinessStatisticsOutputDto:BaseOutputDto + { + [JsonPropertyName("genderRatio")] + public TempGenderRatio GenderRatio { get; set; } + + [JsonPropertyName("memberTypes")] + public List MemberTypes { get; set; } + + [JsonPropertyName("dailyConsumption")] + public TempDailyConsumption DailyConsumption { get; set; } + + [JsonPropertyName("weeklyConsumption")] + public TempDailyConsumption WeeklyConsumption { get; set; } + + [JsonPropertyName("yearConsumption")] + public TempDailyConsumption YearConsumption { get; set; } + + [JsonPropertyName("totalConsumption")] + public TempDailyConsumption TotalConsumption { get; set; } + } + + public class TempGenderRatio + { + [JsonPropertyName("male")] + public int Male { get; set; } + + [JsonPropertyName("female")] + public int Female { get; set; } + } + + public class TempMemberType + { + [JsonPropertyName("type")] + public string Type { get; set; } + + [JsonPropertyName("count")] + public int Count { get; set; } + } + + public class TempDailyConsumption + { + [JsonPropertyName("total")] + public decimal Total { get; set; } + + [JsonPropertyName("settled")] + public decimal Settled { get; set; } + } +} diff --git a/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/HumanResourcesOutputDto.cs b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/HumanResourcesOutputDto.cs new file mode 100644 index 0000000..dfb4db5 --- /dev/null +++ b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/HumanResourcesOutputDto.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace EOM.TSHotelManagement.Common.Contract +{ + public class HumanResourcesOutputDto : BaseOutputDto + { + [JsonPropertyName("totalEmployees")] + public int TotalEmployees { get; set; } + + [JsonPropertyName("totalDepartments")] + public int TotalDepartments { get; set; } + + [JsonPropertyName("attendance")] + [Required] + public TempAttendanceRecord Attendance { get; set; } + } + + public class TempAttendanceRecord + { + [JsonPropertyName("present")] + public int Present { get; set; } + + [JsonPropertyName("late")] + public int Late { get; set; } + + [JsonPropertyName("absent")] + public int Absent { get; set; } + + [JsonIgnore] + public int TotalAttendance => Present + Late; + } +} diff --git a/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/LogisticsDataOutputDto.cs b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/LogisticsDataOutputDto.cs new file mode 100644 index 0000000..d5ceb93 --- /dev/null +++ b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/LogisticsDataOutputDto.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace EOM.TSHotelManagement.Common.Contract +{ + public class LogisticsDataOutputDto : BaseOutputDto + { + [JsonPropertyName("totalProducts")] + public int TotalProducts { get; set; } + + [JsonPropertyName("inventoryWarning")] + public TempInventoryWarning InventoryWarning { get; set; } + + [JsonPropertyName("recentRecords")] + public List RecentRecords { get; set; } + } + + public class TempInventoryWarning + { + [JsonPropertyName("percent")] + public int Percent { get; set; } + + [JsonPropertyName("status")] + public string Status { get; set; } + + [JsonPropertyName("text")] + public string Text { get; set; } + + public List LowStockProducts { get; set; } + } + + public class TempInventoryRecord + { + [JsonPropertyName("id")] + public string RecordId { get; set; } + + [JsonPropertyName("type")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public TempInventoryOperationType OperationType { get; set; } + + [JsonPropertyName("productName")] + public string ProductName { get; set; } + + [JsonPropertyName("quantity")] + public int Quantity { get; set; } + } + + public enum TempInventoryOperationType + { + 出库 = 1, + 入库 = 2 + } + +} diff --git a/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/RoomStatisticsOutputDto.cs b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/RoomStatisticsOutputDto.cs new file mode 100644 index 0000000..b3c93d4 --- /dev/null +++ b/EOM.TSHotelManagement.Common.Contract/Util/Dto/Dashboard/RoomStatisticsOutputDto.cs @@ -0,0 +1,57 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace EOM.TSHotelManagement.Common.Contract +{ + public class RoomStatisticsOutputDto : BaseOutputDto + { + [JsonPropertyName("status")] + public TempRoomStatus Status { get; set; } + + [JsonPropertyName("types")] + public List Types { get; set; } + + [JsonPropertyName("reservationAlerts")] + public List ReservationAlerts { get; set; } + } + public class TempRoomStatus + { + [JsonPropertyName("空房")] + public int Vacant { get; set; } + + [JsonPropertyName("已住")] + public int Occupied { get; set; } + + [JsonPropertyName("维修")] + public int Maintenance { get; set; } + + [JsonPropertyName("脏房")] + public int Dirty { get; set; } + + [JsonPropertyName("预约")] + public int Reserved { get; set; } + } + + public class TempRoomType + { + [JsonPropertyName("name")] + public string Name { get; set; } + [JsonPropertyName("total")] + public int Total { get; set; } + [JsonPropertyName("remaining")] + public int Remaining { get; set; } + } + + public class TempReservationAlert + { + [JsonPropertyName("roomType")] + public string RoomType { get; set; } + [JsonPropertyName("guestName")] + public string GuestName { get; set; } + [JsonPropertyName("guestPhoneNo")] + public string GuestPhoneNo { get; set; } + [JsonPropertyName("endDate")] + [DataType(DataType.Date)] + public DateTime EndDate { get; set; } + } +} \ No newline at end of file diff --git a/EOM.TSHotelManagement.Common.Core/Business/PromotionContent/PromotionContent.cs b/EOM.TSHotelManagement.Common.Core/Business/PromotionContent/PromotionContent.cs index c17de3b..71108f7 100644 --- a/EOM.TSHotelManagement.Common.Core/Business/PromotionContent/PromotionContent.cs +++ b/EOM.TSHotelManagement.Common.Core/Business/PromotionContent/PromotionContent.cs @@ -38,6 +38,18 @@ namespace EOM.TSHotelManagement.Common.Core [SugarColumn(ColumnName = "id", IsIdentity = true, IsPrimaryKey = true, IsNullable = false, ColumnDescription = "编号 (ID)")] public int Id { get; set; } + /// + /// 宣传ID (Promotion Content Number) + /// + [SugarColumn( + ColumnName = "banner_number", + ColumnDescription = "宣传ID (Promotion Content ID)", + IsNullable = false, + Length = 128, + IsPrimaryKey = true + )] + public string PromotionContentNumber { get; set; } + /// /// 宣传内容 (Promotion Content Message) /// diff --git a/EOM.TSHotelManagement.Common.Util/Helper/EntityMapper.cs b/EOM.TSHotelManagement.Common.Util/Helper/EntityMapper.cs index ad9dc0b..38b55d2 100644 --- a/EOM.TSHotelManagement.Common.Util/Helper/EntityMapper.cs +++ b/EOM.TSHotelManagement.Common.Util/Helper/EntityMapper.cs @@ -61,18 +61,19 @@ namespace EOM.TSHotelManagement.Common.Util { var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; - if (underlyingTargetType == typeof(string)) + if (value is DateOnly dateOnly) { - return value.ToString(); + return HandleDateOnlyConversion(dateOnly, underlyingTargetType); } - if (value is DateOnly dateOnly && underlyingTargetType == typeof(DateTime)) + if (value is DateTime dateTime) { - return dateOnly.ToDateTime(TimeOnly.MinValue); + return HandleDateTimeConversion(dateTime, underlyingTargetType); } - if (value is DateTime dateTime && underlyingTargetType == typeof(DateOnly)) + + if (value is string dateString) { - return DateOnly.FromDateTime(dateTime); + return HandleStringConversion(dateString, underlyingTargetType); } try @@ -86,6 +87,43 @@ namespace EOM.TSHotelManagement.Common.Util } } + private static object HandleDateOnlyConversion(DateOnly dateOnly, Type targetType) + { + return targetType switch + { + _ when targetType == typeof(DateTime) => dateOnly.ToDateTime(TimeOnly.MinValue), + _ when targetType == typeof(DateTimeOffset) => new DateTimeOffset(dateOnly.ToDateTime(TimeOnly.MinValue)), + _ when targetType == typeof(string) => dateOnly.ToString("yyyy-MM-dd"), + _ when targetType == typeof(DateOnly) => dateOnly, + _ => throw new InvalidCastException($"Unsupported DateOnly conversion to {targetType}") + }; + } + + private static object HandleDateTimeConversion(DateTime dateTime, Type targetType) + { + return targetType switch + { + _ when targetType == typeof(DateOnly) => DateOnly.FromDateTime(dateTime), + _ when targetType == typeof(DateTimeOffset) => new DateTimeOffset(dateTime), + _ when targetType == typeof(string) => dateTime.ToString("yyyy-MM-dd HH:mm:ss"), + _ => dateTime // ֱӷԭʼֵ + }; + } + + private static object HandleStringConversion(string dateString, Type targetType) + { + if (DateTime.TryParse(dateString, out DateTime dt)) + { + return targetType switch + { + _ when targetType == typeof(DateOnly) => DateOnly.FromDateTime(dt), + _ when targetType == typeof(DateTime) => dt, + _ => dt + }; + } + throw new FormatException($"Invalid date string: {dateString}"); + } + /// /// ת /// diff --git a/EOM.TSHotelManagement.Migration/EntityBuilder.cs b/EOM.TSHotelManagement.Migration/EntityBuilder.cs index 44ef3d7..2b4fe60 100644 --- a/EOM.TSHotelManagement.Migration/EntityBuilder.cs +++ b/EOM.TSHotelManagement.Migration/EntityBuilder.cs @@ -1,10 +1,4 @@ using EOM.TSHotelManagement.Common.Core; -using SqlSugar; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace EOM.TSHotelManagement.Migration { @@ -425,17 +419,6 @@ namespace EOM.TSHotelManagement.Migration DataInsDate = DateTime.Now, }, new Menu // 33 - { - Key = "systemmodule", - Title = "系统模块", - Path = "/systemmodule", - Parent = 31, - Icon = "DatabaseOutlined", - IsDelete = 0, - DataInsUsr = "System", - DataInsDate = DateTime.Now, - }, - new Menu // 34 { Key = "menumanagement", Title = "菜单管理", @@ -446,7 +429,7 @@ namespace EOM.TSHotelManagement.Migration DataInsUsr = "System", DataInsDate = DateTime.Now, }, - new Menu // 35 + new Menu // 34 { Key = "rolemanagement", Title = "角色管理", @@ -457,7 +440,7 @@ namespace EOM.TSHotelManagement.Migration DataInsUsr = "System", DataInsDate = DateTime.Now, }, - new Menu // 36 + new Menu // 35 { Key = "admintypemanagement", Title = "管理员类型管理", @@ -468,6 +451,28 @@ namespace EOM.TSHotelManagement.Migration DataInsUsr = "System", DataInsDate = DateTime.Now, }, + new Menu // 36 + { + Key = "dashboard", + Title = "仪表盘", + Path = "/dashboard", + Parent = 1, + Icon = "DashboardOutlined", + IsDelete = 0, + DataInsUsr = "System", + DataInsDate = DateTime.Now, + }, + new Menu // 37 + { + Key = "promotioncontent", + Title = "宣传联动内容", + Path = "/promotioncontent", + Parent = 2, + Icon = "DashboardOutlined", + IsDelete = 0, + DataInsUsr = "System", + DataInsDate = DateTime.Now, + }, new NavBar { NavigationBarName = "客房管理", @@ -501,6 +506,72 @@ namespace EOM.TSHotelManagement.Migration DataInsUsr = "System", DataInsDate = DateTime.Now }, + new Department + { + DepartmentNumber = "D-000001", + DepartmentName = "酒店部", + DepartmentDescription = null, + DepartmentCreationDate = DateOnly.FromDateTime(DateTime.Now), + DepartmentLeader = "WK010", + IsDelete = 0, + DataInsUsr = "System", + DataInsDate = DateTime.Now + }, + new Position + { + PositionNumber = "P-000001", + PositionName = "初级职员", + IsDelete = 0, + DataInsUsr = "System", + DataInsDate = DateTime.Now + }, + new Education + { + EducationNumber = "E-000001", + EducationName = "本科", + IsDelete = 0, + DataInsUsr = "System", + DataInsDate = DateTime.Now + }, + new Nation + { + NationNumber = "N-000001", + NationName = "汉族", + IsDelete = 0, + DataInsUsr = "System", + DataInsDate = DateTime.Now + }, + new PassportType + { + PassportId = 666, + PassportName = "中国居民身份证", + IsDelete = 0, + DataInsUsr = "System", + DataInsDate = DateTime.Now + }, + new Employee + { + EmployeeId = "WK010", + EmployeeName = "阿杰", + DateOfBirth = DateOnly.FromDateTime(new DateTime(1999,7,20,0,0,0)), + Password="oi6+T4604MqlB/SWAvrJBQ==·?bdc^^ - /// 查询酒店盈利情况(用于报表) - /// - /// - [HttpGet] - public List SelectAllMoney() - { - return customerService.SelectAllMoney(); - } - - /// - /// 查询所有客户信息 - /// - /// - //[HttpGet] - //public ListOutputDto SelectCustoAll([FromQuery] int pageIndex, int pageSize, bool onlyVip = false) - //{ - // return customerService.SelectCustoAll(pageIndex, pageSize, onlyVip); - //} - /// /// 查询所有客户信息 /// diff --git a/EOM.TSHotelManagement.WebApi/Controllers/Business/PromotionContent/FontsController.cs b/EOM.TSHotelManagement.WebApi/Controllers/Business/PromotionContent/PromotionContentController.cs similarity index 94% rename from EOM.TSHotelManagement.WebApi/Controllers/Business/PromotionContent/FontsController.cs rename to EOM.TSHotelManagement.WebApi/Controllers/Business/PromotionContent/PromotionContentController.cs index b8123cd..254ded1 100644 --- a/EOM.TSHotelManagement.WebApi/Controllers/Business/PromotionContent/FontsController.cs +++ b/EOM.TSHotelManagement.WebApi/Controllers/Business/PromotionContent/PromotionContentController.cs @@ -7,7 +7,7 @@ namespace EOM.TSHotelManagement.WebApi.Controllers /// /// 酒店宣传联动内容控制器 /// - public class FontsController : ControllerBase + public class PromotionContentController : ControllerBase { /// /// 酒店宣传联动内容 @@ -18,7 +18,7 @@ namespace EOM.TSHotelManagement.WebApi.Controllers /// /// /// - public FontsController(IPromotionContentService fontsService) + public PromotionContentController(IPromotionContentService fontsService) { this.fontsService = fontsService; } diff --git a/EOM.TSHotelManagement.WebApi/Controllers/Dashboard/DashboardController.cs b/EOM.TSHotelManagement.WebApi/Controllers/Dashboard/DashboardController.cs new file mode 100644 index 0000000..b25fd31 --- /dev/null +++ b/EOM.TSHotelManagement.WebApi/Controllers/Dashboard/DashboardController.cs @@ -0,0 +1,57 @@ +using EOM.TSHotelManagement.Application; +using EOM.TSHotelManagement.Common.Contract; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace EOM.TSHotelManagement.WebApi.Controllers +{ + public class DashboardController : ControllerBase + { + private readonly IDashboardService dashboardService; + + public DashboardController(IDashboardService dashboardService) + { + this.dashboardService = dashboardService; + } + + /// + /// 获取房间统计信息 + /// + /// + [HttpGet] + public RoomStatisticsOutputDto RoomStatistics() + { + return dashboardService.RoomStatistics(); + } + + /// + /// 获取业务统计信息 + /// + /// + [HttpGet] + public BusinessStatisticsOutputDto BusinessStatistics() + { + return dashboardService.BusinessStatistics(); + } + + /// + /// 获取后勤统计信息 + /// + /// + [HttpGet] + public LogisticsDataOutputDto LogisticsStatistics() + { + return dashboardService.LogisticsStatistics(); + } + + /// + /// 获取人事统计信息 + /// + /// + [HttpGet] + public HumanResourcesOutputDto HumanResourcesStatistics() + { + return dashboardService.HumanResourcesStatistics(); + } + } +} diff --git a/EOM.TSHotelManagement.WebApi/Controllers/Util/UtilityController.cs b/EOM.TSHotelManagement.WebApi/Controllers/Util/UtilityController.cs index 8b5a64b..b701b46 100644 --- a/EOM.TSHotelManagement.WebApi/Controllers/Util/UtilityController.cs +++ b/EOM.TSHotelManagement.WebApi/Controllers/Util/UtilityController.cs @@ -1,5 +1,5 @@ using EOM.TSHotelManagement.Application; -using EOM.TSHotelManagement.Common.Contract; +using EOM.TSHotelManagement.Common.Contract; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/EOM.TSHotelManagement.WebApi/EOM.TSHotelManagement.WebApi.csproj b/EOM.TSHotelManagement.WebApi/EOM.TSHotelManagement.WebApi.csproj index 0d9aba3..ad7ebcf 100644 --- a/EOM.TSHotelManagement.WebApi/EOM.TSHotelManagement.WebApi.csproj +++ b/EOM.TSHotelManagement.WebApi/EOM.TSHotelManagement.WebApi.csproj @@ -24,10 +24,10 @@ - + diff --git a/EOM.TSHotelManagement.WebApi/Factory/SqlSugarClientFactory.cs b/EOM.TSHotelManagement.WebApi/Factory/SqlSugarClientFactory.cs index 889c3e6..48eef00 100644 --- a/EOM.TSHotelManagement.WebApi/Factory/SqlSugarClientFactory.cs +++ b/EOM.TSHotelManagement.WebApi/Factory/SqlSugarClientFactory.cs @@ -53,17 +53,15 @@ namespace EOM.TSHotelManagement.WebApi case DbType.PostgreSQL: config.MoreSettings = new ConnMoreSettings { - PgSqlIsAutoToLower = false, //数据库存在大写字段的 - //,需要把这个设为false ,并且实体和字段名称要一样 - //如果数据库里的数据表本身就为小写,则改成true - //详细可以参考官网https://www.donet5.com/Home/Doc + PgSqlIsAutoToLower = true, + PgSqlIsAutoToLowerCodeFirst = true, DisableMillisecond = true }; break; case DbType.SqlServer: config.MoreSettings = new ConnMoreSettings() { - SqlServerCodeFirstNvarchar = true,//建表字符串默认Nvarchar + SqlServerCodeFirstNvarchar = true, IsWithNoLockQuery = true }; break; diff --git a/EOM.TSHotelManagement.WebApi/MigrationConfig/InitializeConfig.cs b/EOM.TSHotelManagement.WebApi/MigrationConfig/InitializeConfig.cs index a41a46e..4538a7a 100644 --- a/EOM.TSHotelManagement.WebApi/MigrationConfig/InitializeConfig.cs +++ b/EOM.TSHotelManagement.WebApi/MigrationConfig/InitializeConfig.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using MySqlConnector; +using Npgsql; using Oracle.ManagedDataAccess.Client; using SqlSugar; using System; @@ -44,11 +45,24 @@ namespace EOM.TSHotelManagement.WebApi { using (var masterDb = CreateMasterConnection(config, dbName, dbSettings.DbType)) { - if (!masterDb.DbMaintenance.GetDataBaseList().Contains(dbSettings.Database)) + if (dbSettings.DbType == DbType.PostgreSQL) { - Console.WriteLine($"Creating database {dbSettings.Database}..."); - masterDb.DbMaintenance.CreateDatabase(dbSettings.Database,null); - Console.WriteLine("Database created successfully"); + var dbExists = masterDb.Ado.GetInt($"SELECT 1 FROM pg_database WHERE datname = '{dbSettings.Database}'") > 0; + if (!dbExists) + { + Console.WriteLine($"Creating database {dbSettings.Database}..."); + masterDb.Ado.ExecuteCommand($"CREATE DATABASE \"{dbSettings.Database}\""); + Console.WriteLine("Database created successfully"); + } + } + else + { + if (!masterDb.DbMaintenance.GetDataBaseList().Contains(dbSettings.Database)) + { + Console.WriteLine($"Creating database {dbSettings.Database}..."); + masterDb.DbMaintenance.CreateDatabase(dbSettings.Database, null); + Console.WriteLine("Database created successfully"); + } } } } @@ -110,6 +124,9 @@ namespace EOM.TSHotelManagement.WebApi case DbType.Sqlite: var sqliteBuilder = new SqliteConnectionStringBuilder(connectionString); return (sqliteBuilder.DataSource, dbType); + case DbType.PostgreSQL: + var pgsqlBuilder = new NpgsqlConnectionStringBuilder(connectionString); + return (pgsqlBuilder.Database, dbType); default: throw new NotSupportedException($"Unsupported DbType: {dbType}"); } @@ -143,6 +160,14 @@ namespace EOM.TSHotelManagement.WebApi UserID = "sys as sysdba", }; break; + case DbType.PostgreSQL: + builder = new NpgsqlConnectionStringBuilder(connectionString) + { + Database = "postgres", + Timeout = 30, + Pooling = false + }; + break; case DbType.Sqlite: break; } @@ -156,6 +181,9 @@ namespace EOM.TSHotelManagement.WebApi { EntityService = (c, p) => { + if (dbType == DbType.PostgreSQL && p.IsPrimarykey && p.IsIdentity) + p.IsIdentity = true; + p.OracleSequenceName = $"seq_{c.Name.ToLower()}"; if (dbType == DbType.Oracle && p.IsPrimarykey && p.IsIdentity) p.OracleSequenceName = "SEQ_" + c.Name; } @@ -182,38 +210,119 @@ namespace EOM.TSHotelManagement.WebApi var entityBuilder = new EntityBuilder(); var entitiesToAdd = new List(); - foreach (var entityData in entityBuilder.GetEntityDatas()) + var sortedEntities = entityBuilder.GetEntityDatas() + .OrderBy(entity => entity switch + { + AdministratorType _ => 1, + Department _ => 2, + Position _ => 3, + Nation _ => 4, + Education _ => 5, + PassportType _ => 6, + Menu _ => 7, + NavBar _ => 8, + SystemInformation _ => 9, + PromotionContent _ => 10, + Administrator _ => 11, + Employee _ => 12, + _ => 99 + }) + .ToList(); + + Console.WriteLine($"Total entities to process: {sortedEntities.Count}"); + + foreach (var entityData in sortedEntities) { - switch (entityData) + Console.WriteLine($"Processing entity: {entityData.GetType().Name}"); + + try { - case Menu menu when db.Queryable().Any(a => a.Key == menu.Key): - continue; + bool alreadyExists = false; - case Administrator admin when db.Queryable().Any(a => admin.Account == admin.Account): - continue; + switch (entityData) + { + case Menu menu: + alreadyExists = db.Queryable().Any(a => a.Key == menu.Key); + break; - case AdministratorType adminType when db.Queryable().Any(a => adminType.TypeName == adminType.TypeName): - continue; + case Administrator admin: + alreadyExists = db.Queryable().Any(a => a.Account == admin.Account); + break; - case NavBar navBar when db.Queryable().Any(a => navBar.NavigationBarName == navBar.NavigationBarName): - continue; + case AdministratorType adminType: + alreadyExists = db.Queryable().Any(a => a.TypeName == adminType.TypeName); + break; - case PromotionContent promoContent when db.Queryable().Any(a => promoContent.PromotionContentMessage == promoContent.PromotionContentMessage): - continue; + case NavBar navBar: + alreadyExists = db.Queryable().Any(a => a.NavigationBarName == navBar.NavigationBarName); + break; + + case PromotionContent promoContent: + alreadyExists = db.Queryable().Any(a => a.PromotionContentMessage == promoContent.PromotionContentMessage); + break; + + case SystemInformation sysInfo: + alreadyExists = db.Queryable().Any(a => a.UrlAddress == sysInfo.UrlAddress); + break; + + case Nation nation: + alreadyExists = db.Queryable().Any(a => a.NationName == nation.NationName); + break; + + case Department department: + alreadyExists = db.Queryable().Any(a => a.DepartmentNumber == department.DepartmentNumber); + break; + + case Position position: + alreadyExists = db.Queryable().Any(a => a.PositionName == position.PositionName); + break; - case SystemInformation sysInfo when db.Queryable().Any(a => sysInfo.UrlNumber == sysInfo.UrlNumber): + case Education education: + alreadyExists = db.Queryable().Any(a => a.EducationName == education.EducationName); + break; + + case PassportType passportType: + alreadyExists = db.Queryable().Any(a => a.PassportName == passportType.PassportName); + break; + + case Employee employee: + alreadyExists = db.Queryable().Any(a => a.EmployeeId == employee.EmployeeId); + break; + } + + if (alreadyExists) + { + Console.WriteLine($"{entityData.GetType().Name} already exists, skipping."); continue; + } + } + catch (Exception ex) + { + Console.WriteLine($"Error checking existence for {entityData.GetType().Name}: {ex.Message}"); + throw; } + entitiesToAdd.Add(entityData); } if (entitiesToAdd.Count > 0) { - foreach (var data in entitiesToAdd) + Console.WriteLine($"Adding {entitiesToAdd.Count} initial data records"); + + var groupedEntities = entitiesToAdd + .GroupBy(e => e.GetType()) + .ToList(); + + foreach (var group in groupedEntities) { - db.InsertableByObject(data).ExecuteCommand(); + Console.WriteLine($"Inserting {group.Count()} records of type {group.Key.Name}"); + + var list = group.ToList(); + + db.InsertableByObject(list).ExecuteCommand(); } - Console.WriteLine($"Adding {entitiesToAdd.Count} initial data records"); + + Console.WriteLine("Data inserted successfully"); } else { @@ -223,12 +332,21 @@ namespace EOM.TSHotelManagement.WebApi catch (Exception ex) { Console.WriteLine($"Database data initialization failed: {ex.Message}"); + Console.WriteLine($"StackTrace: {ex.StackTrace}"); + + if (ex.InnerException != null) + { + Console.WriteLine($"Inner Exception: {ex.InnerException.Message}"); + Console.WriteLine($"Inner StackTrace: {ex.InnerException.StackTrace}"); + } + throw; } finally { Console.WriteLine("Database data initialization completed"); - Console.WriteLine($"administrator account:admin\nadministrator password:admin"); + Console.WriteLine($"administrator account:admin"); + Console.WriteLine($"administrator password:admin"); } } #endregion -- Gitee