This commit is contained in:
misya 2025-05-30 11:15:11 +08:00
parent 755acb1a84
commit 457ee8f5d3
4 changed files with 99 additions and 109 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 required string DateSample { get; set; }
public TimeSpan TimeSample { get; set; } public required string 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
{ {
@ -54,29 +70,31 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
{ {
return View(); return View();
} }
public IActionResult TarBallForm()
public IActionResult TarBallForm()//Queries the database and returns a view with tarball data
{ {
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 +240,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 +257,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,65 +272,48 @@ 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 ===== // Get the specific tarball record with all joins
var query = @" var query = @"
SELECT SELECT
marine.*, marine.Id,
station.LocationName, marine.StationID,
state.StateName, marine.Longitude,
user.FullName,level.LevelName marine.Latitude,
FROM tbl_marine_tarball marine DATE_FORMAT(marine.DateSample, '%Y%m%d') AS DateSample, -- Format date as string
JOIN tbl_marine_station station ON marine.StationID = station.StationID DATE_FORMAT(marine.TimeSample, '%H%i%s') AS TimeSample, -- Format time as string
JOIN tbl_state state ON station.StateID = state.StateID marine.ClassifyID,
JOIN tbl_user user ON marine.FirstSampler = user.FullName -- Corrected column name marine.OptionalName1,
JOIN tbl_level level ON user.LevelID = level.LevelID marine.OptionalName2,
WHERE marine.Id = @id"; marine.OptionalName3,
marine.OptionalName4,
marine.FirstSampler,
station.LocationName,
state.StateName,
user.FullName,
level.LevelName
FROM tbl_marine_tarball marine
JOIN tbl_marine_station station ON marine.StationID = station.StationID
JOIN tbl_state state ON station.StateID = state.StateID
JOIN tbl_user user ON marine.FirstSampler = user.FullName
JOIN tbl_level level ON user.LevelID = level.LevelID
WHERE marine.Id = @id";
var tarball = await _context.Database var tarball = await _context.Database
.SqlQueryRaw<TarballPdfDto>(query, new MySqlParameter("@id", id)) .SqlQueryRaw<TarballPdfDto>(query, new MySqlParameter("@id", id))
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
if (tarball == null) if (tarball == null)
return NotFound("Record not found"); return NotFound($"No record found with ID: {id}");
//Prepare boolean values for PDF // Get images from path
bool tarBallYes = tarball.ClassifyID != "NO";
bool tarBallNo = tarball.ClassifyID == "NO";
bool isSand = tarball.ClassifyID == "SD";
bool isNonSandy = tarball.ClassifyID == "NS";
bool isCoquina = tarball.ClassifyID == "CO";
// ===== 2. Get Images from path =====
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);
string sampleDateTimeString = tarball.DateSample + tarball.TimeSample;
//Image collection
var stationImages = new Dictionary<string, string>(); var stationImages = new Dictionary<string, string>();
if (Directory.Exists(stationFolder)) if (Directory.Exists(stationFolder))
{ {
var imageTypes = new Dictionary<string, string> var imageTypes = new Dictionary<string, string>
@ -321,7 +322,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 +333,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}_{sampleDateTimeString}") &&
fileName.Contains(type, StringComparison.OrdinalIgnoreCase))
{ {
imageTypes[type] = imagePath; imageTypes[type] = imagePath;
break; break;
@ -341,7 +343,8 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
} }
stationImages = imageTypes; stationImages = imageTypes;
} }
//Mandatory images
// Validate mandatory images
var mandatoryImages = new List<string> var mandatoryImages = new List<string>
{ {
"LEFTSIDECOASTALVIEW", "LEFTSIDECOASTALVIEW",
@ -350,15 +353,15 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
"DRAWINGHORIZONTALLINES" "DRAWINGHORIZONTALLINES"
}; };
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}");
} }
} }
// ===== 3. GENERATE PDF (ADAPTED FOR NEW DTO) ===== // Generate PDF with all required parameters
var pdf = new TarBallPDF( var pdf = new TarBallPDF(
tarball.StateName, tarball.StateName,
tarball.StationID, tarball.StationID,
@ -368,11 +371,6 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
tarball.DateSample, tarball.DateSample,
tarball.TimeSample, tarball.TimeSample,
tarball.ClassifyID, tarball.ClassifyID,
tarBallYes,
tarBallNo,
isSand,
isNonSandy,
isCoquina,
stationImages["LEFTSIDECOASTALVIEW"], stationImages["LEFTSIDECOASTALVIEW"],
stationImages["RIGHTSIDECOASTALVIEW"], stationImages["RIGHTSIDECOASTALVIEW"],
stationImages["DRAWINGVERTICALLINES"], stationImages["DRAWINGVERTICALLINES"],
@ -390,23 +388,21 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
tarball.LevelName tarball.LevelName
).GeneratePdf(); ).GeneratePdf();
string pdfFileName = $"{tarball.StationID}_{tarball.DateSample}_{tarball.TimeSample}.pdf";
return forceDownload return forceDownload
? File(pdf, "application/pdf", $"{tarball.StationID}_{tarball.DateSample:yyyyMMdd}_{tarball.TimeSample:hhmmss}.pdf") ? File(pdf, "application/pdf", pdfFileName)
: File(pdf, "application/pdf"); : File(pdf, "application/pdf");
} }
catch (Exception ex) catch (Exception ex)
{ {
var errorMessage = ex.InnerException != null return StatusCode(500, $"Error generating PDF: {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

@ -7,12 +7,14 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator
{ {
public class TarBallPDF(string stateName, string stationID, string locationName, public class TarBallPDF
string longitude, string latitude, DateTime dateSample, TimeSpan timeSample, (
string classifyID, bool tarBallYes, bool tarBallNo, bool isSand, bool isNonSandy, string stateName, string stationID, string locationName, string longitude, string latitude,
bool isCoquina, string photoPath1, string photoPath2, string photoPath3, string photoPath4, string dateSample, string timeSample, string classifyID,
string photoPath5, string photoPath6, string photoPath7, string photoPath8, //bool tarBallYes, bool tarBallNo, bool isSand, bool isNonSandy, bool isCoquina,
string optionalName1, string optionalName2, string optionalName3, string optionalName4, string photoPath1, string photoPath2, string photoPath3, string photoPath4,
string? photoPath5, string? photoPath6, string? photoPath7, string? photoPath8,
string? optionalName1, string? optionalName2, string? optionalName3, string? optionalName4,
string firstSampler, string fullName, string levelName string firstSampler, string fullName, string levelName
) )
: IDocument : IDocument
@ -23,14 +25,14 @@ namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator
private readonly string _locationName = locationName; private readonly string _locationName = locationName;
private readonly string _longitude = longitude; private readonly string _longitude = longitude;
private readonly string _latitude = latitude; private readonly string _latitude = latitude;
private readonly DateTime _dateSample = dateSample; private readonly string _dateSample = dateSample;
private readonly TimeSpan _timeSample = timeSample; private readonly string _timeSample = timeSample;
private readonly string _classifyID = classifyID; private readonly string _classifyID = classifyID;
private readonly bool _tarBallYes = tarBallYes; //private bool TarBallYes => _classifyID != "NO";
private readonly bool _tarBallNo = tarBallNo; //private bool TarBallNo => _classifyID == "NO";
private readonly bool _isSand = isSand; //private bool IsSand => _classifyID == "SD";
private readonly bool _isNonSandy = isNonSandy; //private bool IsNonSandy => _classifyID == "NS";
private readonly bool _isCoquina = isCoquina; //private bool IsCoquina => _classifyID == "CO";
private readonly string _photoPath1 = photoPath1; private readonly string _photoPath1 = photoPath1;
private readonly string _photoPath2 = photoPath2; private readonly string _photoPath2 = photoPath2;
private readonly string _photoPath3 = photoPath3; private readonly string _photoPath3 = photoPath3;
@ -360,7 +362,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator
table.Cell().Element(CellStyle).Text("Signature").FontSize(12); table.Cell().Element(CellStyle).Text("Signature").FontSize(12);
table.Cell().Element(CellStyle).Text(""); table.Cell().Element(CellStyle).Text("");
table.Cell().Element(CellStyle).Text("Date").FontSize(12); table.Cell().Element(CellStyle).Text("Date").FontSize(12);
table.Cell().Element(CellStyle).Text(_dateSample.ToString("yyyy/MM/dd")).FontSize(12); table.Cell().Element(CellStyle).Text($"{_dateSample:yyyyMMdd}").FontSize(12);
table.Cell().Element(CellStyle).Text("Designation").FontSize(12); table.Cell().Element(CellStyle).Text("Designation").FontSize(12);
table.Cell().ColumnSpan(3).Element(CellStyle).Text(_levelName).FontSize(12); table.Cell().ColumnSpan(3).Element(CellStyle).Text(_levelName).FontSize(12);

View File

@ -22,15 +22,6 @@ namespace PSTW_CentralSystem.Models
public string? OptionalName3 { get; set; } public string? OptionalName3 { get; set; }
public string? OptionalName4 { get; set; } public string? OptionalName4 { get; set; }
public required string PhotoPath1 { get; set; } // Left Side Coastal View
public required string PhotoPath2 { get; set; } // Right Side Coastal View
public required string PhotoPath3 { get; set; } // Vertical Lines
public required string PhotoPath4 { get; set; } // Horizontal Lines
public string? PhotoPath5 { get; set; } // optional
public string? PhotoPath6 { get; set; } // optional
public string? PhotoPath7 { get; set; } // optional
public string? PhotoPath8 { get; set; } // optional
[ForeignKey("StationID")] [ForeignKey("StationID")]
public required MarineStation MarineStation { get; set; } public required MarineStation MarineStation { get; set; }
[ForeignKey("FirstSampler")] [ForeignKey("FirstSampler")]

View File

@ -40,6 +40,7 @@
<Folder Include="Areas\JSA\Views\" /> <Folder Include="Areas\JSA\Views\" />
<Folder Include="Areas\Report\Models\" /> <Folder Include="Areas\Report\Models\" />
<Folder Include="Logs\" /> <Folder Include="Logs\" />
<Folder Include="wwwroot\Media\User\Signature\" />
</ItemGroup> </ItemGroup>
</Project> </Project>