Second upload
This commit is contained in:
parent
7be4c0a162
commit
1d91254c61
|
@ -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<IActionResult> 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<Yuntech_parking> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
329
WebApi_data_value/Controllers/ParkingLogsController.cs
Normal file
329
WebApi_data_value/Controllers/ParkingLogsController.cs
Normal file
|
@ -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<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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<object>();
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
WebApi_data_value/Models/ParkingLog.cs
Normal file
29
WebApi_data_value/Models/ParkingLog.cs
Normal file
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,14 +10,18 @@ using System.Text;
|
||||||
using Parking_space_WebAPI.Authorization;
|
using Parking_space_WebAPI.Authorization;
|
||||||
using Parking_space_WebAPI.Helpers;
|
using Parking_space_WebAPI.Helpers;
|
||||||
using Parking_space_WebAPI.Services;
|
using Parking_space_WebAPI.Services;
|
||||||
|
using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;
|
||||||
|
using Parking_space_WebAPI.BackgroundServices;
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
//在 ASP.NET Core 中啟用 CORS (跨原始來源要求)
|
//在 ASP.NET Core 中啟用 CORS (跨原始來源要求)
|
||||||
builder.Services.AddCors();
|
builder.Services.AddCors();
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
// 註冊 ExcelGenerationService 為 HostedService
|
//執行每日存取剩餘車位
|
||||||
builder.Services.AddHostedService<ExcelGenerationService>(); // 如果不要自動保存就不要加
|
builder.Services.AddScoped<ExcelGenerationService>(); // ExcelGenerationService 註冊為 Scoped
|
||||||
|
builder.Services.AddHostedService<DailyExcelGenerationService>(); // DailyExcelGenerationService 註冊為 HostedService
|
||||||
|
|
||||||
|
|
||||||
// 註冊 BackgroundService
|
// 註冊 BackgroundService
|
||||||
builder.Services.AddHostedService<ParkingUpdateService>(); //執行每一分鐘更新剩餘車位
|
builder.Services.AddHostedService<ParkingUpdateService>(); //執行每一分鐘更新剩餘車位
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Parking_space_WebAPI.Services;
|
using Parking_space_WebAPI.Services;
|
||||||
|
using WebApi_data_value.Models;
|
||||||
|
// 執行計算剩餘車位並不為負數存入資料庫ParkingLogs
|
||||||
public class ParkingUpdateService : BackgroundService
|
public class ParkingUpdateService : BackgroundService
|
||||||
{
|
{
|
||||||
private readonly IServiceScopeFactory _scopeFactory;
|
private readonly IServiceScopeFactory _scopeFactory;
|
||||||
|
@ -25,14 +27,13 @@ public class ParkingUpdateService : BackgroundService
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
var yuntech_parking = await _context.yuntech_parking.FirstOrDefaultAsync();
|
var yuntech_parking = await _context.yuntech_parking.FirstOrDefaultAsync();
|
||||||
if (yuntech_parking != null)
|
if (yuntech_parking != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Int32.TryParse(yuntech_parking.all_num, out int totalParkingSpaces))
|
if (Int32.TryParse(yuntech_parking.all_num, out int totalParkingSpaces))
|
||||||
{
|
{
|
||||||
|
|
||||||
var monthly_rent_data = await _context.yuntech_monthly_rent_number
|
var monthly_rent_data = await _context.yuntech_monthly_rent_number
|
||||||
.FirstOrDefaultAsync(rent => rent.category == "月租");
|
.FirstOrDefaultAsync(rent => rent.category == "月租");
|
||||||
int monthlyRentNumber = 0;
|
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;
|
int remainingSpaces = totalParkingSpaces - totalOccupiedSpaces;
|
||||||
|
|
||||||
// 確保剩餘車位數不為負數
|
// 確保剩餘車位數不為負數
|
||||||
yuntech_parking.now_num = Math.Max(remainingSpaces, 0).ToString();
|
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();
|
await _context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// 錯誤處理,這裡可以記錄錯誤或進行其他處理
|
// 錯誤顯示
|
||||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
Console.WriteLine($"An error occurred: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每 60 秒執行一次
|
// 每分鐘執行一次
|
||||||
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
|
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,92 +1,87 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using ClosedXML.Excel;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using OfficeOpenXml;
|
|
||||||
using WebApi_data_value.Models;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Parking_space_WebAPI.Models;
|
||||||
|
|
||||||
namespace Parking_space_WebAPI.Services
|
namespace Parking_space_WebAPI.Services
|
||||||
{
|
{
|
||||||
public class ExcelGenerationService : BackgroundService
|
public class ExcelGenerationService
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly SqlContext _context;
|
||||||
private readonly string _saveDirectory = @"C:\Users\ste92\Desktop\parking-e\excel"; // 指定儲存 Excel 的資料夾
|
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)
|
DateTime today = DateTime.Today;
|
||||||
{
|
|
||||||
await GenerateAndSaveExcel();
|
|
||||||
await Task.Delay(TimeSpan.FromHours(1), stoppingToken); // 每小時執行一次
|
|
||||||
//await Task.Delay(TimeSpan.FromMinutes(2), stoppingToken); // 每 2 分鐘執行一次
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GenerateAndSaveExcel()
|
// 查詢當天的停車紀錄,按小時分組
|
||||||
{
|
var parkingLogs = await _context.ParkingLogs
|
||||||
using (var scope = _serviceProvider.CreateScope())
|
.Where(p => p.Timestamp.Date == today)
|
||||||
{
|
.GroupBy(p => new { p.Timestamp.Year, p.Timestamp.Month, p.Timestamp.Day, p.Timestamp.Hour })
|
||||||
var _context = scope.ServiceProvider.GetRequiredService<SqlContext>();
|
.Select(g => new
|
||||||
|
|
||||||
// 從資料庫讀取數據
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
// 生成 Excel 文件
|
Timestamp = new DateTime(g.Key.Year, g.Key.Month, g.Key.Day, g.Key.Hour, 0, 0),
|
||||||
var fileBytes = GenerateExcel(parkingSpaces, monthlyRent, temporaryParking);
|
TotalParkingSpaces = g.First().TotalParkingSpaces, // 取每小時第一筆的總車位
|
||||||
|
RemainingSpaces = g.First().RemainingSpaces, // 取每小時第一筆的剩餘車位
|
||||||
|
MonthlyRentSpaces = g.First().MonthlyRentSpaces, // 取每小時第一筆的月租車位
|
||||||
|
TemporaryRentSpaces = g.First().TemporaryRentSpaces // 取每小時第一筆的臨停車位
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
// 文件名帶上當前時間
|
if (parkingLogs.Count == 0)
|
||||||
var fileName = $"ParkingSpaces_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
|
|
||||||
var filePath = Path.Combine(_saveDirectory, fileName);
|
|
||||||
|
|
||||||
// 保存文件
|
|
||||||
await File.WriteAllBytesAsync(filePath, fileBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GenerateExcel(IEnumerable<Yuntech_parking> 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[row, 1].Value = item.all_num;
|
// 如果當天沒有紀錄,可以選擇不生成檔案或進行其他處理
|
||||||
worksheet.Cells[row, 2].Value = item.now_num;
|
return;
|
||||||
row++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加月租車與臨停車數據
|
using (var workbook = new XLWorkbook())
|
||||||
worksheet.Cells[2, 3].Value = monthlyRent.number;
|
{
|
||||||
worksheet.Cells[2, 4].Value = temporaryParking.number;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
70
WebApi_data_value/Services/IHostedService.cs
Normal file
70
WebApi_data_value/Services/IHostedService.cs
Normal file
|
@ -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<DailyExcelGenerationService> _logger;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private Timer _timer;
|
||||||
|
|
||||||
|
public DailyExcelGenerationService(ILogger<DailyExcelGenerationService> 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<ExcelGenerationService>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,6 +64,9 @@ namespace Parking_space_WebAPI.Services
|
||||||
//EL125車輛
|
//EL125車輛
|
||||||
public DbSet<El125_car_table> el125_car_table { get; set; } = null!;
|
public DbSet<El125_car_table> el125_car_table { get; set; } = null!;
|
||||||
|
|
||||||
|
// 新的剩餘車位與時間
|
||||||
|
public DbSet<ParkingLog> ParkingLogs { get; set; } = null!;
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder builder)
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(builder);
|
base.OnModelCreating(builder);
|
||||||
|
@ -100,6 +103,9 @@ namespace Parking_space_WebAPI.Services
|
||||||
builder.Entity<Yuntech_parking_user_list>().HasKey(o => new { o.user_license_plate_number });//Primary Key
|
builder.Entity<Yuntech_parking_user_list>().HasKey(o => new { o.user_license_plate_number });//Primary Key
|
||||||
|
|
||||||
builder.Entity<El125_car_table>().HasKey(o => new { o.license_plate_number });//Primary Key
|
builder.Entity<El125_car_table>().HasKey(o => new { o.license_plate_number });//Primary Key
|
||||||
|
builder.Entity<ParkingLog>().HasKey(o => new { o.Id }); // 設定 ParkingLog 的主鍵
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ClosedXML" Version="0.102.3" />
|
||||||
<PackageReference Include="Emgu.CV" Version="4.8.0.5324" />
|
<PackageReference Include="Emgu.CV" Version="4.8.0.5324" />
|
||||||
<PackageReference Include="EPPlus" Version="4.5.3.3" />
|
<PackageReference Include="EPPlus" Version="4.5.3.3" />
|
||||||
<PackageReference Include="FFmpeg.AutoGen" Version="6.0.0.2" />
|
<PackageReference Include="FFmpeg.AutoGen" Version="6.0.0.2" />
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
//連接MYSQL
|
//連接MYSQL 用不到現在都存取在PgSQL
|
||||||
|
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"tarefasConnection": "server=140.125.21.65;port=3307;uid=leo;pwd=@Leo890808;database=leo"
|
"tarefasConnection": "server=140.125.21.65;port=3307;uid=leo;pwd=@Leo890808;database=leo"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user