feat: 推广 V3.5 实时氢耗并完善导出

This commit is contained in:
lingniu
2026-09-04 15:42:02 +08:00
parent a26179c8fe
commit e402eb5e60
53 changed files with 2855 additions and 320 deletions
@@ -27,11 +27,11 @@ export async function createMileageWorkbook(input: MileageExportInput) {
workbook.calcProperties.fullCalcOnLoad = true;
const sheet = workbook.addWorksheet('里程查询', {
views: [{ state: 'frozen', xSplit: 2, ySplit: 6, activeCell: 'C7', showGridLines: false }],
views: [{ state: 'frozen', xSplit: 4, ySplit: 6, activeCell: 'E7', showGridLines: false }],
pageSetup: { orientation: 'landscape', fitToPage: true, fitToWidth: 1, fitToHeight: 0, paperSize: 9, margins: { left: .25, right: .25, top: .45, bottom: .45, header: .2, footer: .2 } },
properties: { defaultRowHeight: 21 }
});
const firstDateColumn = 3;
const firstDateColumn = 5;
const lastDateColumn = firstDateColumn + input.dates.length - 1;
const totalColumn = lastDateColumn + 1;
const lastColumnLetter = excelColumn(totalColumn);
@@ -72,14 +72,14 @@ export async function createMileageWorkbook(input: MileageExportInput) {
sheet.getRow(5).height = 8;
const header = sheet.getRow(headerRowNumber);
header.values = ['车牌', 'VIN', ...input.dates.map((date) => new Date(`${date}T12:00:00Z`)), '区间总里程'];
header.values = ['车牌', 'VIN', '品牌', '车型', ...input.dates.map((date) => new Date(`${date}T12:00:00Z`)), '区间总里程'];
header.height = 30;
header.eachCell((cell, columnNumber) => {
const isDateHeader = columnNumber >= firstDateColumn && columnNumber <= lastDateColumn;
cell.font = { name: 'Microsoft YaHei', size: 10, bold: true, color: { argb: columnNumber === totalColumn ? 'FF1C4F91' : 'FF304158' } };
cell.alignment = {
vertical: 'middle',
horizontal: columnNumber <= 2 ? 'left' : isDateHeader ? 'center' : 'right'
horizontal: columnNumber <= 4 ? 'left' : isDateHeader ? 'center' : 'right'
};
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: columnNumber === totalColumn ? 'FFDCEBFF' : 'FFEAF0F7' } };
cell.border = { bottom: { style: 'medium', color: { argb: 'FFC3D0DF' } } };
@@ -97,11 +97,11 @@ export async function createMileageWorkbook(input: MileageExportInput) {
const dailyValues = input.dates.map((date) => mileageByDate.get(date)?.dailyMileageKm ?? null);
const total = dailyValues.reduce<number>((sum, value) => sum + (value ?? 0), 0);
const row = sheet.getRow(rowNumber);
row.values = [vehicle.plate || '未绑定', vehicle.vin, ...dailyValues, null];
row.values = [vehicle.plate || '未绑定', vehicle.vin, vehicle.brandName || '待维护', vehicle.modelName || '待维护', ...dailyValues, null];
row.height = 25;
row.eachCell({ includeEmpty: true }, (cell, columnNumber) => {
cell.font = { name: columnNumber === 2 ? 'Consolas' : 'Microsoft YaHei', size: columnNumber === 2 ? 9 : 10, color: { argb: columnNumber === totalColumn ? 'FF1D4E89' : 'FF34445A' }, bold: columnNumber === 1 || columnNumber === totalColumn };
cell.alignment = { vertical: 'middle', horizontal: columnNumber <= 2 ? 'left' : 'right' };
cell.alignment = { vertical: 'middle', horizontal: columnNumber <= 4 ? 'left' : 'right' };
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: index % 2 ? 'FFF9FBFD' : 'FFFFFFFF' } };
cell.border = { bottom: { style: 'thin', color: { argb: 'FFE6ECF3' } } };
if (columnNumber >= firstDateColumn) cell.numFmt = '#,##0.0" km"';
@@ -116,6 +116,8 @@ export async function createMileageWorkbook(input: MileageExportInput) {
sheet.getColumn(1).width = 15;
sheet.getColumn(2).width = 24;
sheet.getColumn(3).width = 18;
sheet.getColumn(4).width = 24;
for (let column = firstDateColumn; column <= lastDateColumn; column += 1) sheet.getColumn(column).width = 12;
sheet.getColumn(totalColumn).width = 17;
if (input.vehicles.length) {
@@ -135,7 +137,7 @@ export async function createMileageWorkbook(input: MileageExportInput) {
views: [{ state: 'frozen', ySplit: 1, activeCell: 'A2', showGridLines: false }],
properties: { defaultRowHeight: 21 }
});
hydrogenSheet.addRow(['日期', '车牌', 'VIN', '总里程 (km)', '纯氢里程 (km)', '耗氢 (kg)', '百公里纯氢耗 (kg/100km)', '来源']);
hydrogenSheet.addRow(['日期', '车牌', 'VIN', '品牌', '车型', '总里程 (km)', '纯氢里程 (km)', '耗氢 (kg)', '百公里纯氢耗 (kg/100km)', '来源']);
const hydrogenHeader = hydrogenSheet.getRow(1);
hydrogenHeader.height = 30;
hydrogenHeader.eachCell((cell) => {
@@ -144,13 +146,16 @@ export async function createMileageWorkbook(input: MileageExportInput) {
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFEAF0F7' } };
cell.border = { bottom: { style: 'medium', color: { argb: 'FFC3D0DF' } } };
});
const plateByVIN = new Map(input.vehicles.map((vehicle) => [vehicle.vin, vehicle.plate || '未绑定']));
const vehicleByVIN = new Map(input.vehicles.map((vehicle) => [vehicle.vin, vehicle]));
const energyRows = [...input.mileageRows].sort((left, right) => left.date.localeCompare(right.date) || left.vin.localeCompare(right.vin));
energyRows.forEach((value, index) => {
const vehicle = vehicleByVIN.get(value.vin);
const row = hydrogenSheet.addRow([
value.date,
plateByVIN.get(value.vin) ?? value.plate ?? '未绑定',
vehicle?.plate || value.plate || '未绑定',
value.vin,
vehicle?.brandName || '待维护',
vehicle?.modelName || '待维护',
value.dailyMileageKm,
value.pureHydrogenMileageKm ?? null,
value.hydrogenConsumptionKg ?? null,
@@ -160,17 +165,17 @@ export async function createMileageWorkbook(input: MileageExportInput) {
row.height = 24;
row.eachCell({ includeEmpty: true }, (cell, columnNumber) => {
cell.font = { name: columnNumber === 3 ? 'Consolas' : 'Microsoft YaHei', size: columnNumber === 3 ? 9 : 10, color: { argb: 'FF34445A' } };
cell.alignment = { vertical: 'middle', horizontal: columnNumber >= 4 && columnNumber <= 7 ? 'right' : 'left' };
cell.alignment = { vertical: 'middle', horizontal: columnNumber >= 6 && columnNumber <= 9 ? 'right' : 'left' };
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: index % 2 ? 'FFF9FBFD' : 'FFFFFFFF' } };
cell.border = { bottom: { style: 'thin', color: { argb: 'FFE6ECF3' } } };
if (columnNumber >= 4 && columnNumber <= 7) cell.numFmt = '#,##0.0';
if (columnNumber >= 6 && columnNumber <= 9) cell.numFmt = '#,##0.0';
});
});
[13, 15, 24, 15, 17, 14, 27, 16].forEach((width, index) => {
[13, 15, 24, 18, 24, 15, 17, 14, 27, 16].forEach((width, index) => {
hydrogenSheet.getColumn(index + 1).width = width;
});
if (energyRows.length) {
hydrogenSheet.autoFilter = { from: { row: 1, column: 1 }, to: { row: energyRows.length + 1, column: 8 } };
hydrogenSheet.autoFilter = { from: { row: 1, column: 1 }, to: { row: energyRows.length + 1, column: 10 } };
}
hydrogenSheet.headerFooter.oddFooter = sheet.headerFooter.oddFooter;
return workbook;