Working site
This commit is contained in:
258
src/pages/customer/profile/TankEstimation.vue
Normal file
258
src/pages/customer/profile/TankEstimation.vue
Normal file
@@ -0,0 +1,258 @@
|
||||
<!-- src/pages/customer/profile/TankEstimation.vue -->
|
||||
<template>
|
||||
<div class="bg-base-100 rounded-lg p-4 border">
|
||||
<h3 class="font-semibold mb-4 flex items-center gap-2">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||
</svg>
|
||||
Fuel Tank Estimation
|
||||
</h3>
|
||||
|
||||
<div v-if="loading" class="flex justify-center items-center py-8">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
</div>
|
||||
|
||||
<div v-else-if="error" class="text-center py-4">
|
||||
<p class="text-sm text-red-600">
|
||||
<span class="font-medium">Estimation Error:</span> {{ error }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="estimation">
|
||||
<div class="space-y-4">
|
||||
<!-- Tank Level Display -->
|
||||
<div>
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<label class="label-text font-medium">Current Tank Level</label>
|
||||
<span class="text-sm text-gray-500">{{ Math.round(estimation.estimated_gallons) }} / {{ Math.round(estimation.tank_size) }} gal</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<progress
|
||||
class="progress w-full"
|
||||
:value="estimation.estimated_gallons"
|
||||
:max="estimation.tank_size"
|
||||
:class="{
|
||||
'progress-success': getTankLevelPercentage() > 60,
|
||||
'progress-warning': getTankLevelPercentage() >= 25 && getTankLevelPercentage() <= 60,
|
||||
'progress-error': getTankLevelPercentage() < 25
|
||||
}"
|
||||
></progress>
|
||||
|
||||
<div class="flex justify-between text-xs text-gray-500 mt-1">
|
||||
<span>Empty</span>
|
||||
<span>{{ Math.round(getTankLevelPercentage()) }}% Full</span>
|
||||
<span>Full</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Usage Information -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="label-text font-medium">Usage Factor</label>
|
||||
<div class="text-lg font-mono">{{ getScalingFactorCategory(estimation.scaling_factor) }}</div>
|
||||
<div class="text-xs text-gray-500">{{ formatScalingFactor(estimation.scaling_factor) }} gallons per degree day</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="label-text font-medium">Daily Usage</label>
|
||||
<div class="text-lg font-mono">{{ calculateDailyUsage() }}</div>
|
||||
<div class="text-xs text-gray-500">Gallons per day</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="text-center py-8 text-gray-500">
|
||||
<svg class="w-12 h-12 mx-auto mb-4 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||
</svg>
|
||||
<p>No fuel estimation data available</p>
|
||||
<p class="text-xs mt-1">Run fuel estimation to see tank levels</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import axios from 'axios'
|
||||
import authHeader from '../../../services/auth.header'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
interface FuelEstimation {
|
||||
id: number;
|
||||
customer_id: number;
|
||||
total_deliveries: number;
|
||||
customer_full_name: string;
|
||||
account_number: string;
|
||||
address: string;
|
||||
estimated_gallons: number;
|
||||
tank_size: number;
|
||||
scaling_factor: number | null;
|
||||
last_5_deliveries: Array<{
|
||||
fill_date: string;
|
||||
gallons_delivered: number;
|
||||
price_per_gallon: number | null;
|
||||
total_amount_customer: number;
|
||||
}>;
|
||||
last_fill?: string | null;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TankEstimation',
|
||||
props: {
|
||||
customerId: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
estimation: null as FuelEstimation | null,
|
||||
loading: true,
|
||||
error: null as string | null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchEstimation()
|
||||
},
|
||||
watch: {
|
||||
customerId: {
|
||||
handler(newId, oldId) {
|
||||
if (newId !== oldId) {
|
||||
console.log('Customer ID changed from', oldId, 'to', newId)
|
||||
this.fetchEstimation()
|
||||
}
|
||||
},
|
||||
immediate: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async fetchEstimation() {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
this.estimation = null // Clear previous data
|
||||
|
||||
try {
|
||||
console.log('Fetching estimation for customer ID:', this.customerId)
|
||||
|
||||
// First check if customer is automatic
|
||||
const customerPath = `${import.meta.env.VITE_BASE_URL}/customer/${this.customerId}`
|
||||
console.log('Checking customer type:', customerPath)
|
||||
const customerResponse = await axios.get(customerPath, { headers: authHeader() })
|
||||
const isAutomatic = customerResponse.data.customer_automatic === 1
|
||||
|
||||
console.log('Customer automatic status:', isAutomatic, customerResponse.data)
|
||||
|
||||
let path: string
|
||||
if (isAutomatic) {
|
||||
// Fetch from automatic delivery API
|
||||
path = `${import.meta.env.VITE_AUTO_URL}/delivery/auto/customer/${this.customerId}`
|
||||
console.log('Fetching automatic data from:', path)
|
||||
} else {
|
||||
// Fetch from customer estimation API
|
||||
path = `${import.meta.env.VITE_AUTO_URL}/fixstuff_customer/estimate_gallons/customer/${this.customerId}`
|
||||
console.log('Fetching customer data from:', path)
|
||||
}
|
||||
|
||||
const response = await axios.get(path, { headers: authHeader() })
|
||||
console.log('API Response:', response.data)
|
||||
|
||||
if (response.data.error) {
|
||||
this.error = response.data.error
|
||||
console.error('API returned error:', response.data.error)
|
||||
} else {
|
||||
if (isAutomatic) {
|
||||
// Transform automatic delivery data to match our interface
|
||||
if (response.data && response.data.id) {
|
||||
const autoData = response.data
|
||||
console.log('Processing automatic data:', autoData)
|
||||
this.estimation = {
|
||||
id: autoData.id,
|
||||
customer_id: autoData.customer_id,
|
||||
total_deliveries: 0, // Not available in auto data
|
||||
customer_full_name: autoData.customer_full_name,
|
||||
account_number: autoData.account_number,
|
||||
address: autoData.customer_address,
|
||||
estimated_gallons: autoData.estimated_gallons_left,
|
||||
tank_size: autoData.tank_size,
|
||||
scaling_factor: autoData.house_factor,
|
||||
last_5_deliveries: [],
|
||||
last_fill: autoData.last_fill
|
||||
}
|
||||
console.log('Set automatic estimation:', this.estimation)
|
||||
} else {
|
||||
console.warn('No automatic delivery data found for customer', this.customerId)
|
||||
this.error = 'No automatic delivery data available'
|
||||
}
|
||||
} else {
|
||||
console.log('Setting customer estimation:', response.data)
|
||||
this.estimation = response.data
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Failed to fetch fuel estimation:', error)
|
||||
if (error.response?.status === 404) {
|
||||
this.error = 'Customer data not found'
|
||||
} else if (error.response?.data?.error) {
|
||||
this.error = error.response.data.error
|
||||
} else {
|
||||
this.error = 'Failed to load fuel estimation data'
|
||||
}
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
getTankLevelPercentage(): number {
|
||||
if (!this.estimation || !this.estimation.tank_size || this.estimation.tank_size === 0) {
|
||||
return 0
|
||||
}
|
||||
return (this.estimation.estimated_gallons / this.estimation.tank_size) * 100
|
||||
},
|
||||
|
||||
calculateDailyUsage(): string {
|
||||
if (!this.estimation || !this.estimation.scaling_factor) {
|
||||
return 'N/A'
|
||||
}
|
||||
// For a typical day with ~20 degree days (moderate winter day)
|
||||
const typicalDegreeDays = 20
|
||||
const dailyUsage = this.estimation.scaling_factor * typicalDegreeDays
|
||||
return dailyUsage.toFixed(1)
|
||||
},
|
||||
|
||||
formatScalingFactor(scalingFactor: number | null): string {
|
||||
if (scalingFactor === null || scalingFactor === undefined) {
|
||||
return 'N/A'
|
||||
}
|
||||
return scalingFactor.toFixed(2)
|
||||
},
|
||||
|
||||
getScalingFactorCategory(scalingFactor: number | null): string {
|
||||
if (scalingFactor === null || scalingFactor === undefined) {
|
||||
return 'N/A'
|
||||
}
|
||||
|
||||
if (scalingFactor < 0.05) {
|
||||
return 'Very Low'
|
||||
} else if (scalingFactor < 0.1) {
|
||||
return 'Low'
|
||||
} else if (scalingFactor < 0.2) {
|
||||
return 'Normal'
|
||||
} else if (scalingFactor < 0.5) {
|
||||
return 'High'
|
||||
} else {
|
||||
return 'Very High'
|
||||
}
|
||||
},
|
||||
|
||||
formatDate(dateString: string): string {
|
||||
if (!dateString) return 'N/A'
|
||||
return dayjs(dateString).format('MMM D, YYYY')
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -98,6 +98,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TankEstimation :customer-id="customer.id" />
|
||||
|
||||
<CustomerComments :comments="comments" @add-comment="onSubmitSocial" @delete-comment="deleteCustomerSocial" />
|
||||
<CustomerStats :stats="customer_stats" :last_delivery="customer_last_delivery" />
|
||||
<TankInfo :customer_id="customer.id" :tank="customer_tank" :description="customer_description" />
|
||||
@@ -264,6 +266,7 @@ import EquipmentParts from './profile/EquipmentParts.vue';
|
||||
import CreditCards from './profile/CreditCards.vue';
|
||||
import CustomerComments from './profile/CustomerComments.vue';
|
||||
import HistoryTabs from './profile/HistoryTabs.vue';
|
||||
import TankEstimation from './TankEstimation.vue';
|
||||
|
||||
|
||||
L.Icon.Default.mergeOptions({
|
||||
@@ -352,6 +355,7 @@ export default defineComponent({
|
||||
CreditCards,
|
||||
CustomerComments,
|
||||
HistoryTabs,
|
||||
TankEstimation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -50,9 +50,6 @@
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="grid grid-cols-12">
|
||||
<div class="col-span-6 ">
|
||||
<div class="col-span-12 pl-5">Auburn Oil</div>
|
||||
@@ -90,7 +87,7 @@
|
||||
<div class="col-span-12 h-7 pl-4 pt-2"></div>
|
||||
<div class="col-span-12 h-7 pl-4 pt-2"></div>
|
||||
<div class="col-span-12 h-7 pl-4 pt-2" ></div>
|
||||
<div class="col-span-12 h-7 pl-4 pt-2" >{{todays_price }}</div>
|
||||
<div class="col-span-12 h-7 pl-4 pt-2" ></div>
|
||||
<div class="col-span-12 h-7 pl-4 pt-4" > </div>
|
||||
<div class="col-span-12 h-7 pt-6"></div>
|
||||
<div class="col-span-12 h-7"></div>
|
||||
|
||||
Reference in New Issue
Block a user