Compare commits

...

1 Commits

Author SHA1 Message Date
9bd5774e08 fix data display 2025-05-29 09:23:13 +08:00
2 changed files with 172 additions and 142 deletions

View File

@ -11,6 +11,7 @@ using System.Collections.Generic;
using Microsoft.Data.SqlClient; using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using MySqlConnector; using MySqlConnector;
using Org.BouncyCastle.Asn1.Cms;
namespace PSTW_CentralSystem.Areas.MMS.Controllers namespace PSTW_CentralSystem.Areas.MMS.Controllers
{ {
@ -18,25 +19,40 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
{ {
// From tbl_marine_tarball // From tbl_marine_tarball
public int Id { get; set; } public int Id { get; set; }
public string StationID { get; set; } public required string StationID { get; set; }
public string Longitude { get; set; } public required string Longitude { get; set; }
public string Latitude { get; set; } public required string Latitude { get; set; }
public DateTime DateSample { get; set; } public DateTime DateSample { get; set; }
public TimeSpan TimeSample { get; set; } public TimeSpan TimeSample { get; set; }
public string ClassifyID { get; set; } public required string ClassifyID { get; set; }
public string OptionalName1 { get; set; } public string? OptionalName1 { get; set; }
public string OptionalName2 { get; set; } public string? OptionalName2 { get; set; }
public string OptionalName3 { get; set; } public string? OptionalName3 { get; set; }
public string OptionalName4 { get; set; } public string? OptionalName4 { get; set; }
public string FirstSampler { get; set; } public required string FirstSampler { get; set; }
// From joined tables // From joined tables
public string LocationName { get; set; } // From tbl_marine_station public required string LocationName { get; set; } // From tbl_marine_station
public string StateName { get; set; } // From tbl_state public required string StateName { get; set; } // From tbl_state
public string FullName { get; set; } // From tbl_user public required string FullName { get; set; } // From tbl_user
public string LevelName { get; set; } // From tbl_level public required string LevelName { get; set; } // From tbl_level
} }
public class TarBallGroupViewModel
{
public List<int> Id { get; set; } = new List<int>();
public required string StationID { get; set; }
public required string Date { get; set; }
public required int TimeSampleCount { get; set; }
public required string LatestTime {get; set; }
public List<TarBallTimeSample> TimeSamples { get; set; } = new List<TarBallTimeSample>();
}
public class TarBallTimeSample
{
public required int Id { get; set; }
public string Time { get; set; }
}
[Area("MMS")] [Area("MMS")]
public class MarineController : Controller public class MarineController : Controller
{ {
@ -55,28 +71,37 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
return View(); return View();
} }
public IActionResult TarBallForm()//Queries the database and returns a view with tarball data public class StationDateGroup
{
public required string StationID { get; set; }
public DateTime DateSample { get; set; }
public List<TarballPdfDto> TimeSamples { get; set; } = new List<TarballPdfDto>();
}
public IActionResult TarBallForm()
{ {
try try
{ {
var marineTarballs = _context.MarineTarballs //ERRORRRRRRR====================================== var marineTarballs = _context.MarineTarballs
.Select(t => new .Select(t => new
{ {
t.Id, t.Id,
Date = t.DateSample.ToString("yyyy/MM/dd"), station = t.StationID,
Station = t.StationID date = t.DateSample.ToString("yyyy/MM/dd"),
time = t.TimeSample.ToString(@"hh\:mm\:ss"),
fullDate = t.DateSample, // Keep DateTime for sorting
t.TimeSample
}) })
.AsEnumerable()
.OrderByDescending(t => t.fullDate)
.ThenByDescending(t => t.TimeSample)
.ToList(); .ToList();
Console.WriteLine($"Marine Tarballs Count: {marineTarballs.Count}");
return View(marineTarballs); return View(marineTarballs);
} }
catch (Exception ex) catch (Exception ex)
{ {
// Show the real error in the browser (for debugging only)
return Content($"Error: {ex.Message}<br/>{ex.StackTrace}", "text/html"); return Content($"Error: {ex.Message}<br/>{ex.StackTrace}", "text/html");
} }
} }
[HttpGet] // Explicitly mark as a GET endpoint [HttpGet] // Explicitly mark as a GET endpoint
@ -222,7 +247,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
} }
} }
public async Task<IActionResult> GenerateReport(int id)//calls GeneratePdfResponse to generate a PDF for inline viewing public async Task<IActionResult> GenerateReport(int id)
{ {
return await GeneratePdfResponse(id, true); return await GeneratePdfResponse(id, true);
} }
@ -239,7 +264,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
{ {
// Add timeout for safety // Add timeout for safety
var task = Task.Run(() => GeneratePdfResponse(id, false)); var task = Task.Run(() => GeneratePdfResponse(id, false));
if (task.Wait(TimeSpan.FromSeconds(30))) // 30 second timeout if (task.Wait(TimeSpan.FromSeconds(30))) // 30-second timeout
{ {
return task.Result; return task.Result;
} }
@ -254,63 +279,55 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
private async Task<IActionResult> GeneratePdfResponse(int id, bool forceDownload) private async Task<IActionResult> GeneratePdfResponse(int id, bool forceDownload)
{ {
Console.WriteLine($"Requested ID in {(forceDownload ? "GenerateReport" : "ViewPDF")}: {id}");
// Temporary network connection test
try try
{ {
Console.WriteLine("Testing network connection...");
_networkAccessService.ConnectToNetworkPath();
Console.WriteLine("Network connected successfully!");
_networkAccessService.DisconnectFromNetworkShare();
}
catch (Exception ex)
{
Console.WriteLine($"NETWORK ERROR: {ex.Message}");
return StatusCode(500, $"Cannot access network: {ex.Message}");
}
try
{
// Connect to the network path
_networkAccessService.ConnectToNetworkPath(); _networkAccessService.ConnectToNetworkPath();
// ===== 1. NEW SQL QUERY APPROACH ===== var record = await _context.MarineTarballs.FirstOrDefaultAsync(t => t.Id == id);
if (record == null)
return NotFound($"No record found for Id: {id}");
// Retrieve all entries for the same StationID and DateSample
var query = @" var query = @"
SELECT SELECT
marine.*, marine.*,
station.LocationName, station.LocationName,
state.StateName, state.StateName,
user.FullName,level.LevelName user.FullName,
level.LevelName
FROM tbl_marine_tarball marine FROM tbl_marine_tarball marine
JOIN tbl_marine_station station ON marine.StationID = station.StationID JOIN tbl_marine_station station ON marine.StationID = station.StationID
JOIN tbl_state state ON station.StateID = state.StateID JOIN tbl_state state ON station.StateID = state.StateID
JOIN tbl_user user ON marine.FirstSampler = user.FullName -- Corrected column name JOIN tbl_user user ON marine.FirstSampler = user.FullName
JOIN tbl_level level ON user.LevelID = level.LevelID JOIN tbl_level level ON user.LevelID = level.LevelID
WHERE marine.Id=@id"; WHERE marine.Id=@id";
var tarball = await _context.Database var tarballEntries = await _context.Database
.SqlQueryRaw<TarballPdfDto>(query, new MySqlParameter("@id", id)) .SqlQueryRaw<TarballPdfDto>(query, new MySqlParameter("@id", id))
.FirstOrDefaultAsync(); .ToListAsync();
if (tarball == null) if (!tarballEntries.Any())
return NotFound("Record not found"); return NotFound($"No records found for Id: {id}");
//Prepare boolean values for PDF var pdfList = new List<IActionResult>();
// Iterate over each unique TimeSample within the same DateSample
foreach (var timeGroup in tarballEntries.GroupBy(t => t.TimeSample))
{
var tarball = timeGroup.First(); // Use first entry per time sample
// Classification logic remains unchanged
bool tarBallYes = tarball.ClassifyID != "NO"; bool tarBallYes = tarball.ClassifyID != "NO";
bool tarBallNo = tarball.ClassifyID == "NO"; bool tarBallNo = tarball.ClassifyID == "NO";
bool isSand = tarball.ClassifyID == "SD"; bool isSand = tarball.ClassifyID == "SD";
bool isNonSandy = tarball.ClassifyID == "NS"; bool isNonSandy = tarball.ClassifyID == "NS";
bool isCoquina = tarball.ClassifyID == "CO"; bool isCoquina = tarball.ClassifyID == "CO";
// ===== 2. Get Images from path ===== // Construct image paths ensuring correct naming format
var sampleDateString = tarball.DateSample.ToString("yyyyMMdd");
//var sampleTimeString = tarball.TimeSample.ToString("hhmmss");
var sampleTimePrefix = ((int)tarball.TimeSample.TotalHours).ToString("D2") +
tarball.TimeSample.Minutes.ToString("D2");
var stationFolder = Path.Combine(PhotoBasePath, tarball.StationID); var stationFolder = Path.Combine(PhotoBasePath, tarball.StationID);
var sampleDateString = tarball.DateSample.ToString("yyyyMMdd");
var sampleTimeString = tarball.TimeSample.ToString(@"hhmmss");
//Image collection
var stationImages = new Dictionary<string, string>(); var stationImages = new Dictionary<string, string>();
if (Directory.Exists(stationFolder)) if (Directory.Exists(stationFolder))
@ -321,7 +338,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
{ "RIGHTSIDECOASTALVIEW", null }, { "RIGHTSIDECOASTALVIEW", null },
{ "DRAWINGVERTICALLINES", null }, { "DRAWINGVERTICALLINES", null },
{ "DRAWINGHORIZONTALLINES", null }, { "DRAWINGHORIZONTALLINES", null },
{ "OPTIONAL01", null }, // Will remain null if not found { "OPTIONAL01", null },
{ "OPTIONAL02", null }, { "OPTIONAL02", null },
{ "OPTIONAL03", null }, { "OPTIONAL03", null },
{ "OPTIONAL04", null } { "OPTIONAL04", null }
@ -332,7 +349,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
var fileName = Path.GetFileNameWithoutExtension(imagePath); var fileName = Path.GetFileNameWithoutExtension(imagePath);
foreach (var type in imageTypes.Keys.ToList()) foreach (var type in imageTypes.Keys.ToList())
{ {
if (fileName.EndsWith(type, StringComparison.OrdinalIgnoreCase)) if (fileName.StartsWith($"{tarball.StationID}_{sampleDateString}_{sampleTimeString}") &&
fileName.Contains(type, StringComparison.OrdinalIgnoreCase))
{ {
imageTypes[type] = imagePath; imageTypes[type] = imagePath;
break; break;
@ -341,7 +359,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
} }
stationImages = imageTypes; stationImages = imageTypes;
} }
//Mandatory images
// Validate mandatory images exist
var mandatoryImages = new List<string> var mandatoryImages = new List<string>
{ {
"LEFTSIDECOASTALVIEW", "LEFTSIDECOASTALVIEW",
@ -352,14 +371,14 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
foreach (var mandatoryType in mandatoryImages) foreach (var mandatoryType in mandatoryImages)
{ {
if(!stationImages.ContainsKey(mandatoryType)) if (!stationImages.ContainsKey(mandatoryType) || stationImages[mandatoryType] == null)
{ {
return StatusCode(400, $"Missing mandatory image: {mandatoryType}"); return StatusCode(400, $"Missing mandatory image: {mandatoryType} for {tarball.StationID} on {tarball.DateSample}");
} }
} }
// ===== 3. GENERATE PDF (ADAPTED FOR NEW DTO) ===== // Generate PDF using existing classification and sorting logic
var pdf = new TarBallPDF( var pdfDocument = new TarBallPDF(
tarball.StateName, tarball.StateName,
tarball.StationID, tarball.StationID,
tarball.LocationName, tarball.LocationName,
@ -390,23 +409,26 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
tarball.LevelName tarball.LevelName
).GeneratePdf(); ).GeneratePdf();
return forceDownload string pdfFileName = $"{tarball.StationID}_{tarball.DateSample:yyyyMMdd}_{tarball.TimeSample:hhmmss}.pdf";
? File(pdf, "application/pdf", $"{tarball.StationID}_{tarball.DateSample:yyyyMMdd}_{tarball.TimeSample:hhmmss}.pdf")
: File(pdf, "application/pdf"); pdfList.Add(
forceDownload
? File(pdfDocument, "application/pdf", pdfFileName)
: File(pdfDocument, "application/pdf")
);
}
return pdfList.Count == 1 ? pdfList.First() : Ok(pdfList);
} }
catch (Exception ex) catch (Exception ex)
{ {
var errorMessage = ex.InnerException != null return StatusCode(500, $"Error: {ex.Message}");
? $"{ex.Message} (Inner: {ex.InnerException.Message})"
: ex.Message;
return Content($"PDF generation failed: {errorMessage}<br/>{ex.StackTrace}", "text/html");
} }
finally finally
{ {
_networkAccessService.DisconnectFromNetworkShare(); _networkAccessService.DisconnectFromNetworkShare();
} }
} }
private bool IsImageValid(string imagePath) private bool IsImageValid(string imagePath)
{ {
try try

View File

@ -102,15 +102,21 @@
return []; // Return an empty array if no data is available return []; // Return an empty array if no data is available
} }
// Extract all years from the data // Extract all years from the data (handling both FormattedDate and date)
const allYears = this.dataFromServer.map(data => new Date(data.date).getFullYear()); const allYears = this.dataFromServer.map(data => {
const dateStr = data.Date || data.date; // Handle both cases
return new Date(dateStr).getFullYear();
});
// Find the minimum and maximum years // Find the minimum and maximum years
const minYear = Math.min(...allYears); const minYear = Math.min(...allYears);
const maxYear = Math.max(...allYears); const maxYear = Math.max(...allYears);
// Generate a range of years from minYear to maxYear // Generate a range of years from minYear to maxYear
return Array.from({ length: maxYear - minYear + 1 }, (_, i) => (minYear + i).toString()); return Array.from(
{ length: maxYear - minYear + 1 },
(_, i) => (minYear + i).toString()
);
}, },
sortedFilteredData() { sortedFilteredData() {
// If no filters are applied, return all data sorted by descending date // If no filters are applied, return all data sorted by descending date
@ -154,11 +160,11 @@
"data": null, "data": null,
"render": (data, type, row, meta) => meta.row + 1 // Dynamically generate "No." "render": (data, type, row, meta) => meta.row + 1 // Dynamically generate "No."
}, },
{ "data": "date", "render": (data) => new Date(data).toLocaleDateString('en-GB') }, { "data": "date"},
{ "data": "station" }, { "data": "station" },
{ {
"data": null, "data": null,
"render": () => ` "render": (data) => `
<button class="btn btn-success">Approve</button> <button class="btn btn-success">Approve</button>
<button class="btn btn-danger">Reject</button> <button class="btn btn-danger">Reject</button>
` `
@ -166,8 +172,10 @@
{ {
"data": null, "data": null,
"render": (data) => ` "render": (data) => `
<a href="/MMS/Marine/ViewPDF?id=${data.id}" class="btn btn-primary" target="_blank">View PDF</a> <a href="/MMS/Marine/ViewPDF?stationId=${data.Id}"
<a href="/MMS/Marine/GenerateReport?id=${data.id}" class="btn btn-primary">Download PDF</a> class="btn btn-primary" target="_blank">View PDF</a>
<a href="/MMS/Marine/GenerateReport?stationId=${data.Id}"
class="btn btn-primary">Download PDF</a>
` `
} }
], ],