Kaynağa Gözat

報表調整

master
MSI\User 1 ay önce
ebeveyn
işleme
aa9d3b3329
5 değiştirilmiş dosya ile 183 ekleme ve 90 silme
  1. +6
    -0
      Controllers/HomeController.cs
  2. +144
    -77
      Controllers/ReportController.cs
  3. +3
    -1
      Program.cs
  4. +18
    -11
      Views/Report/Index.cshtml
  5. +12
    -1
      Views/Shared/_Layout.cshtml

+ 6
- 0
Controllers/HomeController.cs Dosyayı Görüntüle

@@ -27,6 +27,12 @@ public class HomeController : Controller
}
public IActionResult Index()
{
//如果已經登入,直接導向報表頁面
if (User.Identity?.IsAuthenticated == true)
{
return RedirectToAction("Index", "Report");
}

ViewBag.OauthUrl = _oauthOption.Value.ParkingOAuthUrl;
return View(new LoginViewModel());
}


+ 144
- 77
Controllers/ReportController.cs Dosyayı Görüntüle

@@ -52,11 +52,11 @@ public class ReportController : Controller

private async Task<IActionResult> LoadReportData(DateTime? startDate, DateTime? endDate)
{
var query = _couponContext.Logs.AsQueryable().Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功"));
var serialNo = query.GroupBy(x => x.SerialNo).Select(g => g.Key).ToList();
var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList();
// 建立包含日期篩選的查詢
var query = _couponContext.Logs.AsQueryable()
.Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功"));

if (startDate.HasValue)
if (startDate.HasValue)
{
query = query.Where(x => x.LogTime >= startDate.Value);
}
@@ -66,21 +66,30 @@ public class ReportController : Controller
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1));
}

var logs = await query.OrderBy(x => x.LogTime).ToListAsync();
var consumeLogs = await query.OrderBy(x => x.LogTime).ToListAsync();
var serialNo = consumeLogs.Select(x => x.SerialNo).Distinct().ToList();

var evaluateLogsQuery = await _couponContext.Logs
.Where(x => serialNo.Contains(x.SerialNo) && x.LogType == "Evaluate" && x.LogInfo.Contains("評估成功"))
.ToListAsync();

// 建立 SerialNo 到 Evaluate Log 的映射
var evaluateLogDict = evaluateLogsQuery
.GroupBy(x => x.SerialNo)
.ToDictionary(g => g.Key, g => g.FirstOrDefault());

//var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList();
//var carEnter = _mySqlContext.Cario.Where(x => serialNo.Contains(x.SerialNo)).ToList();

// 建立 SerialNo 到編號的映射
var serialNoToRowNumber = new Dictionary<string, int>();
int currentRowNumber = 1;

// 建立 SerialNo 到 CarEnter 的映射,方便快速查找
var carEnterDict = carEnter.GroupBy(x => x.SerialNo)
.ToDictionary(g => g.Key, g => g.FirstOrDefault());
//var carEnterDict = carEnter.GroupBy(x => x.SerialNo)
// .ToDictionary(g => g.Key, g => g.FirstOrDefault());

var viewModel = new CouponReportViewModel
{
StartDate = startDate,
EndDate = endDate,
ReportItems = logs.Select(log =>
var reportItems = consumeLogs.Select(log =>
{
// 如果這個 SerialNo 還沒出現過,給它一個新編號
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo))
@@ -88,17 +97,22 @@ public class ReportController : Controller
serialNoToRowNumber[log.SerialNo] = currentRowNumber++;
}

// 從 CarEnter 取得出場時間
// 從 evaluateLogDict 取得出場時間
DateTime? exitTime = null;
if (!string.IsNullOrEmpty(log.SerialNo) && evaluateLogDict.ContainsKey(log.SerialNo))
{
exitTime = evaluateLogDict[log.SerialNo]?.LogTime;
}

var tenantCode = string.Empty;
DateTime? invoiceDate = null;
var invoiceNo = string.Empty;
var invoiceAmount = 0m;

if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo))
{
exitTime = carEnterDict[log.SerialNo]?.DepartureDateTime;
}
//if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo))
// {
// exitTime = carEnterDict[log.SerialNo]?.OutTime;
// }

invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey);
invoiceNo = _reportService.GetInvoiceNo(log.ExternalSystemKey);
@@ -113,7 +127,7 @@ public class ReportController : Controller
InvoiceDate = invoiceDate,
InvoiceNumber = invoiceNo,
InvoiceAmount = invoiceAmount,
DiscountUnit = "新台幣",
DiscountUnit = "金額",
DiscountAmount = log.DiscountAmount,
DiscountTime = log.LogTime,
EnterTime = log.EnterTime,
@@ -121,7 +135,13 @@ public class ReportController : Controller
ParkingAmount = log.TotalAmount,
ClaimAmount = log.DiscountAmount
};
}).ToList()
}).OrderBy(x => x.RowNumber).ThenBy(x => x.DiscountTime).ToList();

var viewModel = new CouponReportViewModel
{
StartDate = startDate,
EndDate = endDate,
ReportItems = reportItems
};

return View(viewModel);
@@ -129,9 +149,8 @@ public class ReportController : Controller

public async Task<IActionResult> ExportToExcel(DateTime? startDate, DateTime? endDate)
{
var query = _couponContext.Logs.AsQueryable().Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功"));
var serialNo = query.GroupBy(x => x.SerialNo).Select(g => g.Key).ToList();
var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList();
var query = _couponContext.Logs.AsQueryable()
.Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功"));

if (startDate.HasValue)
{
@@ -143,23 +162,29 @@ public class ReportController : Controller
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1));
}

var logs = await query.OrderBy(x => x.LogTime).ToListAsync();
var consumeLogs = await query.OrderBy(x => x.LogTime).ToListAsync();
var serialNo = consumeLogs.Select(x => x.SerialNo).Distinct().ToList();

var evaluateLogsQuery = await _couponContext.Logs
.Where(x => serialNo.Contains(x.SerialNo) && x.LogType == "Evaluate" && x.LogInfo.Contains("評估成功"))
.ToListAsync();

// 建立 SerialNo 到 Evaluate Log 的映射
var evaluateLogDict = evaluateLogsQuery
.GroupBy(x => x.SerialNo)
.ToDictionary(g => g.Key, g => g.FirstOrDefault());

// 建立 SerialNo 到編號的映射
var serialNoToRowNumber = new Dictionary<string, int>();
int currentRowNumber = 1;

// 建立 SerialNo 到 CarEnter 的映射,方便快速查找
var carEnterDict = carEnter.GroupBy(x => x.SerialNo)
.ToDictionary(g => g.Key, g => g.FirstOrDefault());

// 建立報表資料列表
var reportItems = new List<(int rowNumber, string tenantCode, string carNumber, DateTime? invoiceDate,
string invoiceNo, decimal invoiceAmount, string discountUnit, decimal? discountAmount,
DateTime discountTime, DateTime? enterTime, DateTime? exitTime,
decimal? parkingAmount, decimal? claimAmount)>();

foreach (var log in logs)
foreach (var log in consumeLogs)
{
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo))
{
@@ -167,9 +192,9 @@ public class ReportController : Controller
}

DateTime? exitTime = null;
if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo))
if (!string.IsNullOrEmpty(log.SerialNo) && evaluateLogDict.ContainsKey(log.SerialNo))
{
exitTime = carEnterDict[log.SerialNo]?.DepartureDateTime;
exitTime = evaluateLogDict[log.SerialNo]?.LogTime;
}

var invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey);
@@ -180,37 +205,47 @@ public class ReportController : Controller
int rowNumber = !string.IsNullOrEmpty(log.SerialNo) ? serialNoToRowNumber[log.SerialNo] : 0;

reportItems.Add((rowNumber, tenantCode, log.PlateNo, invoiceDate, invoiceNo, invoiceAmount,
"新台幣", log.DiscountAmount, log.LogTime, log.EnterTime, exitTime,
"金額", log.DiscountAmount, log.LogTime, log.EnterTime, exitTime,
log.TotalAmount, log.DiscountAmount));
}

// 按 RowNumber 排序,確保相同編號的資料連續,避免合併儲存格錯誤
reportItems = reportItems.OrderBy(x => x.rowNumber).ThenBy(x => x.discountTime).ToList();

using var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("折扣報表");

// 匯出資訊(合併儲存格以避免影響欄寬)
worksheet.Range(1, 1, 1, 13).Merge();
worksheet.Cell(1, 1).Value = $"匯出時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}";

worksheet.Range(2, 1, 2, 13).Merge();
worksheet.Cell(2, 1).Value = $"篩選條件:{startDate?.ToString("yyyy-MM-dd")} ~ {endDate?.ToString("yyyy-MM-dd")}";

// 標題列
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(1, 8).Value = "折扣金額";
worksheet.Cell(1, 9).Value = "折扣時間";
worksheet.Cell(1, 10).Value = "入場時間";
worksheet.Cell(1, 11).Value = "出場時間";
worksheet.Cell(1, 12).Value = "停車金額";
worksheet.Cell(1, 13).Value = "請款金額";
worksheet.Cell(4, 1).Value = "編號";
worksheet.Cell(4, 2).Value = "店別(統編)";
worksheet.Cell(4, 3).Value = "車號";
worksheet.Cell(4, 4).Value = "發票日期";
worksheet.Cell(4, 5).Value = "發票號碼";
worksheet.Cell(4, 6).Value = "發票金額";
worksheet.Cell(4, 7).Value = "折扣單位";
worksheet.Cell(4, 8).Value = "折扣金額";
worksheet.Cell(4, 9).Value = "折扣時間";
worksheet.Cell(4, 10).Value = "入場時間";
worksheet.Cell(4, 11).Value = "出場時間";
worksheet.Cell(4, 12).Value = "停車金額";
worksheet.Cell(4, 13).Value = "請款金額";

// 設定標題列樣式
var headerRange = worksheet.Range(1, 1, 1, 13);
var headerRange = worksheet.Range(4, 1, 4, 13);
headerRange.Style.Font.Bold = true;
headerRange.Style.Fill.BackgroundColor = XLColor.LightGray;
headerRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
headerRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;

// 填入資料並記錄合併範圍
int row = 2;
int row = 5;
var mergedCells = new Dictionary<int, (int startRow, int endRow)>();

foreach (var item in reportItems)
@@ -219,16 +254,16 @@ public class ReportController : Controller
worksheet.Cell(row, 1).Value = item.rowNumber;
worksheet.Cell(row, 2).Value = item.tenantCode;
worksheet.Cell(row, 3).Value = item.carNumber;
worksheet.Cell(row, 4).Value = item.invoiceDate?.ToString("yyyy-MM-dd HH:mm:ss");
worksheet.Cell(row, 4).Value = item.invoiceDate?.ToString("yyyy-MM-dd");
worksheet.Cell(row, 5).Value = item.invoiceNo;
worksheet.Cell(row, 6).Value = item.invoiceAmount;
worksheet.Cell(row, 6).Value = $"NT$ {item.invoiceAmount:N0}";
worksheet.Cell(row, 7).Value = item.discountUnit;
worksheet.Cell(row, 8).Value = item.discountAmount;
worksheet.Cell(row, 8).Value = $"NT$ {item.discountAmount:N0}";
worksheet.Cell(row, 9).Value = item.discountTime.ToString("yyyy-MM-dd HH:mm:ss");
worksheet.Cell(row, 10).Value = item.enterTime?.ToString("yyyy-MM-dd HH:mm:ss");
worksheet.Cell(row, 11).Value = item.exitTime?.ToString("yyyy-MM-dd HH:mm:ss");
worksheet.Cell(row, 12).Value = item.parkingAmount;
worksheet.Cell(row, 13).Value = item.claimAmount;
worksheet.Cell(row, 12).Value = $"NT$ {item.parkingAmount:N0}";
worksheet.Cell(row, 13).Value = $"NT$ {item.claimAmount:N0}";

// 記錄需要合併的儲存格範圍(按 rowNumber 分組)
if (item.rowNumber > 0)
@@ -274,7 +309,7 @@ public class ReportController : Controller
}

// 將所有資料儲存格置中
var dataRange = worksheet.Range(2, 1, row - 1, 13);
var dataRange = worksheet.Range(5, 1, row - 1, 13);
dataRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
dataRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;

@@ -288,9 +323,8 @@ public class ReportController : Controller

public async Task<IActionResult> ExportToPdf(DateTime? startDate, DateTime? endDate)
{
var query = _couponContext.Logs.AsQueryable().Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功"));
var serialNo = query.GroupBy(x => x.SerialNo).Select(g => g.Key).ToList();
var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList();
var query = _couponContext.Logs.AsQueryable()
.Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功"));

if (startDate.HasValue)
{
@@ -302,23 +336,29 @@ public class ReportController : Controller
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1));
}

var logs = await query.OrderBy(x => x.LogTime).ToListAsync();
var consumeLogs = await query.OrderBy(x => x.LogTime).ToListAsync();
var serialNo = consumeLogs.Select(x => x.SerialNo).Distinct().ToList();

var evaluateLogsQuery = await _couponContext.Logs
.Where(x => serialNo.Contains(x.SerialNo) && x.LogType == "Evaluate" && x.LogInfo.Contains("評估成功"))
.ToListAsync();

// 建立 SerialNo 到 Evaluate Log 的映射
var evaluateLogDict = evaluateLogsQuery
.GroupBy(x => x.SerialNo)
.ToDictionary(g => g.Key, g => g.FirstOrDefault());

// 建立 SerialNo 到編號的映射
var serialNoToRowNumber = new Dictionary<string, int>();
int currentRowNumber = 1;

// 建立 SerialNo 到 CarEnter 的映射,方便快速查找
var carEnterDict = carEnter.GroupBy(x => x.SerialNo)
.ToDictionary(g => g.Key, g => g.FirstOrDefault());
// 建立臨時資料列表以便排序
var tempReportItems = new List<(int rowNumber, string tenantCode, string carNumber, DateTime? invoiceDate,
string invoiceNo, decimal invoiceAmount, string discountUnit, decimal? discountAmount,
DateTime discountTime, DateTime? enterTime, DateTime? exitTime,
decimal? parkingAmount, decimal? claimAmount)>();

// 建立報表資料並分組
var reportGroups = new Dictionary<int, List<(string tenantCode, DateTime? invoiceDate, string invoiceNo, decimal invoiceAmount)>>();
var groupData = new Dictionary<int, (int rowNumber, string carNumber, string discountUnit, decimal? discountAmount,
DateTime discountTime, DateTime? enterTime, DateTime? exitTime,
decimal? parkingAmount, decimal? claimAmount)>();

foreach (var log in logs)
foreach (var log in consumeLogs)
{
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo))
{
@@ -326,9 +366,9 @@ public class ReportController : Controller
}

DateTime? exitTime = null;
if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo))
if (!string.IsNullOrEmpty(log.SerialNo) && evaluateLogDict.ContainsKey(log.SerialNo))
{
exitTime = carEnterDict[log.SerialNo]?.DepartureDateTime;
exitTime = evaluateLogDict[log.SerialNo]?.LogTime;
}

var invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey);
@@ -338,15 +378,31 @@ public class ReportController : Controller

int rowNumber = !string.IsNullOrEmpty(log.SerialNo) ? serialNoToRowNumber[log.SerialNo] : 0;

tempReportItems.Add((rowNumber, tenantCode, log.PlateNo, invoiceDate, invoiceNo, invoiceAmount,
"金額", log.DiscountAmount, log.LogTime, log.EnterTime, exitTime,
log.TotalAmount, log.DiscountAmount));
}

// 按 RowNumber 排序,確保相同編號的資料連續,避免合併儲存格錯誤
tempReportItems = tempReportItems.OrderBy(x => x.rowNumber).ThenBy(x => x.discountTime).ToList();

// 建立報表資料並分組
var reportGroups = new Dictionary<int, List<(string tenantCode, DateTime? invoiceDate, string invoiceNo, decimal invoiceAmount)>>();
var groupData = new Dictionary<int, (int rowNumber, string carNumber, string discountUnit, decimal? discountAmount,
DateTime discountTime, DateTime? enterTime, DateTime? exitTime,
decimal? parkingAmount, decimal? claimAmount)>();

foreach (var item in tempReportItems)
{
// 記錄群組資料
if (!groupData.ContainsKey(rowNumber))
if (!groupData.ContainsKey(item.rowNumber))
{
groupData[rowNumber] = (rowNumber, log.PlateNo, "新台幣", log.DiscountAmount, log.LogTime,
log.EnterTime, exitTime, log.TotalAmount, log.DiscountAmount);
reportGroups[rowNumber] = new List<(string, DateTime?, string, decimal)>();
groupData[item.rowNumber] = (item.rowNumber, item.carNumber, item.discountUnit, item.discountAmount, item.discountTime,
item.enterTime, item.exitTime, item.parkingAmount, item.claimAmount);
reportGroups[item.rowNumber] = new List<(string, DateTime?, string, decimal)>();
}

reportGroups[rowNumber].Add((tenantCode, invoiceDate, invoiceNo, invoiceAmount));
reportGroups[item.rowNumber].Add((item.tenantCode, item.invoiceDate, item.invoiceNo, item.invoiceAmount));
}

var stream = new MemoryStream();
@@ -380,6 +436,17 @@ public class ReportController : Controller
.SetFontSize(18);
document.Add(title);

// 匯出資訊
var exportInfo = new Paragraph($"匯出時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}")
.SetFontSize(10)
.SetMarginTop(10);
document.Add(exportInfo);

var filterInfo = new Paragraph($"篩選條件:{startDate?.ToString("yyyy-MM-dd")} ~ {endDate?.ToString("yyyy-MM-dd")}")
.SetFontSize(10)
.SetMarginBottom(10);
document.Add(filterInfo);

// 建立表格
var table = new Table(13).UseAllAvailableWidth();
table.SetFontSize(8);
@@ -428,18 +495,18 @@ public class ReportController : Controller
// 每一行:發票日期、發票號碼、發票金額
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceDate?.ToString("yyyy-MM-dd") ?? "")).SetTextAlignment(TextAlignment.CENTER));
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceNo ?? "")).SetTextAlignment(TextAlignment.CENTER));
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceAmount.ToString("N0"))).SetTextAlignment(TextAlignment.CENTER));
table.AddCell(new Cell().Add(new Paragraph($"NT$ {invoice.invoiceAmount:N0}")).SetTextAlignment(TextAlignment.CENTER));

if (isFirstRow)
{
// 合併欄位:折扣單位、折扣金額、折扣時間、入場時間、出場時間、停車金額、請款金額
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountUnit ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountAmount?.ToString("N0") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph($"NT$ {group.discountAmount:N0}")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountTime.ToString("yyyy-MM-dd HH:mm"))).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.enterTime?.ToString("yyyy-MM-dd HH:mm") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.exitTime?.ToString("yyyy-MM-dd HH:mm") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.parkingAmount?.ToString("N0") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.claimAmount?.ToString("N0") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph($"NT$ {group.parkingAmount:N0}")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph($"NT$ {group.claimAmount:N0}")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE));
}
}
}


+ 3
- 1
Program.cs Dosyayı Görüntüle

@@ -24,11 +24,12 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
{
options.LoginPath = "/Home/Index";
options.AccessDeniedPath = "/Home/Index";
options.Cookie.Name = "CouponReport.Auth"; // 設定 Cookie 名稱
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SameSite = SameSiteMode.Strict;
options.SlidingExpiration = true;
options.Cookie.Expiration = null;
options.ExpireTimeSpan = TimeSpan.FromMinutes(15); // 設定15分鐘後過期
});

// Add services to the container.
@@ -37,6 +38,7 @@ builder.Services.AddSession(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.IdleTimeout = TimeSpan.FromMinutes(15); // Session 15分鐘後過期
});

var app = builder.Build();


+ 18
- 11
Views/Report/Index.cshtml Dosyayı Görüntüle

@@ -56,6 +56,13 @@
.group-row-odd {
background-color: #ffffff;
}
.table th, .table td {
text-align: center;
vertical-align: middle;
}
.text-right {
text-align: right !important;
}
</style>

<div class="table-responsive">
@@ -100,25 +107,25 @@
<tr class="@rowClass">
@if (isNewGroup)
{
<td rowspan="@rowSpanCount" class="align-middle">@item.RowNumber</td>
<td rowspan="@rowSpanCount">@item.RowNumber</td>
}
<td>@item.TenantCode</td>
@if (isNewGroup)
{
<td rowspan="@rowSpanCount" class="align-middle">@item.CarNumber</td>
<td rowspan="@rowSpanCount">@item.CarNumber</td>
}
<td>@item.InvoiceDate?.ToString("yyyy-MM-dd HH:mm:ss")</td>
<td>@item.InvoiceDate?.ToString("yyyy-MM-dd")</td>
<td>@item.InvoiceNumber</td>
<td class="text-end">@item.InvoiceAmount?.ToString("N0")</td>
<td class="text-right">NT$ @item.InvoiceAmount?.ToString("N0")</td>
@if (isNewGroup)
{
<td rowspan="@rowSpanCount" class="align-middle">@item.DiscountUnit</td>
<td rowspan="@rowSpanCount" class="align-middle text-end">@item.DiscountAmount?.ToString("N0")</td>
<td rowspan="@rowSpanCount" class="align-middle">@item.DiscountTime?.ToString("yyyy-MM-dd HH:mm:ss")</td>
<td rowspan="@rowSpanCount" class="align-middle">@item.EnterTime?.ToString("yyyy-MM-dd HH:mm:ss")</td>
<td rowspan="@rowSpanCount" class="align-middle">@item.ExitTime?.ToString("yyyy-MM-dd HH:mm:ss")</td>
<td rowspan="@rowSpanCount" class="align-middle text-end">@item.ParkingAmount?.ToString("N0")</td>
<td rowspan="@rowSpanCount" class="align-middle text-end">@item.ClaimAmount?.ToString("N0")</td>
<td rowspan="@rowSpanCount">@item.DiscountUnit</td>
<td rowspan="@rowSpanCount" class="text-right">NT$ @item.DiscountAmount?.ToString("N0")</td>
<td rowspan="@rowSpanCount">@item.DiscountTime?.ToString("yyyy-MM-dd HH:mm:ss")</td>
<td rowspan="@rowSpanCount">@item.EnterTime?.ToString("yyyy-MM-dd HH:mm:ss")</td>
<td rowspan="@rowSpanCount">@item.ExitTime?.ToString("yyyy-MM-dd HH:mm:ss")</td>
<td rowspan="@rowSpanCount" class="text-right">NT$ @item.ParkingAmount?.ToString("N0")</td>
<td rowspan="@rowSpanCount" class="text-right">NT$ @item.ClaimAmount?.ToString("N0")</td>
}
</tr>
}


+ 12
- 1
Views/Shared/_Layout.cshtml Dosyayı Görüntüle

@@ -12,7 +12,18 @@
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Report" asp-action="Index">折扣報表系統</a>
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">首頁</a>
@if (User.Identity?.IsAuthenticated == true)
{
<div class="ms-auto">
<form method="post" asp-controller="Home" asp-action="Logout" style="display: inline;">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-outline-secondary">
<i class="bi bi-box-arrow-right"></i> 登出
</button>
</form>
</div>
}
</div>
</nav>
</header>


Yükleniyor…
İptal
Kaydet