Merge pull request #75 from hargata/Hargata/vehicle.history

added front end stuff for consolidated vehicle maintenance record.
This commit is contained in:
Hargata Softworks
2024-01-12 14:55:50 -07:00
committed by GitHub
19 changed files with 292 additions and 15 deletions

View File

@@ -682,6 +682,69 @@ namespace CarCareTracker.Controllers
};
return PartialView("_ReminderMakeUpReport", viewModel);
}
public IActionResult GetVehicleHistory(int vehicleId)
{
var vehicleHistory = new VehicleHistoryViewModel();
vehicleHistory.VehicleData = _dataAccess.GetVehicleById(vehicleId);
vehicleHistory.Odometer = GetMaxMileage(vehicleId).ToString("N0");
List<GenericReportModel> reportData = new List<GenericReportModel>();
var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId);
var repairRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId);
var upgradeRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId);
var taxRecords = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId);
var gasRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
bool useMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]);
bool useUKMPG = bool.Parse(_config[nameof(UserConfig.UseUKMPG)]);
vehicleHistory.TotalGasCost = gasRecords.Sum(x => x.Cost);
vehicleHistory.TotalCost = serviceRecords.Sum(x => x.Cost) + repairRecords.Sum(x => x.Cost) + upgradeRecords.Sum(x => x.Cost) + taxRecords.Sum(x => x.Cost);
var averageMPG = 0.00M;
var gasViewModels = _gasHelper.GetGasRecordViewModels(gasRecords, useMPG, useUKMPG);
if (gasViewModels.Any())
{
averageMPG = gasViewModels.Average(x => x.MilesPerGallon);
}
vehicleHistory.MPG = averageMPG;
//insert servicerecords
reportData.AddRange(serviceRecords.Select(x => new GenericReportModel
{
Date = x.Date,
Odometer = x.Mileage,
Description = x.Description,
Notes = x.Notes,
Cost = x.Cost,
DataType = ImportMode.ServiceRecord
}));
//repair records
reportData.AddRange(repairRecords.Select(x => new GenericReportModel
{
Date = x.Date,
Odometer = x.Mileage,
Description = x.Description,
Notes = x.Notes,
Cost = x.Cost,
DataType = ImportMode.RepairRecord
}));
reportData.AddRange(upgradeRecords.Select(x => new GenericReportModel
{
Date = x.Date,
Odometer = x.Mileage,
Description = x.Description,
Notes = x.Notes,
Cost = x.Cost,
DataType = ImportMode.UpgradeRecord
}));
reportData.AddRange(taxRecords.Select(x => new GenericReportModel
{
Date = x.Date,
Odometer = 0,
Description = x.Description,
Notes = x.Notes,
Cost = x.Cost,
DataType = ImportMode.TaxRecord
}));
vehicleHistory.VehicleHistory = reportData;
return PartialView("_VehicleHistory", vehicleHistory);
}
[HttpPost]
public IActionResult GetCostByMonthByVehicle(int vehicleId, List<ImportMode> selectedMetrics, int year = 0)
{

View File

@@ -1,7 +1,7 @@
namespace CarCareTracker.Models
{
/// <summary>
/// Import model used for importing Gas records.
/// Import model used for importing records via CSV.
/// </summary>
public class ImportModel
{
@@ -16,6 +16,7 @@
public string IsFillToFull { get; set; }
public string MissedFuelUp { get; set; }
}
public class ServiceRecordExportModel
{
public string Date { get; set; }

View File

@@ -0,0 +1,15 @@
namespace CarCareTracker.Models
{
/// <summary>
/// Generic Model used for vehicle history report.
/// </summary>
public class GenericReportModel
{
public ImportMode DataType { get; set; }
public DateTime Date { get; set; }
public int Odometer { get; set; }
public string Description { get; set; }
public string Notes { get; set; }
public decimal Cost { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
namespace CarCareTracker.Models
{
public class VehicleHistoryViewModel
{
public Vehicle VehicleData { get; set; }
public List<GenericReportModel> VehicleHistory { get; set; }
public string Odometer { get; set; }
public decimal MPG { get; set; }
public decimal TotalCost { get; set; }
public decimal TotalGasCost { get; set; }
}
}

View File

@@ -37,7 +37,7 @@
<button class="nav-link" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-journal-bookmark me-2"></i>Notes</span></button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><div id="reminderBellDiv" style="display:inline-flex;"><i id="reminderBell" class="bi bi-bell me-2"></i></div>Reminders</span></button>
<button class="nav-link" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell me-2"></i></div>Reminders</span></button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><span class="display-3 ms-2"><i class="bi bi-file-bar-graph me-2"></i>Reports</span></button>
@@ -79,7 +79,7 @@
<button class="nav-link" id="notes-tab" data-bs-toggle="tab" data-bs-target="#notes-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-journal-bookmark me-2"></i>Notes</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><div id="reminderBellDiv" style="display:inline-flex;"><i id="reminderBell" class="bi bi-bell me-2"></i></div>Reminders</button>
<button class="nav-link" id="reminder-tab" data-bs-toggle="tab" data-bs-target="#reminder-tab-pane" type="button" role="tab" aria-selected="false"><div class="reminderBellDiv" style="display:inline-flex;"><i class="reminderBell bi bi-bell me-2"></i></div>Reminders</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="report-tab" data-bs-toggle="tab" data-bs-target="#report-tab-pane" type="button" role="tab" aria-selected="false"><i class="bi bi-file-bar-graph me-2"></i>Reports</button>

View File

@@ -33,6 +33,11 @@
</div>
<div class="row vehicleDetailTabContainer">
<div class="col-12">
<div class="row mt-2 showOnPrint">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
</div>
</div>
<table class="table table-hover">
<thead>
<tr class="d-flex">

View File

@@ -62,6 +62,11 @@
</div>
<div class="row vehicleDetailTabContainer">
<div class="col-12">
<div class="row mt-2 showOnPrint">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
</div>
</div>
<table class="table table-hover">
<thead>
<tr class="d-flex">

View File

@@ -1,7 +1,7 @@
@model List<CostForVehicleByMonth>
@if (Model.Any())
{
<canvas id="bar-chart" class="vehicleDetailTabContainer"></canvas>
<canvas id="bar-chart"></canvas>
<script>
renderChart();
function renderChart() {

View File

@@ -11,6 +11,11 @@
</div>
<div class="row vehicleDetailTabContainer">
<div class="col-12">
<div class="row mt-2 showOnPrint">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
</div>
</div>
<table class="table table-hover">
<thead>
<tr class="d-flex">

View File

@@ -15,6 +15,11 @@
</div>
<div class="row vehicleDetailTabContainer">
<div class="col-12">
<div class="row mt-2 showOnPrint">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
</div>
</div>
<table class="table table-hover">
<thead>
<tr class="d-flex">

View File

@@ -1,5 +1,5 @@
@model ReportViewModel
<div class="row">
<div class="row hideOnPrint">
<div class="col-md-3 col-12 mt-2">
<div class="row">
<div class="col-12">
@@ -68,12 +68,27 @@
</div>
</div>
<hr />
<div class="row">
<div class="row hideOnPrint">
<div class="d-flex justify-content-center">
<button onclick="generateVehicleHistoryReport()" class="btn btn-secondary btn-md mt-1 mb-1"><i class="bi bi-pencil-square me-2"></i>Generate and Print Vehicle Maintenance Report</button>
</div>
</div>
<div id="vehicleHistoryReport" class="showOnPrint"></div>
<script>
function getYear() {
return $("#yearOption").val();
}
function generateVehicleHistoryReport(){
var vehicleId = GetVehicleId().vehicleId;
$.get(`/Vehicle/GetVehicleHistory?vehicleId=${vehicleId}`, function(data){
if (data) {
$("#vehicleHistoryReport").html(data);
setTimeout(function () {
window.print();
}, 500);
}
})
}
var debounce = null;
function updateCheck(sender) {
clearTimeout(debounce);

View File

@@ -33,6 +33,11 @@
</div>
<div class="row vehicleDetailTabContainer">
<div class="col-12">
<div class="row mt-2 showOnPrint">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
</div>
</div>
<table class="table table-hover">
<thead>
<tr class="d-flex">

View File

@@ -33,6 +33,11 @@
</div>
<div class="row vehicleDetailTabContainer">
<div class="col-12">
<div class="row mt-2 showOnPrint">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
</div>
</div>
<table class="table table-hover">
<thead>
<tr class="d-flex">

View File

@@ -33,6 +33,11 @@
</div>
<div class="row vehicleDetailTabContainer">
<div class="col-12">
<div class="row mt-2 showOnPrint">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
</div>
</div>
<table class="table table-hover">
<thead>
<tr class="d-flex">

View File

@@ -0,0 +1,108 @@
@inject IConfiguration Configuration
@{
var hideZero = bool.Parse(Configuration[nameof(UserConfig.HideZero)]);
var useMPG = bool.Parse(Configuration[nameof(UserConfig.UseMPG)]);
var useUKMPG = bool.Parse(Configuration[nameof(UserConfig.UseUKMPG)]);
var useKwh = Model.VehicleData.IsElectric;
string fuelEconomyUnit;
if (useKwh)
{
fuelEconomyUnit = useMPG ? "mi./kWh" : "kWh/100km";
}
else if (useMPG && useUKMPG)
{
fuelEconomyUnit = "mpg";
}
else if (useUKMPG)
{
fuelEconomyUnit = "l/100mi.";
}
else
{
fuelEconomyUnit = useMPG ? "mpg" : "l/100km";
}
}
@model VehicleHistoryViewModel
<div class="vehicleDetailTabContainer">
<div class="row mt-2">
<div class="d-flex">
<img src="/defaults/lubelogger_logo.png" />
<span class="display-6 ms-5">Vehicle Maintenance Report</span>
</div>
</div>
<hr />
<div class="row">
<div class="col-6">
<ul class="list-group">
<li class="list-group-item">
<span class="display-6">@($"{Model.VehicleData.Year} {Model.VehicleData.Make} {Model.VehicleData.Model}")</span>
</li>
<li class="list-group-item">
<span class="lead">@Model.VehicleData.LicensePlate</span>
</li>
<li class="list-group-item">
@if (Model.VehicleData.IsElectric)
{
<span><i class="bi bi-ev-station"></i> Electric</span>
}
else
{
<span><i class="bi bi-fuel-pump"></i> Gasoline</span>
}
</li>
</ul>
</div>
<div class="col-6">
<ul class="list-group">
<li class="list-group-item">Last Reported Odometer Reading: @Model.Odometer</li>
<li class="list-group-item">Average Fuel Economy: @($"{Model.MPG.ToString("F")} {fuelEconomyUnit}")</li>
<li class="list-group-item">Total Spent(excl. fuel): @Model.TotalCost.ToString("C")</li>
<li class="list-group-item">Total Spent on Fuel: @Model.TotalGasCost.ToString("C")</li>
</ul>
</div>
</div>
<hr />
<div class="row">
<div class="col-12">
<table class="table table-hover">
<thead>
<tr class="d-flex">
<th scope="col" class="col-2">Type</th>
<th scope="col" class="col-1">Date</th>
<th scope="col" class="col-1">Odometer</th>
<th scope="col" class="col-3">Description</th>
<th scope="col" class="col-1">Cost</th>
<th scope="col" class="col-4">Notes</th>
</tr>
</thead>
<tbody>
@foreach (GenericReportModel reportData in Model.VehicleHistory)
{
<tr class="d-flex">
<td class="col-2">
@if(reportData.DataType == ImportMode.ServiceRecord)
{
<span><i class="bi bi-card-checklist me-2"></i>Service</span>
} else if (reportData.DataType == ImportMode.RepairRecord)
{
<span><i class="bi bi-exclamation-octagon me-2"></i>Repair</span>
} else if (reportData.DataType == ImportMode.UpgradeRecord)
{
<span><i class="bi bi-wrench-adjustable me-2"></i>Upgrade</span>
} else if (reportData.DataType == ImportMode.TaxRecord)
{
<span><i class="bi bi-currency-dollar me-2"></i>Tax</span>
}
</td>
<td class="col-1">@reportData.Date.ToShortDateString()</td>
<td class="col-1">@(reportData.Odometer == default ? "---" : reportData.Odometer.ToString("N0"))</td>
<td class="col-3">@reportData.Description</td>
<td class="col-1">@((hideZero && reportData.Cost == default) ? "---" : reportData.Cost.ToString("C"))</td>
<td class="col-4 text-wrap">@CarCareTracker.Helper.StaticHelper.TruncateStrings(reportData.Notes, 100)</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>

View File

@@ -12,6 +12,7 @@ services:
- data:/App/data
- documents:/App/wwwroot/documents
- images:/App/wwwroot/images
- temp:/App/wwwroot/temp
- log:/App/log
- keys:/root/.aspnet/DataProtection-Keys
# expose port and/or use serving via traefik
@@ -42,6 +43,7 @@ volumes:
data:
documents:
images:
temp:
log:
keys:

View File

@@ -12,6 +12,7 @@ services:
- data:/App/data
- documents:/App/wwwroot/documents
- images:/App/wwwroot/images
- temp:/App/wwwroot/temp
- log:/App/log
- keys:/root/.aspnet/DataProtection-Keys
# expose port and/or use serving via traefik
@@ -25,5 +26,6 @@ volumes:
data:
documents:
images:
temp:
log:
keys:

View File

@@ -36,7 +36,17 @@ html {
overflow-x: auto;
}
.showOnPrint {
display:none;
}
@media print {
.hideOnPrint {
display:none;
}
.showOnPrint{
display:block !important;
}
.vehicleDetailTabContainer {
background-color: #fff;
height: 100%;
@@ -50,14 +60,24 @@ html {
color: #000 !important;
overflow: visible;
}
ul {
border: 0px !important;
}
li {
color: #000 !important;
border: 0px !important;
}
td {
color: #000 !important;
border: hidden;
}
td.col-1 {
width: 10%;
}
td.col-4.text-wrap{
width: 30%;
}
th.col-1 {
width: 10%;
@@ -66,6 +86,10 @@ html {
th {
color: #000 !important;
}
tr{
border: hidden;
}
}
.chartContainer {

View File

@@ -212,15 +212,15 @@ function getVehicleHaveImportantReminders(vehicleId) {
setTimeout(function () {
$.get(`/Vehicle/GetVehicleHaveUrgentOrPastDueReminders?vehicleId=${vehicleId}`, function (data) {
if (data) {
$("#reminderBell").removeClass("bi-bell");
$("#reminderBell").addClass("bi-bell-fill");
$("#reminderBell").addClass("text-warning");
$("#reminderBellDiv").addClass("bell-shake");
$(".reminderBell").removeClass("bi-bell");
$(".reminderBell").addClass("bi-bell-fill");
$(".reminderBell").addClass("text-warning");
$(".reminderBellDiv").addClass("bell-shake");
} else {
$("#reminderBellDiv").removeClass("bell-shake");
$("#reminderBell").removeClass("bi-bell-fill");
$("#reminderBell").addClass("bi-bell");
$("#reminderBell").removeClass("text-warning");
$(".reminderBellDiv").removeClass("bell-shake");
$(".reminderBell").removeClass("bi-bell-fill");
$(".reminderBell").addClass("bi-bell");
$(".reminderBell").removeClass("text-warning");
}
});
}, 500);