From 1d91254c61e5384bfe0ae90af244dd39bb2807d4 Mon Sep 17 00:00:00 2001 From: qi_0527 Date: Tue, 1 Oct 2024 02:30:08 +0800 Subject: [PATCH] Second upload --- .../Controllers/ExcelControlle.cs | 84 ----- .../Controllers/ParkingLogsController.cs | 329 ++++++++++++++++++ WebApi_data_value/Models/ParkingLog.cs | 29 ++ WebApi_data_value/Program.cs | 8 +- .../Services/BackgroundService.cs | 30 +- .../Services/ExcelGenerationService.cs | 131 ++++--- WebApi_data_value/Services/IHostedService.cs | 70 ++++ WebApi_data_value/Services/SqlContext.cs | 6 + WebApi_data_value/WebApi_data_value.csproj | 1 + WebApi_data_value/appsettings.json | 2 +- 10 files changed, 528 insertions(+), 162 deletions(-) delete mode 100644 WebApi_data_value/Controllers/ExcelControlle.cs create mode 100644 WebApi_data_value/Controllers/ParkingLogsController.cs create mode 100644 WebApi_data_value/Models/ParkingLog.cs create mode 100644 WebApi_data_value/Services/IHostedService.cs diff --git a/WebApi_data_value/Controllers/ExcelControlle.cs b/WebApi_data_value/Controllers/ExcelControlle.cs deleted file mode 100644 index 929e66b..0000000 --- a/WebApi_data_value/Controllers/ExcelControlle.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using OfficeOpenXml; // 引入 EPPlus 套件 -using WebApi_data_value.Models; // 更新為正確的命名空間 -using Microsoft.EntityFrameworkCore; -using Parking_space_WebAPI.Services; - -namespace WebApi_data_value.Controllers -{ - [Route("api/[controller]")] - [ApiController] - public class ExcelController : ControllerBase - { - private readonly SqlContext _context; - - public ExcelController(SqlContext context) - { - _context = context; - } - - // GET: api/Excel/Download - [HttpGet("Download")] - public async Task DownloadExcel() - { - // 從資料庫中讀取 yuntech_parking 表的數據 - var parkingSpaces = await _context.yuntech_parking.ToListAsync(); - - if (parkingSpaces == null || !parkingSpaces.Any()) - { - return NotFound("No parking spaces data found."); - } - - // 從資料庫中讀取月租車與臨停車的數據 - var monthlyRent = await _context.yuntech_monthly_rent_number - .FirstOrDefaultAsync(x => x.category == "月租"); - var temporaryParking = await _context.yuntech_monthly_rent_number - .FirstOrDefaultAsync(x => x.category == "臨停"); - - if (monthlyRent == null || temporaryParking == null) - { - return NotFound("No data found for monthly rent or temporary parking."); - } - - var file = GenerateExcel(parkingSpaces, monthlyRent, temporaryParking); - var fileName = $"ParkingSpaces_{DateTime.Now:yyyyMMddHHmmss}.xlsx"; - return File(file, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName); - } - - private byte[] GenerateExcel(IEnumerable parkingData, Yuntech_monthly_rent_number monthlyRent, Yuntech_monthly_rent_number temporaryParking) - { - using var package = new ExcelPackage(); - var worksheet = package.Workbook.Worksheets.Add("Yuntech Parking"); - - // 設定標題 - worksheet.Cells[1, 1].Value = "總車位"; - worksheet.Cells[1, 2].Value = "剩餘車位"; - worksheet.Cells[1, 3].Value = "月租車數量"; - worksheet.Cells[1, 4].Value = "臨停數量"; - - // 添加下載時間 - worksheet.Cells[1, 6].Value = "下載時間"; - worksheet.Cells[2, 6].Value = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); - - var row = 2; - - // 添加每一行的數據 - foreach (var item in parkingData) - { - worksheet.Cells[2, 1].Value = item.all_num; - worksheet.Cells[2, 2].Value = item.now_num; - row++; - } - - // 添加月租車與臨停車的數據 - worksheet.Cells[2, 3].Value = monthlyRent.number; - worksheet.Cells[2, 4].Value = temporaryParking.number; - - return package.GetAsByteArray(); - } - } -} diff --git a/WebApi_data_value/Controllers/ParkingLogsController.cs b/WebApi_data_value/Controllers/ParkingLogsController.cs new file mode 100644 index 0000000..0c861bd --- /dev/null +++ b/WebApi_data_value/Controllers/ParkingLogsController.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using ClosedXML.Excel; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Parking_space_WebAPI.Services; +using WebApi_data_value.Models; + +namespace WebApi_data_value.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ParkingLogsController : ControllerBase + { + private readonly SqlContext _context; + + public ParkingLogsController(SqlContext context) + { + _context = context; + } + + // 新增停車紀錄 + [HttpPost] + public async Task AddParkingLog([FromBody] ParkingLog parkingLog) + { + // 確認模型有效 + if (!ModelState.IsValid) + { + return BadRequest(new { message = "請求的模型無效。" }); + } + + + _context.ParkingLogs.Add(parkingLog); + + // 儲存變更到資料庫 + await _context.SaveChangesAsync(); + + + return CreatedAtAction(nameof(GetParkingLogById), new { id = parkingLog.Id }, parkingLog); + } + + // 根據 ID 獲取停車紀錄 + [HttpGet("{id}")] + public async Task GetParkingLogById(int id) + { + var parkingLog = await _context.ParkingLogs.FindAsync(id); + if (parkingLog == null) + { + return NotFound(new { message = "找不到該停車紀錄。" }); + } + + return Ok(parkingLog); + } + + // 下載即時車位 Excel 檔案 + [HttpGet("DownloadCurrentStatusExcel")] + public async Task DownloadCurrentStatusExcel() + { + + DateTime currentTime = DateTime.Now; + + + var parkingLog = await _context.ParkingLogs + .OrderByDescending(p => p.Timestamp) + .FirstOrDefaultAsync(p => p.Timestamp <= currentTime); + + if (parkingLog == null) + { + return NotFound(new { message = "找不到即時車位資料。" }); + } + + using (var workbook = new XLWorkbook()) + { + var worksheet = workbook.Worksheets.Add("即時車位資訊"); + worksheet.Cell(1, 1).Value = "時間"; + worksheet.Cell(1, 2).Value = "星期"; + worksheet.Cell(1, 3).Value = "總車位"; + worksheet.Cell(1, 4).Value = "剩餘車位"; + worksheet.Cell(1, 5).Value = "月租車位"; + worksheet.Cell(1, 6).Value = "臨停車位"; + worksheet.Cell(1, 7).Value = "下載日期"; + + + worksheet.Cell(2, 1).Value = parkingLog.Timestamp.ToString("yyyy/MM/dd HH:mm:ss"); + worksheet.Cell(2, 2).Value = DateTime.Now.ToString("dddd", new CultureInfo("zh-TW")); + worksheet.Cell(2, 3).Value = parkingLog.TotalParkingSpaces; + worksheet.Cell(2, 4).Value = parkingLog.RemainingSpaces; + worksheet.Cell(2, 5).Value = parkingLog.MonthlyRentSpaces; + worksheet.Cell(2, 6).Value = parkingLog.TemporaryRentSpaces; + worksheet.Cell(2, 7).Value = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss dddd"); + + // 設定欄位寬度 + worksheet.Column(1).Width = 25; + worksheet.Column(2).Width = 10; + worksheet.Column(3).Width = 15; + worksheet.Column(4).Width = 15; + worksheet.Column(5).Width = 15; + worksheet.Column(6).Width = 15; + worksheet.Column(7).Width = 25; + + using (var stream = new MemoryStream()) + { + workbook.SaveAs(stream); + var content = stream.ToArray(); + + // 生成檔案名稱 + string currentDate = DateTime.Now.ToString("yyyy-MM-dd"); + string weekDayDownload = DateTime.Now.ToString("dddd", new CultureInfo("zh-TW")); // 獲取當前星期幾 + + string fileName = $"即時車位-{currentDate}-{weekDayDownload}.xlsx"; + + return File(content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName); + } + } + } + + // 下載 Excel 檔案 + [HttpGet("DownloadExcel")] + public async Task DownloadExcel(DateTime startDate, DateTime endDate, string interval) + { + // 確保日期有效 + if (startDate == default || endDate == default) + { + return BadRequest(new { message = "日期無效。" }); + } + + // 確保開始時間早於結束時間 + if (startDate >= endDate) + { + return BadRequest(new { message = "結束日期必須晚於開始日期。" }); + } + + // 調用 GetHourlyParkingLogs 方法以獲取停車紀錄 + var parkingLogsResult = await GetHourlyParkingLogs(startDate, endDate, interval); + + if (parkingLogsResult is NotFoundResult) + { + return NotFound(new { message = "找不到該日期範圍的停車紀錄。" }); + } + + var logs = (parkingLogsResult as OkObjectResult).Value as dynamic; + var records = logs.logs; // 獲取停車紀錄 + + using (var workbook = new XLWorkbook()) + { + var worksheet = workbook.Worksheets.Add("停車紀錄"); + worksheet.Cell(1, 1).Value = "時間"; + worksheet.Cell(1, 2).Value = "星期"; + worksheet.Cell(1, 3).Value = "總車位"; + worksheet.Cell(1, 4).Value = "剩餘車位"; + worksheet.Cell(1, 5).Value = "月租車位"; + worksheet.Cell(1, 6).Value = "臨停車位"; + worksheet.Cell(1, 7).Value = "下載日期"; + + for (int i = 0; i < records.Count; i++) + { + var log = records[i]; + worksheet.Cell(i + 2, 1).Value = log.Timestamp.ToString("yyyy/MM/dd HH:mm:ss"); + worksheet.Cell(i + 2, 2).Value = log.DayOfWeek; + worksheet.Cell(i + 2, 3).Value = log.TotalParkingSpaces; + worksheet.Cell(i + 2, 4).Value = log.RemainingSpaces; + worksheet.Cell(i + 2, 5).Value = log.MonthlyRentSpaces; + worksheet.Cell(i + 2, 6).Value = log.TemporaryRentSpaces; + worksheet.Cell(2, 7).Value = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss dddd"); + + } + + + worksheet.Column(1).Width = 25; + worksheet.Column(2).Width = 10; + worksheet.Column(3).Width = 15; + worksheet.Column(4).Width = 15; + worksheet.Column(5).Width = 15; + worksheet.Column(6).Width = 15; + worksheet.Column(7).Width = 25; + + using (var stream = new MemoryStream()) + { + workbook.SaveAs(stream); + var content = stream.ToArray(); + + + string currentDate = DateTime.Now.ToString("yyyy-MM-dd"); + string weekDay = DateTime.Now.ToString("dddd", new CultureInfo("zh-TW")); + + string fileName = $"停車紀錄-{currentDate}-{weekDay}.xlsx"; + + return File(content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName); + } + } + } + + + // 獲取停車紀錄 + private async Task GetParkingLogs(DateTime startDate, DateTime endDate, int pageNumber, int pageSize) + { + + if (startDate == default || endDate == default) + { + return BadRequest(new { message = "日期無效。" }); + } + + + if (startDate >= endDate) + { + return BadRequest(new { message = "結束日期必須晚於開始日期。" }); + } + + + var parkingLogs = await _context.ParkingLogs + .AsNoTracking() + .Where(p => p.Timestamp >= startDate && p.Timestamp <= endDate) + .OrderByDescending(p => p.Timestamp) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + if (!parkingLogs.Any()) + { + return NotFound(new { message = "找不到該日期範圍的停車紀錄。" }); + } + + return Ok(new + { + totalRecords = await _context.ParkingLogs.CountAsync(p => p.Timestamp >= startDate && p.Timestamp <= endDate), // 總紀錄數 + records = parkingLogs + }); + } + //獲取前端要查詢的時間 利用interval == "none" 不需要分間格 interval != 分間隔 + [HttpGet("GetHourlyParkingLogs")] + public async Task GetHourlyParkingLogs(DateTime startDate, DateTime endDate, string interval, int page = 1, int recordsPerPage = 20) + { + + if (startDate == default || endDate == default) + { + return BadRequest(new { message = "日期無效。" }); + } + + + if (startDate >= endDate) + { + return BadRequest(new { message = "結束日期必須晚於開始日期。" }); + } + + // 查詢指定時間範圍的停車紀錄 + var parkingLogs = await _context.ParkingLogs + .AsNoTracking() + .Where(p => p.Timestamp >= startDate && p.Timestamp <= endDate) + .ToListAsync(); + + if (!parkingLogs.Any()) + { + return NotFound(new { message = "找不到該日期範圍的停車紀錄。" }); + } + + // 設定時間間隔 + if (interval == "none") + { + + var formattedLogs = parkingLogs.Select(log => new + { + log.Timestamp, + DayOfWeek = log.Timestamp.ToString("dddd", new CultureInfo("zh-TW")), + log.TotalParkingSpaces, + log.RemainingSpaces, + log.MonthlyRentSpaces, + log.TemporaryRentSpaces + }).ToList(); + + + var totalRecords = formattedLogs.Count; + var pagedLogs = formattedLogs.Skip((page - 1) * recordsPerPage).Take(recordsPerPage).ToList(); + + return Ok(new + { + totalRecords = totalRecords, + logs = pagedLogs + }); + } + else + { + // 將 interval 轉換為整數 + int hourInterval = int.Parse(interval); + + // 轉換時間格式為可讀的格式,並獲取每小時的紀錄 + var formattedLogs = new List(); + foreach (var logGroup in parkingLogs.GroupBy(log => new + { + log.Timestamp.Year, + log.Timestamp.Month, + log.Timestamp.Day, + HourGroup = log.Timestamp.Hour / hourInterval + })) + { + formattedLogs.Add(new + { + Timestamp = new DateTime(logGroup.Key.Year, logGroup.Key.Month, logGroup.Key.Day, logGroup.Key.HourGroup * hourInterval, 0, 0), + DayOfWeek = logGroup.First().Timestamp.ToString("dddd", new CultureInfo("zh-TW")), + TotalParkingSpaces = logGroup.First().TotalParkingSpaces, + RemainingSpaces = logGroup.First().RemainingSpaces, + MonthlyRentSpaces = logGroup.First().MonthlyRentSpaces, + TemporaryRentSpaces = logGroup.First().TemporaryRentSpaces + }); + } + + if (!formattedLogs.Any()) + { + return NotFound(new { message = "找不到該日期範圍的整點停車紀錄。" }); + } + + // 分頁處理 + var totalRecords = formattedLogs.Count; + var pagedLogs = formattedLogs.Skip((page - 1) * recordsPerPage).Take(recordsPerPage).ToList(); + + return Ok(new + { + totalRecords = totalRecords, + logs = pagedLogs + }); + } + } + + } + +} diff --git a/WebApi_data_value/Models/ParkingLog.cs b/WebApi_data_value/Models/ParkingLog.cs new file mode 100644 index 0000000..f269503 --- /dev/null +++ b/WebApi_data_value/Models/ParkingLog.cs @@ -0,0 +1,29 @@ + using System.ComponentModel.DataAnnotations; + + namespace WebApi_data_value.Models + { + public class ParkingLog + { + [Key] // 標示主鍵 + public int Id { get; set; } + + [Required] + public DateTime Timestamp { get; set; } // 儲存完整的時間 + + [Required] + public int TotalParkingSpaces { get; set; } // 總車位 + + [Required] + public int RemainingSpaces { get; set; } // 剩餘車位 + + [Required] + public int MonthlyRentSpaces { get; set; } // 月租車位 + + [Required] + public int TemporaryRentSpaces { get; set; } // 臨停車位 + + [Required] + [StringLength(10)] + public string? DayOfWeek { get; set; } + } + } diff --git a/WebApi_data_value/Program.cs b/WebApi_data_value/Program.cs index f048b12..2a2662d 100644 --- a/WebApi_data_value/Program.cs +++ b/WebApi_data_value/Program.cs @@ -10,14 +10,18 @@ using System.Text; using Parking_space_WebAPI.Authorization; using Parking_space_WebAPI.Helpers; using Parking_space_WebAPI.Services; +using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing; +using Parking_space_WebAPI.BackgroundServices; var builder = WebApplication.CreateBuilder(args); //在 ASP.NET Core 中啟用 CORS (跨原始來源要求) builder.Services.AddCors(); // Add services to the container. builder.Services.AddControllers(); -// 註冊 ExcelGenerationService 為 HostedService -builder.Services.AddHostedService(); // 如果不要自動保存就不要加 +//執行每日存取剩餘車位 +builder.Services.AddScoped(); // ExcelGenerationService 註冊為 Scoped +builder.Services.AddHostedService(); // DailyExcelGenerationService 註冊為 HostedService + // 註冊 BackgroundService builder.Services.AddHostedService(); //執行每一分鐘更新剩餘車位 diff --git a/WebApi_data_value/Services/BackgroundService.cs b/WebApi_data_value/Services/BackgroundService.cs index 3334078..5489451 100644 --- a/WebApi_data_value/Services/BackgroundService.cs +++ b/WebApi_data_value/Services/BackgroundService.cs @@ -2,10 +2,12 @@ using Microsoft.Extensions.Hosting; using Microsoft.EntityFrameworkCore; using System; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using Parking_space_WebAPI.Services; - +using WebApi_data_value.Models; +// 執行計算剩餘車位並不為負數存入資料庫ParkingLogs public class ParkingUpdateService : BackgroundService { private readonly IServiceScopeFactory _scopeFactory; @@ -25,14 +27,13 @@ public class ParkingUpdateService : BackgroundService try { - var yuntech_parking = await _context.yuntech_parking.FirstOrDefaultAsync(); if (yuntech_parking != null) { if (Int32.TryParse(yuntech_parking.all_num, out int totalParkingSpaces)) { - + var monthly_rent_data = await _context.yuntech_monthly_rent_number .FirstOrDefaultAsync(rent => rent.category == "月租"); int monthlyRentNumber = 0; @@ -51,25 +52,40 @@ public class ParkingUpdateService : BackgroundService } - int totalOccupiedSpaces = monthlyRentNumber + Math.Abs(temporaryRentNumber); // 確保臨停車位數為絕對值 + int totalOccupiedSpaces = monthlyRentNumber + Math.Abs(temporaryRentNumber); //確保絕對值 int remainingSpaces = totalParkingSpaces - totalOccupiedSpaces; // 確保剩餘車位數不為負數 yuntech_parking.now_num = Math.Max(remainingSpaces, 0).ToString(); - // 保存更改 + + await _context.SaveChangesAsync(); + + + var log = new ParkingLog + { + Timestamp = DateTime.Now, + TotalParkingSpaces = totalParkingSpaces, + RemainingSpaces = remainingSpaces, + MonthlyRentSpaces = monthlyRentNumber, + TemporaryRentSpaces = Math.Abs(temporaryRentNumber), + DayOfWeek = DateTime.Now.ToString("dddd", new CultureInfo("zh-TW")) + }; + + // 儲存資料庫ParkingLogs + _context.ParkingLogs.Add(log); await _context.SaveChangesAsync(); } } } catch (Exception ex) { - // 錯誤處理,這裡可以記錄錯誤或進行其他處理 + // 錯誤顯示 Console.WriteLine($"An error occurred: {ex.Message}"); } } - // 每 60 秒執行一次 + // 每分鐘執行一次 await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); } } diff --git a/WebApi_data_value/Services/ExcelGenerationService.cs b/WebApi_data_value/Services/ExcelGenerationService.cs index fa7c6ca..a9ef829 100644 --- a/WebApi_data_value/Services/ExcelGenerationService.cs +++ b/WebApi_data_value/Services/ExcelGenerationService.cs @@ -1,92 +1,87 @@ using System; +using System.Globalization; using System.IO; using System.Linq; -using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using OfficeOpenXml; -using WebApi_data_value.Models; +using ClosedXML.Excel; using Microsoft.EntityFrameworkCore; +using Parking_space_WebAPI.Models; namespace Parking_space_WebAPI.Services { - public class ExcelGenerationService : BackgroundService + public class ExcelGenerationService { - private readonly IServiceProvider _serviceProvider; - private readonly string _saveDirectory = @"C:\Users\ste92\Desktop\parking-e\excel"; // 指定儲存 Excel 的資料夾 + private readonly SqlContext _context; + private readonly string _excelDirectory; - public ExcelGenerationService(IServiceProvider serviceProvider) + public ExcelGenerationService(SqlContext context) { - _serviceProvider = serviceProvider; + _context = context; + _excelDirectory = @"C:\Users\ste92\Desktop\parking-e\excel"; // 設定 Excel 檔案存儲路徑 } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + public async Task GenerateDailyExcel() { - while (!stoppingToken.IsCancellationRequested) - { - await GenerateAndSaveExcel(); - await Task.Delay(TimeSpan.FromHours(1), stoppingToken); // 每小時執行一次 - //await Task.Delay(TimeSpan.FromMinutes(2), stoppingToken); // 每 2 分鐘執行一次 - } - } + DateTime today = DateTime.Today; - private async Task GenerateAndSaveExcel() - { - using (var scope = _serviceProvider.CreateScope()) - { - var _context = scope.ServiceProvider.GetRequiredService(); - - // 從資料庫讀取數據 - var parkingSpaces = await _context.yuntech_parking.ToListAsync(); - var monthlyRent = await _context.yuntech_monthly_rent_number - .FirstOrDefaultAsync(x => x.category == "月租"); - var temporaryParking = await _context.yuntech_monthly_rent_number - .FirstOrDefaultAsync(x => x.category == "臨停"); - - if (parkingSpaces != null && monthlyRent != null && temporaryParking != null) + // 查詢當天的停車紀錄,按小時分組 + var parkingLogs = await _context.ParkingLogs + .Where(p => p.Timestamp.Date == today) + .GroupBy(p => new { p.Timestamp.Year, p.Timestamp.Month, p.Timestamp.Day, p.Timestamp.Hour }) + .Select(g => new { - // 生成 Excel 文件 - var fileBytes = GenerateExcel(parkingSpaces, monthlyRent, temporaryParking); + Timestamp = new DateTime(g.Key.Year, g.Key.Month, g.Key.Day, g.Key.Hour, 0, 0), + TotalParkingSpaces = g.First().TotalParkingSpaces, // 取每小時第一筆的總車位 + RemainingSpaces = g.First().RemainingSpaces, // 取每小時第一筆的剩餘車位 + MonthlyRentSpaces = g.First().MonthlyRentSpaces, // 取每小時第一筆的月租車位 + TemporaryRentSpaces = g.First().TemporaryRentSpaces // 取每小時第一筆的臨停車位 + }) + .ToListAsync(); - // 文件名帶上當前時間 - var fileName = $"ParkingSpaces_{DateTime.Now:yyyyMMddHHmmss}.xlsx"; - var filePath = Path.Combine(_saveDirectory, fileName); - - // 保存文件 - await File.WriteAllBytesAsync(filePath, fileBytes); - } - } - } - - private byte[] GenerateExcel(IEnumerable parkingData, Yuntech_monthly_rent_number monthlyRent, Yuntech_monthly_rent_number temporaryParking) - { - using var package = new ExcelPackage(); - var worksheet = package.Workbook.Worksheets.Add("Yuntech Parking"); - - // 設定標題 - worksheet.Cells[1, 1].Value = "總車位"; - worksheet.Cells[1, 2].Value = "剩餘車位"; - worksheet.Cells[1, 3].Value = "月租車數量"; - worksheet.Cells[1, 4].Value = "臨停數量"; - - // 添加下載時間 - worksheet.Cells[1, 6].Value = "下載時間"; - worksheet.Cells[2, 6].Value = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); - - var row = 2; - foreach (var item in parkingData) + if (parkingLogs.Count == 0) { - worksheet.Cells[row, 1].Value = item.all_num; - worksheet.Cells[row, 2].Value = item.now_num; - row++; + // 如果當天沒有紀錄,可以選擇不生成檔案或進行其他處理 + return; } - // 添加月租車與臨停車數據 - worksheet.Cells[2, 3].Value = monthlyRent.number; - worksheet.Cells[2, 4].Value = temporaryParking.number; + using (var workbook = new XLWorkbook()) + { + var worksheet = workbook.Worksheets.Add("當天停車紀錄"); + worksheet.Cell(1, 1).Value = "時間"; + worksheet.Cell(1, 2).Value = "總車位"; + worksheet.Cell(1, 3).Value = "剩餘車位"; + worksheet.Cell(1, 4).Value = "月租車位"; + worksheet.Cell(1, 5).Value = "臨停車位"; + worksheet.Cell(1, 6).Value = "生成日期"; + worksheet.Cell(2, 6).Value = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss dddd"); // 填入當前生成時間 - return package.GetAsByteArray(); + for (int i = 0; i < parkingLogs.Count; i++) + { + var log = parkingLogs[i]; + worksheet.Cell(i + 2, 1).Value = log.Timestamp.ToString("yyyy/MM/dd HH:mm:ss"); + worksheet.Cell(i + 2, 2).Value = log.TotalParkingSpaces; + worksheet.Cell(i + 2, 3).Value = log.RemainingSpaces; + worksheet.Cell(i + 2, 4).Value = log.MonthlyRentSpaces; + worksheet.Cell(i + 2, 5).Value = log.TemporaryRentSpaces; + } + + // 設定欄位寬度 + worksheet.Column(1).Width = 25; + worksheet.Column(2).Width = 15; + worksheet.Column(3).Width = 15; + worksheet.Column(4).Width = 15; + worksheet.Column(5).Width = 15; + worksheet.Column(6).Width = 25; + + // 生成檔案名稱 + string fileName = $"整天車位數-{today:yyyy-MM-dd-dddd}.xlsx"; + + // 儲存檔案 + var filePath = Path.Combine(_excelDirectory, fileName); + workbook.SaveAs(filePath); + } } + + } } diff --git a/WebApi_data_value/Services/IHostedService.cs b/WebApi_data_value/Services/IHostedService.cs new file mode 100644 index 0000000..5d10376 --- /dev/null +++ b/WebApi_data_value/Services/IHostedService.cs @@ -0,0 +1,70 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Parking_space_WebAPI.Services; + +// 讓ExcelGenerationService執行每日固定存取 +namespace Parking_space_WebAPI.BackgroundServices +{ + public class DailyExcelGenerationService : IHostedService, IDisposable + { + private readonly ILogger _logger; + private readonly IServiceProvider _serviceProvider; + private Timer _timer; + + public DailyExcelGenerationService(ILogger logger, IServiceProvider serviceProvider) + { + _logger = logger; + _serviceProvider = serviceProvider; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + TimeSpan scheduledTime = new TimeSpan(23, 59, 0); //設定固定每天存取的時間 + var now = DateTime.Now; + var nextRunTime = DateTime.Today.Add(scheduledTime); + + if (now > nextRunTime) + { + nextRunTime = nextRunTime.AddDays(1); + } + + var timeToGo = nextRunTime - now; + + _timer = new Timer(GenerateExcel, null, timeToGo, TimeSpan.FromDays(1)); + return Task.CompletedTask; + } + + private async void GenerateExcel(object state) + { + try + { + + using (var scope = _serviceProvider.CreateScope()) + { + var excelGenerationService = scope.ServiceProvider.GetRequiredService(); + await excelGenerationService.GenerateDailyExcel(); + } + _logger.LogInformation("每日 Excel 檔案已生成。"); + } + catch (Exception ex) + { + _logger.LogError(ex, "生成 Excel 檔案時出錯。"); + } + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _timer?.Change(Timeout.Infinite, 0); + return Task.CompletedTask; + } + + public void Dispose() + { + _timer?.Dispose(); + } + } +} diff --git a/WebApi_data_value/Services/SqlContext.cs b/WebApi_data_value/Services/SqlContext.cs index bf71624..12ba06d 100644 --- a/WebApi_data_value/Services/SqlContext.cs +++ b/WebApi_data_value/Services/SqlContext.cs @@ -64,6 +64,9 @@ namespace Parking_space_WebAPI.Services //EL125車輛 public DbSet el125_car_table { get; set; } = null!; + // 新的剩餘車位與時間 + public DbSet ParkingLogs { get; set; } = null!; + protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); @@ -100,6 +103,9 @@ namespace Parking_space_WebAPI.Services builder.Entity().HasKey(o => new { o.user_license_plate_number });//Primary Key builder.Entity().HasKey(o => new { o.license_plate_number });//Primary Key + builder.Entity().HasKey(o => new { o.Id }); // 設定 ParkingLog 的主鍵 + + } diff --git a/WebApi_data_value/WebApi_data_value.csproj b/WebApi_data_value/WebApi_data_value.csproj index ce43b17..0ad6634 100644 --- a/WebApi_data_value/WebApi_data_value.csproj +++ b/WebApi_data_value/WebApi_data_value.csproj @@ -19,6 +19,7 @@ + diff --git a/WebApi_data_value/appsettings.json b/WebApi_data_value/appsettings.json index 5945ca0..e09354c 100644 --- a/WebApi_data_value/appsettings.json +++ b/WebApi_data_value/appsettings.json @@ -10,7 +10,7 @@ }, "AllowedHosts": "*", - //連接MYSQL + //連接MYSQL 用不到現在都存取在PgSQL "ConnectionStrings": { "tarefasConnection": "server=140.125.21.65;port=3307;uid=leo;pwd=@Leo890808;database=leo"