@jjlmoya/utils-motor 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/category/index.ts +2 -1
- package/src/entries.ts +4 -1
- package/src/index.ts +5 -0
- package/src/tests/i18n_coverage.test.ts +5 -3
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -2
- package/src/tool/realFuelConsumptionCalculator/bibliography.astro +6 -0
- package/src/tool/realFuelConsumptionCalculator/bibliography.ts +12 -0
- package/src/tool/realFuelConsumptionCalculator/component.astro +111 -0
- package/src/tool/realFuelConsumptionCalculator/controller.ts +175 -0
- package/src/tool/realFuelConsumptionCalculator/dom-views.ts +132 -0
- package/src/tool/realFuelConsumptionCalculator/entry.ts +30 -0
- package/src/tool/realFuelConsumptionCalculator/evaluator.ts +15 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/de.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/en.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/es.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/factory.ts +110 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/fr.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/id.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/it.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/ja.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/ko.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/nl.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/pl.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/pt.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/ru.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/sv.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/tr.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/i18n/zh.ts +119 -0
- package/src/tool/realFuelConsumptionCalculator/index.ts +10 -0
- package/src/tool/realFuelConsumptionCalculator/logic.test.ts +72 -0
- package/src/tool/realFuelConsumptionCalculator/logic.ts +142 -0
- package/src/tool/realFuelConsumptionCalculator/real-fuel-consumption-calculator.css +692 -0
- package/src/tool/realFuelConsumptionCalculator/seo.astro +15 -0
- package/src/tool/realFuelConsumptionCalculator/storage.ts +54 -0
- package/src/tool/realFuelConsumptionCalculator/ui.ts +72 -0
- package/src/tools.ts +2 -1
- package/src/tests/faq_count.test.ts +0 -19
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { createLocalizedContent } from './factory';
|
|
2
|
+
|
|
3
|
+
export const content = createLocalizedContent({
|
|
4
|
+
locale: 'zh',
|
|
5
|
+
slug: 'real-fuel-consumption-calculator',
|
|
6
|
+
title: '汽车与摩托车实际油耗·电耗计算器',
|
|
7
|
+
description: '根据行驶里程和加油/充电量,精准计算燃油车或电动车的实际油耗与电耗。对比每百公里费用,并与官方标称数据作参照。',
|
|
8
|
+
faqTitle: '常见问题解答',
|
|
9
|
+
bibliographyTitle: '参考文献与依据',
|
|
10
|
+
ui: {
|
|
11
|
+
fuelTypeLabel: '能源类型',
|
|
12
|
+
gasolineLabel: '汽油',
|
|
13
|
+
dieselLabel: '柴油',
|
|
14
|
+
electricLabel: '纯电 (EV)',
|
|
15
|
+
currencyLabel: '货币',
|
|
16
|
+
currencyRateLabel: '1 EUR =',
|
|
17
|
+
resetLabel: '重置',
|
|
18
|
+
measurementTitle: '您的实测行程',
|
|
19
|
+
intakeQuestion: '本次行程实际消耗了多少能源?',
|
|
20
|
+
distanceLabel: '行驶里程',
|
|
21
|
+
distanceHint: '测量期间行驶的总公里数',
|
|
22
|
+
distanceUnit: 'km',
|
|
23
|
+
usedLabel: '消耗总量',
|
|
24
|
+
gasolineUsedLabel: '加注汽油量',
|
|
25
|
+
gasolineUsedHint: '加油站加满时补充的升数',
|
|
26
|
+
dieselUsedLabel: '加注柴油量',
|
|
27
|
+
dieselUsedHint: '加油站加满时补充的升数',
|
|
28
|
+
electricUsedLabel: '充入电量',
|
|
29
|
+
electricUsedHint: '充电桩充入的度数 (kWh)',
|
|
30
|
+
fuelUnit: 'L',
|
|
31
|
+
energyUnit: 'kWh',
|
|
32
|
+
fuelConsumptionUnit: 'L/100 km',
|
|
33
|
+
energyConsumptionUnit: 'kWh/100 km',
|
|
34
|
+
priceLabel: '能源单价',
|
|
35
|
+
priceHint: '实际支付的每单位价格',
|
|
36
|
+
gasolinePriceLabel: '每升汽油价格',
|
|
37
|
+
dieselPriceLabel: '每升柴油价格',
|
|
38
|
+
electricPriceLabel: '每度电 (kWh) 价格',
|
|
39
|
+
optionalDetails: '添加官方标称值与对比车型',
|
|
40
|
+
ratedLabel: '官方标称能耗',
|
|
41
|
+
gasolineRatedLabel: '官方汽油标称油耗',
|
|
42
|
+
dieselRatedLabel: '官方柴油标称油耗',
|
|
43
|
+
electricRatedLabel: '官方纯电标称电耗',
|
|
44
|
+
ratedHint: '请输入您车辆的工况/WLTC申报数据',
|
|
45
|
+
readingTitle: '您的实际能耗',
|
|
46
|
+
comparisonTitle: '用车成本对比',
|
|
47
|
+
comparisonQuestion: '哪种动力每百公里花费更低?',
|
|
48
|
+
comparisonHint: '柱状图越长,代表百公里能耗费用越高。',
|
|
49
|
+
comparisonCostLabel: '费用 / 100 km',
|
|
50
|
+
comparisonNotSet: '请在下方添加数据',
|
|
51
|
+
comparisonReady: '已具备对比条件',
|
|
52
|
+
comparisonCheapest: '最省钱',
|
|
53
|
+
comparisonMostExpensive: '费用最高',
|
|
54
|
+
comparisonPunchline: '柱状图最短的选项,即为日常行驶成本最低的动力方案。',
|
|
55
|
+
comparisonSettingsTitle: '能耗换算比例设置',
|
|
56
|
+
comparisonSettingsHint: '每一行均与您的实测数据联动。您可以修改比例来模拟不同车型。',
|
|
57
|
+
rememberComparisonsLabel: '在本设备上保存比率设置',
|
|
58
|
+
resetComparisonsLabel: '重置比率',
|
|
59
|
+
compareConsumptionLabel: '能耗数值',
|
|
60
|
+
compareRatioLabel: '对比汽油比率',
|
|
61
|
+
comparePriceLabel: '单价',
|
|
62
|
+
efficiencyLabel: '单位能耗行驶距离',
|
|
63
|
+
mpgLabel: '美制 MPG',
|
|
64
|
+
tripCostLabel: '本次行程总花费',
|
|
65
|
+
costPer100Label: '百公里行驶花费',
|
|
66
|
+
savedLabel: '节省金额',
|
|
67
|
+
extraLabel: '额外支出',
|
|
68
|
+
gasolineStatusBetter: '本次行程汽油消耗低于官方申报油耗。',
|
|
69
|
+
gasolineStatusClose: '本次行程汽油消耗接近官方申报油耗。',
|
|
70
|
+
gasolineStatusHigher: '本次行程汽油消耗高于官方申报油耗。',
|
|
71
|
+
dieselStatusBetter: '本次行程柴油消耗低于官方申报油耗。',
|
|
72
|
+
dieselStatusClose: '本次行程柴油消耗接近官方申报油耗。',
|
|
73
|
+
dieselStatusHigher: '本次行程柴油消耗高于官方申报油耗。',
|
|
74
|
+
electricStatusBetter: '本次充电电耗低于官方申报电耗。',
|
|
75
|
+
electricStatusClose: '本次充电电耗接近官方申报电耗。',
|
|
76
|
+
electricStatusHigher: '本次充电电耗高于官方申报电耗。',
|
|
77
|
+
formulaLabel: '计算公式',
|
|
78
|
+
fuelFormula: '升数 ÷ 公里数 × 100',
|
|
79
|
+
electricFormula: '度数 ÷ 公里数 × 100',
|
|
80
|
+
localNotice: '所有测量数据仅保存在您的本地浏览器中。',
|
|
81
|
+
},
|
|
82
|
+
faq: [
|
|
83
|
+
{ question: '如何计算车辆的实际油耗/电耗?', answer: '将加满补充的升数(或充入的度数kWh)除以行驶公里数,再乘以100。例如:600公里消耗了45升汽油,实际油耗即为 7.5 L/100 km。' },
|
|
84
|
+
{ question: '单价栏应该输入什么?', answer: '输入您实际支付的每升油价或每度电价。选择对应的货币后,计算器会自动算出本次行程总支出及百公里费用。' },
|
|
85
|
+
{ question: '可以同时对比汽油车、柴油车和电动车吗?', answer: '可以。计算器将不同动力形式的能耗与当地单价结合,统一换算为百公里花费金额,从而实现直观公平的对比。' },
|
|
86
|
+
{ question: '为什么实际能耗通常高于官方工况(如WLTC/CLTC)数据?', answer: '官方数据是在标准实验室环境测得的。实际驾驶中的路况拥堵、车速变化、地形起伏、载重、胎压以及空调开闭等均会增加能耗。' },
|
|
87
|
+
],
|
|
88
|
+
howTo: [
|
|
89
|
+
{ name: '选择能源类型', text: '点击汽油、柴油或纯电,计算器会自动切换对应计量单位。' },
|
|
90
|
+
{ name: '输入实测行程数据', text: '填入小计里程表显示行驶公里数,以及跳枪/充满时补充的油量或电量。' },
|
|
91
|
+
{ name: '输入实际单价', text: '填入每升或每度的单价,并选择您所使用的货币。' },
|
|
92
|
+
{ name: '查看计算结果', text: '实时获取 L/100km 或 kWh/100km 实际能耗、行程总油费/电费及百公里成本。' },
|
|
93
|
+
{ name: '添加参考对比数据', text: '展开可选设置区,输入官方工况申报值或其他动力车型的对比参数。' },
|
|
94
|
+
],
|
|
95
|
+
seo: {
|
|
96
|
+
calcTitle: '精准计算爱车真实用车成本与百公里花费',
|
|
97
|
+
calcText: '本计算器解答加油/充电后的实用疑问:<strong>我的车这次到底消耗了多少,这趟行程花了多少钱?</strong> 只需里程、加油量和单价,即可得出真实平均油耗、行程总开销和百公里用车成本。',
|
|
98
|
+
stat1Value: '3项输入',
|
|
99
|
+
stat1Label: '里程、加油量与单价',
|
|
100
|
+
stat2Value: 'L/100 km',
|
|
101
|
+
stat2Label: '汽油与柴油',
|
|
102
|
+
stat3Value: 'kWh/100 km',
|
|
103
|
+
stat3Label: '纯电动汽车 (EV)',
|
|
104
|
+
measureTitle: '如何用二次加满法精准测量实际油耗',
|
|
105
|
+
measureText: '先将油箱加满(或电量充至100%),将小计里程归零,正常行驶至下一次加油。再次加满并记录里程与加注升数。计算公式为:<strong>加注量 ÷ 行驶里程 × 100</strong>。',
|
|
106
|
+
tableHeaders: ['已知数据', '计算公式', '得出结果'],
|
|
107
|
+
tableRows: [
|
|
108
|
+
['加注升数与公里数', '升数 ÷ 公里数 × 100', 'L/100 km (实际油耗)'],
|
|
109
|
+
['充入度数与公里数', 'kWh ÷ 公里数 × 100', 'kWh/100 km (实际电耗)'],
|
|
110
|
+
['加注量与单位单价', '加注量 × 单价', '行程总费用'],
|
|
111
|
+
['实际能耗与单价', '实际能耗 × 单价', '百公里行驶成本'],
|
|
112
|
+
],
|
|
113
|
+
compareTitle: '横向对比汽油、柴油与纯电能耗费用',
|
|
114
|
+
compareText: '对比卡片可一目了然地分析不同动力形式的日常花费。用百公里资金支出进行对比,比单纯比较升数与度数更为精准,能将不同能源放在同一基准线上评测。',
|
|
115
|
+
versusTitle: '实际能耗与官方工况标称值的差异',
|
|
116
|
+
tipTitle: '设置爱车官方申报值作为参考基准',
|
|
117
|
+
tipText: '在折叠面板中输入您爱车的官方工况申报数值。受实际路况、气温与驾驶习惯影响,日常行驶能耗通常高于实验室测得的申报数据。',
|
|
118
|
+
},
|
|
119
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { realFuelConsumptionCalculator } from './entry';
|
|
2
|
+
|
|
3
|
+
export * from './entry';
|
|
4
|
+
|
|
5
|
+
export const REAL_FUEL_CONSUMPTION_CALCULATOR_TOOL = {
|
|
6
|
+
entry: realFuelConsumptionCalculator,
|
|
7
|
+
Component: () => import('./component.astro'),
|
|
8
|
+
SEOComponent: () => import('./seo.astro'),
|
|
9
|
+
BibliographyComponent: () => import('./bibliography.astro'),
|
|
10
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { amountUnit, calculateFuelLog, consumptionUnit, currencyConversionFactor, currencySymbol } from './logic';
|
|
3
|
+
|
|
4
|
+
const comparisons = {
|
|
5
|
+
gasoline: { ratio: 1, price: 1.8 },
|
|
6
|
+
diesel: { ratio: 0.82, price: 1.72 },
|
|
7
|
+
electric: { ratio: 2.6, price: 0.22 },
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
describe('fuel log logic', () => {
|
|
11
|
+
it('calculates gasoline consumption and cost', () => {
|
|
12
|
+
const result = calculateFuelLog({ distance: 400, used: 24, price: 1.8, rated: 5.2, mode: 'gasoline', currency: 'EUR', comparisons });
|
|
13
|
+
|
|
14
|
+
expect(result.realPer100).toBeCloseTo(6, 6);
|
|
15
|
+
expect(result.distancePerUnit).toBeCloseTo(16.6667, 4);
|
|
16
|
+
expect(result.usMpg).toBeCloseTo(39.2, 1);
|
|
17
|
+
expect(result.tripCost).toBeCloseTo(43.2, 6);
|
|
18
|
+
expect(result.differencePercent).toBeCloseTo(15.3846, 4);
|
|
19
|
+
expect(result.amountDelta).toBeCloseTo(-3.2, 6);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('calculates electric consumption without MPG', () => {
|
|
23
|
+
const result = calculateFuelLog({ distance: 250, used: 42.5, price: 0.22, rated: 16, mode: 'electric', currency: 'EUR', comparisons });
|
|
24
|
+
|
|
25
|
+
expect(result.realPer100).toBeCloseTo(17, 6);
|
|
26
|
+
expect(result.usMpg).toBeNull();
|
|
27
|
+
expect(result.tripCost).toBeCloseTo(9.35, 6);
|
|
28
|
+
expect(result.ratedAmount).toBe(40);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('protects calculations from invalid readings', () => {
|
|
32
|
+
const result = calculateFuelLog({ distance: Number.NaN, used: -1, price: Number.NaN, rated: 0, mode: 'diesel', currency: 'RUB', comparisons });
|
|
33
|
+
|
|
34
|
+
expect(result.distance).toBe(1);
|
|
35
|
+
expect(Number.isFinite(result.realPer100)).toBe(true);
|
|
36
|
+
expect(Number.isFinite(result.tripCost)).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('returns a cost comparison for each configured energy type', () => {
|
|
40
|
+
const result = calculateFuelLog({ distance: 100, used: 6.5, price: 1.8, rated: 5.8, mode: 'gasoline', currency: 'EUR', comparisons });
|
|
41
|
+
|
|
42
|
+
expect(result.comparisons.gasoline?.costPer100).toBeCloseTo(11.7, 6);
|
|
43
|
+
expect(result.comparisons.diesel?.costPer100).toBeCloseTo(9.1676, 6);
|
|
44
|
+
expect(result.comparisons.electric?.costPer100).toBeCloseTo(3.718, 6);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('converts the active diesel reading back to the gasoline baseline', () => {
|
|
48
|
+
const result = calculateFuelLog({ distance: 100, used: 5.33, price: 1.72, rated: 5.8, mode: 'diesel', currency: 'EUR', comparisons });
|
|
49
|
+
|
|
50
|
+
expect(result.realPer100).toBeCloseTo(5.33, 6);
|
|
51
|
+
expect(result.comparisons.gasoline?.consumption).toBeCloseTo(6.5, 1);
|
|
52
|
+
expect(result.comparisons.gasoline?.costPer100).toBeGreaterThan(result.comparisons.diesel?.costPer100 ?? 0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('uses currency factors that match the scale of each local currency', () => {
|
|
56
|
+
expect(currencyConversionFactor('EUR')).toBe(1);
|
|
57
|
+
expect(currencyConversionFactor('RUB')).toBeCloseTo(96.73, 2);
|
|
58
|
+
expect(currencyConversionFactor('JPY')).toBeCloseTo(185.66, 2);
|
|
59
|
+
expect(currencyConversionFactor('IDR')).toBeCloseTo(20659.38, 2);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('exposes the units and currency symbols used by the interface', () => {
|
|
63
|
+
expect(amountUnit('gasoline')).toBe('L');
|
|
64
|
+
expect(amountUnit('electric')).toBe('kWh');
|
|
65
|
+
expect(consumptionUnit('diesel')).toBe('L/100 km');
|
|
66
|
+
expect(consumptionUnit('electric')).toBe('kWh/100 km');
|
|
67
|
+
expect(currencySymbol('EUR')).toBe('€');
|
|
68
|
+
expect(currencySymbol('USD')).toBe('$');
|
|
69
|
+
expect(currencySymbol('RUB')).toBe('₽');
|
|
70
|
+
expect(currencySymbol('JPY')).toBe('¥');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
export type EnergyMode = 'gasoline' | 'diesel' | 'electric';
|
|
2
|
+
export type Currency = 'EUR' | 'USD' | 'IDR' | 'JPY' | 'KRW' | 'PLN' | 'RUB' | 'SEK' | 'TRY' | 'CNY';
|
|
3
|
+
|
|
4
|
+
export interface ComparisonInput {
|
|
5
|
+
ratio: number;
|
|
6
|
+
price: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface FuelLogInput {
|
|
10
|
+
distance: number;
|
|
11
|
+
used: number;
|
|
12
|
+
price: number;
|
|
13
|
+
rated: number;
|
|
14
|
+
mode: EnergyMode;
|
|
15
|
+
currency: Currency;
|
|
16
|
+
comparisons: Record<EnergyMode, ComparisonInput>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FuelComparisonResult {
|
|
20
|
+
mode: EnergyMode;
|
|
21
|
+
consumption: number;
|
|
22
|
+
price: number;
|
|
23
|
+
costPer100: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface FuelLogResult {
|
|
27
|
+
distance: number;
|
|
28
|
+
used: number;
|
|
29
|
+
price: number;
|
|
30
|
+
rated: number;
|
|
31
|
+
mode: EnergyMode;
|
|
32
|
+
currency: Currency;
|
|
33
|
+
realPer100: number;
|
|
34
|
+
distancePerUnit: number;
|
|
35
|
+
usMpg: number | null;
|
|
36
|
+
tripCost: number;
|
|
37
|
+
costPer100: number;
|
|
38
|
+
differencePercent: number;
|
|
39
|
+
ratedAmount: number;
|
|
40
|
+
amountDelta: number;
|
|
41
|
+
comparisons: Record<EnergyMode, FuelComparisonResult | null>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const KM_TO_MILES = 0.621371192;
|
|
45
|
+
const LITRES_TO_US_GALLONS = 0.264172052;
|
|
46
|
+
|
|
47
|
+
const CURRENCY_PER_EUR: Record<Currency, number> = {
|
|
48
|
+
EUR: 1, USD: 1.1699, IDR: 20659.38, JPY: 185.66, KRW: 1619.41,
|
|
49
|
+
PLN: 4.3078, RUB: 96.73, SEK: 11.0625, TRY: 56.2318, CNY: 7.8624,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function positive(value: number, fallback: number): number {
|
|
53
|
+
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function nonNegative(value: number): number {
|
|
57
|
+
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function comparison(mode: EnergyMode, input: ComparisonInput, gasolineBase: number): FuelComparisonResult | null {
|
|
61
|
+
if (!Number.isFinite(input.ratio) || input.ratio <= 0) return null;
|
|
62
|
+
const price = nonNegative(input.price);
|
|
63
|
+
const consumption = gasolineBase * input.ratio;
|
|
64
|
+
return { mode, consumption, price, costPer100: consumption * price };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface NormalizedFuelInput {
|
|
68
|
+
distance: number;
|
|
69
|
+
used: number;
|
|
70
|
+
price: number;
|
|
71
|
+
rated: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizedInput(input: FuelLogInput): NormalizedFuelInput {
|
|
75
|
+
return {
|
|
76
|
+
distance: positive(input.distance, 1),
|
|
77
|
+
used: positive(input.used, 0.001),
|
|
78
|
+
price: nonNegative(input.price),
|
|
79
|
+
rated: positive(input.rated, 0.1),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function fuelMetrics(input: NormalizedFuelInput, mode: EnergyMode): Pick<FuelLogResult, 'realPer100' | 'distancePerUnit' | 'usMpg' | 'tripCost' | 'costPer100' | 'differencePercent' | 'ratedAmount' | 'amountDelta'> {
|
|
84
|
+
const { distance, used, price, rated } = input;
|
|
85
|
+
const realPer100 = (used / distance) * 100;
|
|
86
|
+
const ratedAmount = (distance / 100) * rated;
|
|
87
|
+
const usMpg = mode === 'electric' ? null : (distance * KM_TO_MILES) / (used * LITRES_TO_US_GALLONS);
|
|
88
|
+
return {
|
|
89
|
+
realPer100,
|
|
90
|
+
distancePerUnit: distance / used,
|
|
91
|
+
usMpg,
|
|
92
|
+
tripCost: used * price,
|
|
93
|
+
costPer100: realPer100 * price,
|
|
94
|
+
differencePercent: ((realPer100 - rated) / rated) * 100,
|
|
95
|
+
ratedAmount,
|
|
96
|
+
amountDelta: ratedAmount - used,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function calculateFuelLog(input: FuelLogInput): FuelLogResult {
|
|
101
|
+
const { distance, used, price, rated } = normalizedInput(input);
|
|
102
|
+
const metrics = fuelMetrics({ distance, used, price, rated }, input.mode);
|
|
103
|
+
const activeRatio = positive(input.comparisons[input.mode].ratio, 1);
|
|
104
|
+
const gasolineBase = input.mode === 'gasoline' ? metrics.realPer100 : metrics.realPer100 / activeRatio;
|
|
105
|
+
const comparisons = {
|
|
106
|
+
gasoline: comparison('gasoline', input.comparisons.gasoline, gasolineBase),
|
|
107
|
+
diesel: comparison('diesel', input.comparisons.diesel, gasolineBase),
|
|
108
|
+
electric: comparison('electric', input.comparisons.electric, gasolineBase),
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
comparisons[input.mode] = { mode: input.mode, consumption: metrics.realPer100, price, costPer100: metrics.costPer100 };
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
distance,
|
|
115
|
+
used,
|
|
116
|
+
price,
|
|
117
|
+
rated,
|
|
118
|
+
mode: input.mode,
|
|
119
|
+
currency: input.currency,
|
|
120
|
+
...metrics,
|
|
121
|
+
comparisons,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function currencyConversionFactor(currency: Currency): number {
|
|
126
|
+
return CURRENCY_PER_EUR[currency];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function currencySymbol(currency: Currency): string {
|
|
130
|
+
const symbols: Record<Currency, string> = {
|
|
131
|
+
EUR: '€', USD: '$', IDR: 'Rp', JPY: '¥', KRW: '₩', PLN: 'zł', RUB: '₽', SEK: 'kr', TRY: '₺', CNY: '¥',
|
|
132
|
+
};
|
|
133
|
+
return symbols[currency];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function amountUnit(mode: EnergyMode): string {
|
|
137
|
+
return mode === 'electric' ? 'kWh' : 'L';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function consumptionUnit(mode: EnergyMode): string {
|
|
141
|
+
return mode === 'electric' ? 'kWh/100 km' : 'L/100 km';
|
|
142
|
+
}
|