Merge pull request #75 from hargata/Hargata/vehicle.history
added front end stuff for consolidated vehicle maintenance record.
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
|
||||
15
Models/Report/GenericReportModel.cs
Normal file
15
Models/Report/GenericReportModel.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
12
Models/Report/VehicleHistoryViewModel.cs
Normal file
12
Models/Report/VehicleHistoryViewModel.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
108
Views/Vehicle/_VehicleHistory.cshtml
Normal file
108
Views/Vehicle/_VehicleHistory.cshtml
Normal 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>
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user