initial commit
This commit is contained in:
40
resources/js/pages/analytics/ProductsAnalyticsTable.vue
Normal file
40
resources/js/pages/analytics/ProductsAnalyticsTable.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore();
|
||||
const OrdersData = ref([]);
|
||||
onMounted(() => {
|
||||
OrdersData.value = store.getters.getProductsAnalytics.orders;
|
||||
console.log("OrdersData onMounted:", OrdersData.value);
|
||||
});
|
||||
|
||||
const headers = [
|
||||
{ title: '#Product', key: 'product_id' },
|
||||
{ title: 'Name', key: 'product_name' },
|
||||
{ title: 'Amount', key: 'total_amount' },
|
||||
{ title: 'Orders', key: 'total_orders' },
|
||||
{ title: 'Item sold', key: 'total_item_sold' },
|
||||
];
|
||||
|
||||
|
||||
const formatAmount = (amount) => {
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD'
|
||||
}).format(amount);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VDataTable :headers="headers" :items="store.getters.getProductsAnalytics.orders" :items-per-page="5"
|
||||
class="text-no-wrap">
|
||||
<template #item.product_id="{ item }">
|
||||
<span class="text-h6">{{ item.product_id }}</span>
|
||||
</template>
|
||||
<template #item.total_amount="{ item }">
|
||||
<span class="text-h6">{{ formatAmount(item.total_amount) }}</span>
|
||||
</template>
|
||||
</VDataTable>
|
||||
</VCard>
|
||||
</template>
|
33
resources/js/pages/analytics/apexchart.vue
Normal file
33
resources/js/pages/analytics/apexchart.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup>
|
||||
import ApexChartBalance from '@/views/charts/apex-chart/ApexChartBalance.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow id="apex-chart-wrapper">
|
||||
|
||||
|
||||
<!-- 👉 Balance Line Chart -->
|
||||
<VCol cols="12">
|
||||
<ApexChartBalance />
|
||||
</VCol>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</VRow>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@core-scss/template/libs/apex-chart.scss";
|
||||
|
||||
.date-picker-wrapper {
|
||||
inline-size: 10.5rem;
|
||||
}
|
||||
|
||||
#apex-chart-wrapper {
|
||||
.v-card-item__append {
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
33
resources/js/pages/analytics/apexchartOrder.vue
Normal file
33
resources/js/pages/analytics/apexchartOrder.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup>
|
||||
import ApexChartOrderBalance from '@/views/charts/apex-chart/ApexChartOrderBalance.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow id="apex-chart-wrapper">
|
||||
|
||||
|
||||
<!-- 👉 Balance Line Chart -->
|
||||
<VCol cols="12">
|
||||
<ApexChartOrderBalance />
|
||||
</VCol>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</VRow>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@core-scss/template/libs/apex-chart.scss";
|
||||
|
||||
.date-picker-wrapper {
|
||||
inline-size: 10.5rem;
|
||||
}
|
||||
|
||||
#apex-chart-wrapper {
|
||||
.v-card-item__append {
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
235
resources/js/pages/analytics/dashboardTable.vue
Normal file
235
resources/js/pages/analytics/dashboardTable.vue
Normal file
@@ -0,0 +1,235 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import * as XLSX from 'xlsx';
|
||||
const store = useStore();
|
||||
const OrdersData = ref([]);
|
||||
// const isExpanded = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
downloadable: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
onMounted(() => {
|
||||
OrdersData.value = store.getters.getOverviewOrder;
|
||||
console.log("OrdersData onMounted:", OrdersData.value);
|
||||
});
|
||||
|
||||
const headers = [
|
||||
{ title: 'Date', key: 'date' },
|
||||
{ title: '#Order', key: 'order_id' },
|
||||
{ title: 'Status', key: 'status' },
|
||||
{ title: 'Patient', key: 'patient_name' },
|
||||
{ title: 'Patient type', key: 'customer_type' },
|
||||
{ title: 'Product(s)', key: 'products' },
|
||||
{ title: 'Item sold', key: 'item_sold' },
|
||||
{ title: 'Net Sale', key: 'total_amount' },
|
||||
{ title: 'Attribution', key: 'attribution' },
|
||||
];
|
||||
|
||||
function changeFormat(dateFormat) {
|
||||
const dateParts = dateFormat.split('-');
|
||||
const year = parseInt(dateParts[0]);
|
||||
const month = parseInt(dateParts[1]);
|
||||
const day = parseInt(dateParts[2]);
|
||||
const date = new Date(year, month - 1, day);
|
||||
return `${month}-${day}-${date.getFullYear()}`;
|
||||
}
|
||||
|
||||
const getStatusColor = (status) => {
|
||||
switch (status) {
|
||||
case "pending":
|
||||
return "warning";
|
||||
case "shipped":
|
||||
return "primary";
|
||||
case "delivered":
|
||||
return "success";
|
||||
case "cancelled":
|
||||
return "error";
|
||||
default:
|
||||
return "gray";
|
||||
}
|
||||
};
|
||||
// const tableData = computed(() => {
|
||||
// let d = store.getters.getOverviewOrder.map((order) => ({
|
||||
// ...order,
|
||||
// products:order.products
|
||||
|
||||
|
||||
// }));
|
||||
// return d;
|
||||
// });
|
||||
|
||||
const downloadExcel = () => {
|
||||
const data = store.getters.getOverviewOrder.map(order => ({
|
||||
'Date': changeFormat(order.date),
|
||||
'#Order': order.order_id,
|
||||
'Status': order.status,
|
||||
'Patient': order.patient_name,
|
||||
'Customer type': order.customer_type,
|
||||
'Product(s)': order.products,
|
||||
'Item sold': order.item_sold,
|
||||
'Net Sale': order.total_amount,
|
||||
'Attribution': order.attribution,
|
||||
}));
|
||||
|
||||
console.log('Mapped Data:', data);
|
||||
|
||||
const worksheet = XLSX.utils.json_to_sheet(data);
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
headers.map(header => header.title)
|
||||
], { origin: 'A1' });
|
||||
XLSX.utils.sheet_add_json(worksheet, data, { origin: 'A2', skipHeader: true });
|
||||
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, 'Orders');
|
||||
XLSX.writeFile(workbook, 'OrdersData.xlsx');
|
||||
};
|
||||
|
||||
|
||||
// const isLongText = computed(() => {
|
||||
// console.log("currentText",currentText.value.length);
|
||||
// return currentText.value.length > 20;
|
||||
// });
|
||||
const currentText = ref();
|
||||
const expandedItems = ref(new Map());
|
||||
const isLongText = (item) => {
|
||||
return item.length > 20;
|
||||
}
|
||||
// Display text based on whether it's expanded
|
||||
const displayText = (item) => {
|
||||
const isExpanded = expandedItems.value.get(item);
|
||||
return isExpanded || !isLongText(item)
|
||||
? item
|
||||
: item.slice(0, 20) + '...';
|
||||
};
|
||||
const toggleText = (item) => {
|
||||
const currentState = expandedItems.value.get(item) || false;
|
||||
expandedItems.value.set(item, !currentState);
|
||||
}
|
||||
|
||||
// Function to check if item is expanded
|
||||
const isExpanded = (item) =>{
|
||||
return expandedItems.value.get(item) || false;
|
||||
}
|
||||
// const toggleText = (item) => {
|
||||
// currentText.value = item;
|
||||
// // alert(isExpanded.value);
|
||||
// if(isExpanded.value == false){
|
||||
// isExpanded.value == true;
|
||||
// return isExpanded.value || !isLongText.value
|
||||
// ? item
|
||||
// : item.slice(0, 20) + '...';
|
||||
|
||||
// }
|
||||
// if(isExpanded.value || !isLongText.value){
|
||||
// return isExpanded.value || !isLongText.value
|
||||
// ? item
|
||||
// : item.slice(0, 20) + '...';
|
||||
// }
|
||||
// };
|
||||
|
||||
// Toggle text display
|
||||
// const toggleText = () => {
|
||||
// isExpanded.value = !isExpanded.value;
|
||||
// alert(isExpanded.value);
|
||||
// }
|
||||
|
||||
// const isLongText = computed(() => props.item.products.length > 30);
|
||||
// const displayText = (item) => {
|
||||
// if(item.length >= 20){
|
||||
// isExpanded.value = false;
|
||||
// return item.slice(0, 20) + '...';
|
||||
|
||||
// }else{
|
||||
// isExpanded.value = true;
|
||||
// return item;
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
// const toggleText = (isExp) => {
|
||||
// alert(isExp);
|
||||
|
||||
// };
|
||||
const formatOrderId = (id) => {
|
||||
if (id >= 1 && id <= 9) {
|
||||
return id.toString().padStart(4, '0');
|
||||
} else if (id >= 10 && id <= 99) {
|
||||
return id.toString().padStart(4, '0');
|
||||
} else if (id >= 100 && id <= 999) {
|
||||
return id.toString().padStart(4, '0');
|
||||
} else {
|
||||
return id; // or handle cases for IDs outside these ranges
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VRow v-if="props.downloadable">
|
||||
<VCol cols="12" >
|
||||
<VBtn @click="downloadExcel" class="float-right mt-2 mb-2 mr-2" color="black" variant="text" v-if="$can('read', 'Analytics Orders Download Data')">
|
||||
<VIcon start icon="ri-download-cloud-fill" />Download
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VDataTable
|
||||
:headers="headers"
|
||||
:items="store.getters.getOverviewOrder"
|
||||
:items-per-page="5"
|
||||
class="text-no-wrap"
|
||||
>
|
||||
<template #item.order_id="{ item }">
|
||||
<RouterLink :to="{ name: 'admin-order-detail', params: { id: item.order_id } }">
|
||||
<span class="text-h6 text-primary">{{ formatOrderId(item.order_id) }}</span>
|
||||
</RouterLink>
|
||||
|
||||
</template>
|
||||
<template #item.date="{ item }">
|
||||
<span class="text-h6">{{ changeFormat(item.date) }}</span>
|
||||
</template>
|
||||
<template #item.total_amount="{ item }">
|
||||
${{ parseFloat(item.total_amount).toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}) }}
|
||||
<!-- <span class="text-h6">{{ '$'+item.total_amount }}</span> -->
|
||||
</template>
|
||||
<template #item.status="{ item }">
|
||||
<span>
|
||||
<VChip variant="tonal" :color="getStatusColor(item.status)" size="small">
|
||||
{{ item.status }}
|
||||
</VChip>
|
||||
</span>
|
||||
</template>
|
||||
<template #item.products="{ item }">
|
||||
<div>
|
||||
<!-- Display truncated or full text based on isExpanded -->
|
||||
<span style="white-space: normal; word-break: break-word; width:100px">
|
||||
{{ displayText(item.products) }}
|
||||
<!-- {{ item.products }} -->
|
||||
</span>
|
||||
<!-- Conditionally render Show More/Show Less button -->
|
||||
<button v-if="isLongText(item.products)" @click="toggleText(item.products)" style="font-size: 12px">
|
||||
{{ isExpanded(item.products) ? 'Show Less' : 'Show More' }}
|
||||
</button>
|
||||
</div>
|
||||
<!-- <span style="white-space: normal;word-break: break-word;">
|
||||
{{ displayText(item.products) }}
|
||||
|
||||
</span>
|
||||
<button size="small" style="font-size: 10px;">
|
||||
{{ isExpanded ? 'Show Less' : 'Show More' }}
|
||||
</button> -->
|
||||
</template>
|
||||
<template #item.item_sold="{ item }">
|
||||
<span style="white-space: normal;word-break: break-word;">
|
||||
{{ item.item_sold }}
|
||||
</span>
|
||||
</template>
|
||||
</VDataTable>
|
||||
</VCard>
|
||||
</template>
|
229
resources/js/pages/analytics/orderTable.vue
Normal file
229
resources/js/pages/analytics/orderTable.vue
Normal file
@@ -0,0 +1,229 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import * as XLSX from 'xlsx';
|
||||
const store = useStore();
|
||||
const OrdersData = ref([]);
|
||||
// const isExpanded = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
downloadable: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
onMounted(() => {
|
||||
OrdersData.value = store.getters.getOverviewOrderData;
|
||||
console.log("OrdersData onMounted:", OrdersData.value);
|
||||
});
|
||||
|
||||
const headers = [
|
||||
{ title: 'Date', key: 'order_date' },
|
||||
{ title: '#Order', key: 'order_id' },
|
||||
{ title: 'Status', key: 'order_status' },
|
||||
{ title: 'Patient', key: 'patient_name' },
|
||||
{ title: 'Item sold', key: 'item_sold' },
|
||||
{ title: 'Amount', key: 'total_amount' },
|
||||
|
||||
];
|
||||
|
||||
function changeFormat(dateFormat) {
|
||||
const dateParts = dateFormat.split('-');
|
||||
const year = parseInt(dateParts[0]);
|
||||
const month = parseInt(dateParts[1]);
|
||||
const day = parseInt(dateParts[2]);
|
||||
const date = new Date(year, month - 1, day);
|
||||
return `${month}-${day}-${date.getFullYear()}`;
|
||||
}
|
||||
|
||||
function formatDate(dateTime) {
|
||||
if (!dateTime) return '';
|
||||
|
||||
// Split date and time parts
|
||||
const [datePart, timePart] = dateTime.split(' ');
|
||||
|
||||
// Split date into parts
|
||||
const [year, month, day] = datePart.split('-').map(Number);
|
||||
|
||||
// Split time into parts
|
||||
const [hour, minute, second] = timePart.split(':').map(Number);
|
||||
|
||||
// Format the date and time
|
||||
return `${month}-${day}-${year}`;
|
||||
}
|
||||
const getStatusColor = (status) => {
|
||||
switch (status) {
|
||||
case "pending":
|
||||
return "warning";
|
||||
case "shipped":
|
||||
return "primary";
|
||||
case "delivered":
|
||||
return "success";
|
||||
case "cancelled":
|
||||
return "error";
|
||||
default:
|
||||
return "gray";
|
||||
}
|
||||
};
|
||||
// const tableData = computed(() => {
|
||||
// let d = store.getters.getOverviewOrder.map((order) => ({
|
||||
// ...order,
|
||||
// products:order.products
|
||||
|
||||
|
||||
// }));
|
||||
// return d;
|
||||
// });
|
||||
|
||||
const downloadExcel = () => {
|
||||
const data = store.getters.getOverviewOrderData.map(order => ({
|
||||
// 'Date': changeFormat(order.date),
|
||||
'Date': formatDate(order.order_date),
|
||||
'#Order': order.order_id,
|
||||
'Status': order.order_status,
|
||||
'Patient': order.patient_name,
|
||||
// 'Customer type': order.customer_type,
|
||||
// 'Product(s)': order.products,
|
||||
'Item sold': order.item_sold,
|
||||
'Net Sale': order.total_amount,
|
||||
// 'Attribution': order.attribution,
|
||||
}));
|
||||
|
||||
console.log('Mapped Data:', data);
|
||||
|
||||
const worksheet = XLSX.utils.json_to_sheet(data);
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
headers.map(header => header.title)
|
||||
], { origin: 'A1' });
|
||||
XLSX.utils.sheet_add_json(worksheet, data, { origin: 'A2', skipHeader: true });
|
||||
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, 'Orders');
|
||||
XLSX.writeFile(workbook, 'OrdersData.xlsx');
|
||||
};
|
||||
|
||||
|
||||
// const isLongText = computed(() => {
|
||||
// console.log("currentText",currentText.value.length);
|
||||
// return currentText.value.length > 20;
|
||||
// });
|
||||
const currentText = ref();
|
||||
const expandedItems = ref(new Map());
|
||||
const isLongText = (item) => {
|
||||
return item.length > 20;
|
||||
}
|
||||
// Display text based on whether it's expanded
|
||||
const displayText = (item) => {
|
||||
const isExpanded = expandedItems.value.get(item);
|
||||
return isExpanded || !isLongText(item)
|
||||
? item
|
||||
: item.slice(0, 20) + '...';
|
||||
};
|
||||
const toggleText = (item) => {
|
||||
const currentState = expandedItems.value.get(item) || false;
|
||||
expandedItems.value.set(item, !currentState);
|
||||
}
|
||||
|
||||
// Function to check if item is expanded
|
||||
const isExpanded = (item) =>{
|
||||
return expandedItems.value.get(item) || false;
|
||||
}
|
||||
// const toggleText = (item) => {
|
||||
// currentText.value = item;
|
||||
// // alert(isExpanded.value);
|
||||
// if(isExpanded.value == false){
|
||||
// isExpanded.value == true;
|
||||
// return isExpanded.value || !isLongText.value
|
||||
// ? item
|
||||
// : item.slice(0, 20) + '...';
|
||||
|
||||
// }
|
||||
// if(isExpanded.value || !isLongText.value){
|
||||
// return isExpanded.value || !isLongText.value
|
||||
// ? item
|
||||
// : item.slice(0, 20) + '...';
|
||||
// }
|
||||
// };
|
||||
|
||||
// Toggle text display
|
||||
// const toggleText = () => {
|
||||
// isExpanded.value = !isExpanded.value;
|
||||
// alert(isExpanded.value);
|
||||
// }
|
||||
|
||||
// const isLongText = computed(() => props.item.products.length > 30);
|
||||
// const displayText = (item) => {
|
||||
// if(item.length >= 20){
|
||||
// isExpanded.value = false;
|
||||
// return item.slice(0, 20) + '...';
|
||||
|
||||
// }else{
|
||||
// isExpanded.value = true;
|
||||
// return item;
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
// const toggleText = (isExp) => {
|
||||
// alert(isExp);
|
||||
|
||||
// };
|
||||
const formatOrderId = (id) => {
|
||||
if (id >= 1 && id <= 9) {
|
||||
return id.toString().padStart(4, '0');
|
||||
} else if (id >= 10 && id <= 99) {
|
||||
return id.toString().padStart(4, '0');
|
||||
} else if (id >= 100 && id <= 999) {
|
||||
return id.toString().padStart(4, '0');
|
||||
} else {
|
||||
return id; // or handle cases for IDs outside these ranges
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VRow v-if="props.downloadable">
|
||||
<VCol cols="12" >
|
||||
<VBtn @click="downloadExcel" class="float-right mt-2 mb-2 mr-2" color="black" variant="text" v-if="$can('read', 'Analytics Orders Download Data')">
|
||||
<VIcon start icon="ri-download-cloud-fill" />Download
|
||||
</VBtn>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VDataTable
|
||||
:headers="headers"
|
||||
:items="store.getters.getOverviewOrderData"
|
||||
:items-per-page="5"
|
||||
class="text-no-wrap"
|
||||
>
|
||||
<template #item.order_id="{ item }">
|
||||
<RouterLink :to="{ name: 'admin-order-detail', params: { id: item.order_id } }">
|
||||
<span class="text-h6 text-primary">{{ formatOrderId(item.order_id) }}</span>
|
||||
</RouterLink>
|
||||
|
||||
</template>
|
||||
<template #item.order_date="{ item }">
|
||||
<span class="text-h6">{{ changeFormat(item.order_date) }}</span>
|
||||
</template>
|
||||
<template #item.total_amount="{ item }">
|
||||
{{ '$' + (item.total_amount !== null ? parseFloat(item.total_amount).toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}) : 0) }}
|
||||
</template>
|
||||
<template #item.order_status="{ item }">
|
||||
<span>
|
||||
<VChip variant="tonal" :color="getStatusColor(item.order_status)" size="small">
|
||||
{{ item.order_status }}
|
||||
</VChip>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #item.item_sold="{ item }">
|
||||
<span style="white-space: normal;word-break: break-word;">
|
||||
{{ item.item_sold }}
|
||||
</span>
|
||||
</template>
|
||||
</VDataTable>
|
||||
</VCard>
|
||||
</template>
|
168
resources/js/pages/analytics/orders.vue
Normal file
168
resources/js/pages/analytics/orders.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<script setup>
|
||||
import ApexChart from '@/pages/analytics/apexchart.vue';
|
||||
import DashboardTable from '@/pages/analytics/dashboardTable.vue';
|
||||
import LogisticsCardStatistics from '@/views/apps/logistics/LogisticsCardStatistics.vue';
|
||||
import { computed, onBeforeMount, ref } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
const store = useStore();
|
||||
const date = ref('');
|
||||
const orderStartdate = ref('');
|
||||
const orderEnddate = ref('');
|
||||
const orderData = ref([]);
|
||||
const analyticsData = ref(null);
|
||||
const patientData = ref([]);
|
||||
|
||||
const filter = ref({
|
||||
patient: 'all',
|
||||
order_status: 'all',
|
||||
});
|
||||
|
||||
// Change this to a regular function that returns a computed ref
|
||||
const useSortedPatient = () => {
|
||||
const isLoading = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
const sortedPatient = computed(() => {
|
||||
const allOption = { id: 'all', patient_name: 'All' };
|
||||
const sortedData = patientData.value.slice().sort((a, b) => {
|
||||
return a.patient_name.localeCompare(b.patient_name);
|
||||
});
|
||||
return [allOption, ...sortedData];
|
||||
});
|
||||
|
||||
const fetchPatientData = async () => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
await store.dispatch('getAnalyticOrderFilters');
|
||||
patientData.value = store.getters.getOrderFilters || [];
|
||||
console.log('Fetched patient data:', patientData.value);
|
||||
} catch (e) {
|
||||
console.error('Error fetching patient data:', e);
|
||||
error.value = 'Failed to fetch patient data';
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(fetchPatientData);
|
||||
|
||||
return { sortedPatient, isLoading, error, fetchPatientData };
|
||||
};
|
||||
|
||||
const { sortedPatient, isLoading, error, fetchPatientData } = useSortedPatient();
|
||||
|
||||
const setDateRange = () => {
|
||||
const today = new Date();
|
||||
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
date.value = [startOfMonth, today];
|
||||
console.log("xxxxxxxx", date.value);
|
||||
};
|
||||
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
setDateRange();
|
||||
const now = new Date();
|
||||
let startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const currentDate = formatDate(now);
|
||||
const monthStart = formatDate(startOfMonth);
|
||||
orderStartdate.value = monthStart;
|
||||
orderEnddate.value = currentDate;
|
||||
await fetchOrder();
|
||||
});
|
||||
|
||||
const fetchOrder = async () => {
|
||||
await store.dispatch('getAdminAnalyticsOrder', {
|
||||
start_date: orderStartdate.value,
|
||||
end_date: orderEnddate.value,
|
||||
patientId: filter.value.patient,
|
||||
order_status: filter.value.order_status
|
||||
});
|
||||
};
|
||||
|
||||
const changeDateRange = async () => {
|
||||
console.log('changed date', date.value, 'type:', typeof date.value);
|
||||
try {
|
||||
const dateString = typeof date.value === 'string' ? date.value : '';
|
||||
const [startDate, endDate] = dateString.split(" to ");
|
||||
if (startDate && endDate) {
|
||||
orderStartdate.value = startDate;
|
||||
orderEnddate.value = endDate;
|
||||
await fetchOrder();
|
||||
} else {
|
||||
console.warn('Invalid date range');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing date range:', error);
|
||||
}
|
||||
};
|
||||
const order_status = [
|
||||
{ title: 'All', slug: 'all' },
|
||||
{ title: 'Pending', slug: 'pending' },
|
||||
{ title: 'On hold', slug: 'on hold' },
|
||||
{ title: 'Completed', slug: 'completed' },
|
||||
{ title: 'Canceled', slug: 'canceled' },
|
||||
{ title: 'Failed', slug: 'failed' },
|
||||
{ title: 'Refunded', slug: 'refunded' }
|
||||
];
|
||||
|
||||
const onOrderStatusChange = () => {
|
||||
fetchOrder();
|
||||
};
|
||||
|
||||
const onPatientChange = () => {
|
||||
fetchOrder();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow class="match-height">
|
||||
<VCol cols="12" md="4" class="px-3">
|
||||
<AppDateTimePicker v-model="date" label="Date Range" :config="{ mode: 'range' }" @change="changeDateRange" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="3">
|
||||
<VAutocomplete v-model="filter.patient" label="Patient" placeholder="Patient" density="comfortable"
|
||||
:items="sortedPatient" item-title="patient_name" item-value="id" :loading="isLoading" :error-messages="error"
|
||||
@update:model-value="onPatientChange" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="3">
|
||||
<VAutocomplete v-model="filter.order_status" label="Order Status" density="comfortable" :items="order_status"
|
||||
placeholder="Order Status" item-title="title" item-value="slug" @update:model-value="onOrderStatusChange" />
|
||||
<!-- <VSelect
|
||||
v-model="filter.order_status"
|
||||
label="Order Status"
|
||||
placeholder="Order Status"
|
||||
density="comfortable"
|
||||
:items="order_status"
|
||||
item-title="title"
|
||||
item-value="slug"
|
||||
@update:model-value="onOrderStatusChange"
|
||||
/> -->
|
||||
</VCol>
|
||||
<VCol cols="12" md="12">
|
||||
<LogisticsCardStatistics :overview="store.getters.getAnalyticsOverview" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="12">
|
||||
<VCard title="Chart">
|
||||
<VCardText>
|
||||
<ApexChart />
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol cols="12" md="12">
|
||||
<VCardTitle>
|
||||
Leadboards
|
||||
</VCardTitle>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<DashboardTable :downloadable="true" />
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
181
resources/js/pages/analytics/overview-order.vue
Normal file
181
resources/js/pages/analytics/overview-order.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<script setup>
|
||||
// import ApexChart from '@/pages/analytics/apexchart.vue';
|
||||
import ApexChartOrder from '@/pages/analytics/apexchartOrder.vue';
|
||||
import OverViewOrderTable from '@/pages/analytics/orderTable.vue';
|
||||
import LogisticsOrderCardStatistics from '@/views/apps/logistics/LogisticsCardStatisticsOrder.vue';
|
||||
import { computed, onBeforeMount, ref } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
const store = useStore();
|
||||
const date = ref('');
|
||||
const orderStartdate = ref('');
|
||||
const orderEnddate = ref('');
|
||||
const orderData = ref([]);
|
||||
const analyticsData = ref(null);
|
||||
const patientData = ref([]);
|
||||
|
||||
const filter = ref({
|
||||
patient: 'all',
|
||||
order_status: 'all',
|
||||
});
|
||||
|
||||
// Change this to a regular function that returns a computed ref
|
||||
const useSortedPatient = () => {
|
||||
const isLoading = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
const sortedPatient = computed(() => {
|
||||
const allOption = { id: 'all', patient_name: 'All' };
|
||||
const sortedData = patientData.value.slice().sort((a, b) => {
|
||||
return a.patient_name.localeCompare(b.patient_name);
|
||||
});
|
||||
return [allOption, ...sortedData];
|
||||
});
|
||||
|
||||
const fetchPatientData = async () => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
await store.dispatch('getAnalyticOrderFilters');
|
||||
patientData.value = store.getters.getOrderFilters || [];
|
||||
console.log('Fetched patient data:', patientData.value);
|
||||
} catch (e) {
|
||||
console.error('Error fetching patient data:', e);
|
||||
error.value = 'Failed to fetch patient data';
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(fetchPatientData);
|
||||
|
||||
return { sortedPatient, isLoading, error, fetchPatientData };
|
||||
};
|
||||
|
||||
const { sortedPatient, isLoading, error, fetchPatientData } = useSortedPatient();
|
||||
|
||||
const setDateRange = () => {
|
||||
const today = new Date();
|
||||
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
date.value = [startOfMonth, today];
|
||||
console.log("xxxxxxxx", date.value);
|
||||
};
|
||||
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
let productRange = store.getters.getCurrentFilterDate.filter_date;
|
||||
console.log("productRangeOrder",productRange);
|
||||
if(productRange){
|
||||
try {
|
||||
date.value = productRange;
|
||||
const dateString = typeof productRange === 'string' ? productRange : '';
|
||||
const [startDate, endDate] = dateString.split(" to ");
|
||||
if (startDate && endDate) {
|
||||
orderStartdate.value = startDate;
|
||||
orderEnddate.value = endDate;
|
||||
await fetchOrder();
|
||||
} else {
|
||||
console.warn('Invalid date range');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing date range:', error);
|
||||
}
|
||||
await store.dispatch('getAllProductsList');
|
||||
await fetchOrder();
|
||||
|
||||
}else{
|
||||
setDateRange();
|
||||
const now = new Date();
|
||||
let startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const currentDate = formatDate(now);
|
||||
const monthStart = formatDate(startOfMonth);
|
||||
orderStartdate.value = monthStart;
|
||||
orderEnddate.value = currentDate;
|
||||
await fetchOrder();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const fetchOrder = async () => {
|
||||
await store.dispatch('getAdminAnalyticsOverviewOrder', {
|
||||
start_date: orderStartdate.value,
|
||||
end_date: orderEnddate.value,
|
||||
});
|
||||
console.log("getAnalyticsOverviewOrder",store.getters.getAnalyticsOverviewOrder);
|
||||
};
|
||||
|
||||
const changeDateRange = async () => {
|
||||
console.log('changed date', date.value, 'type:', typeof date.value);
|
||||
try {
|
||||
const dateString = typeof date.value === 'string' ? date.value : '';
|
||||
const [startDate, endDate] = dateString.split(" to ");
|
||||
if (startDate && endDate) {
|
||||
orderStartdate.value = startDate;
|
||||
orderEnddate.value = endDate;
|
||||
await fetchOrder();
|
||||
} else {
|
||||
console.warn('Invalid date range');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing date range:', error);
|
||||
}
|
||||
};
|
||||
const order_status = [
|
||||
{ title: 'All', slug: 'all' },
|
||||
{ title: 'Pending', slug: 'pending' },
|
||||
{ title: 'On hold', slug: 'on hold' },
|
||||
{ title: 'Completed', slug: 'completed' },
|
||||
{ title: 'Canceled', slug: 'canceled' },
|
||||
{ title: 'Failed', slug: 'failed' },
|
||||
{ title: 'Refunded', slug: 'refunded' }
|
||||
];
|
||||
|
||||
const onOrderStatusChange = () => {
|
||||
fetchOrder();
|
||||
};
|
||||
|
||||
const onPatientChange = () => {
|
||||
fetchOrder();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow class="match-height">
|
||||
<VCol cols="12" md="4" class="px-3">
|
||||
<AppDateTimePicker v-model="date" label="Date Range" :config="{ mode: 'range' }" @change="changeDateRange" />
|
||||
</VCol>
|
||||
<!-- <VCol cols="12" md="3">
|
||||
<VAutocomplete v-model="filter.patient" label="Patient" placeholder="Patient" density="comfortable"
|
||||
:items="sortedPatient" item-title="patient_name" item-value="id" :loading="isLoading" :error-messages="error"
|
||||
@update:model-value="onPatientChange" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="3">
|
||||
<VAutocomplete v-model="filter.order_status" label="Order Status" density="comfortable" :items="order_status"
|
||||
placeholder="Order Status" item-title="title" item-value="slug" @update:model-value="onOrderStatusChange" />
|
||||
</VCol> -->
|
||||
<VCol cols="12" md="12">
|
||||
<LogisticsOrderCardStatistics :overview="store.getters.getAnalyticsOverviewOrder" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="12">
|
||||
<VCard title="Chart">
|
||||
<VCardText>
|
||||
<ApexChartOrder />
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol cols="12" md="12">
|
||||
<VCardTitle>
|
||||
Leadboards
|
||||
</VCardTitle>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<OverViewOrderTable :downloadable="true" />
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
239
resources/js/pages/analytics/overview.vue
Normal file
239
resources/js/pages/analytics/overview.vue
Normal file
@@ -0,0 +1,239 @@
|
||||
<script setup>
|
||||
import ApexChart from '@/pages/analytics/apexchart.vue';
|
||||
import DashboardTable from '@/pages/analytics/dashboardTable.vue';
|
||||
import LogisticsCardStatistics from '@/views/apps/logistics/LogisticsCardStatistics.vue';
|
||||
import { useStore } from 'vuex';
|
||||
const store = useStore()
|
||||
const date = ref('')
|
||||
const orderData = ref([]);
|
||||
const analyticsData = ref(null);
|
||||
const chartJsCustomColors = {
|
||||
white: '#fff',
|
||||
yellow: '#ffe802',
|
||||
primary: '#836af9',
|
||||
areaChartBlue: '#2c9aff',
|
||||
barChartYellow: '#ffcf5c',
|
||||
polarChartGrey: '#4f5d70',
|
||||
polarChartInfo: '#299aff',
|
||||
lineChartYellow: '#d4e157',
|
||||
polarChartGreen: '#28dac6',
|
||||
lineChartPrimary: '#9e69fd',
|
||||
lineChartWarning: '#ff9800',
|
||||
horizontalBarInfo: '#26c6da',
|
||||
polarChartWarning: '#ff8131',
|
||||
scatterChartGreen: '#28c76f',
|
||||
warningShade: '#ffbd1f',
|
||||
areaChartBlueLight: '#84d0ff',
|
||||
areaChartGreyLight: '#edf1f4',
|
||||
scatterChartWarning: '#ff9f43',
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
setDateRange();
|
||||
const now = new Date()
|
||||
let startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
const currentDate = formatDate(now)
|
||||
const monthStart = formatDate(startOfMonth)
|
||||
console.log(date.value[0]);
|
||||
// const formattedDates = date.value.map(formatDate);
|
||||
// console.log('Default date',formattedDates[0],formattedDates[1])
|
||||
await store.dispatch('getAdminAnalyticsOverview', {
|
||||
start_date:monthStart,
|
||||
end_date:currentDate,
|
||||
})
|
||||
orderData.value = store.getters.getAnalyticsOverview.orders;
|
||||
console.log("orderData",orderData.value);
|
||||
});
|
||||
|
||||
// const formatDate = (dateString) => {
|
||||
// const date = new Date(dateString);
|
||||
// return date.toISOString().split('T')[0];
|
||||
// };
|
||||
const selectedDate = ref();
|
||||
const setDateRange = () => {
|
||||
const today = new Date();
|
||||
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
|
||||
// Set the date range
|
||||
// date.value = [startOfMonth, today];
|
||||
date.value = formatDate(startOfMonth) + ' to ' + formatDate(today);
|
||||
|
||||
console.log("helllowwewew",date.value, formatDate(startOfMonth) + ' to ' + formatDate(today));
|
||||
};
|
||||
const formatDate = (date) => {
|
||||
const month = date.getMonth() + 1; // Months are zero-indexed
|
||||
const day = date.getDate();
|
||||
const year = date.getFullYear();
|
||||
|
||||
// Pad month and day with leading zeros if needed
|
||||
const formattedMonth = month.toString().padStart(2, '0');
|
||||
const formattedDay = day.toString().padStart(2, '0');
|
||||
// console.log('xnmzcnmasdasdas',`${formattedMonth}-${formattedDay}-${year}`);
|
||||
return `${year}-${formattedMonth}-${formattedDay}`;
|
||||
}
|
||||
const changeDateRange = async () => {
|
||||
|
||||
// console.log('shgdhasgdshla',store.getters.getCurrentFilterDate);
|
||||
console.log('changed date', date.value, 'type:', typeof date.value);
|
||||
|
||||
try {
|
||||
const dateString = typeof date.value === 'string' ? date.value : '';
|
||||
const [startDate, endDate] = dateString.split(" to ");
|
||||
|
||||
if (startDate && endDate) {
|
||||
await store.dispatch('getAdminAnalyticsOverview', {
|
||||
start_date: startDate,
|
||||
end_date: endDate,
|
||||
});
|
||||
analyticsData.value = store.getters.getAnalyticsOverview;
|
||||
} else {
|
||||
console.warn('Invalid date range');
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing date range:', error);
|
||||
|
||||
}
|
||||
};
|
||||
const standardPlan = {
|
||||
plan: 'Standard',
|
||||
price: 99,
|
||||
benefits: [
|
||||
'10 Users',
|
||||
'Up to 10GB storage',
|
||||
'Basic Support',
|
||||
],
|
||||
}
|
||||
const porgressPercentage = (value) => {
|
||||
if(value){
|
||||
console.log('>>>>',value.replace(/%/g, ''));
|
||||
return value.replace(/%/g, '');
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow class="match-height">
|
||||
<VCol cols="12" md="5" class="mt-3 px-3">
|
||||
<AppDateTimePicker
|
||||
v-model="date"
|
||||
label="Date Range"
|
||||
:config="{ mode: 'range' }"
|
||||
@change="changeDateRange()"
|
||||
>
|
||||
</AppDateTimePicker>
|
||||
</VCol>
|
||||
|
||||
<VCol cols="12">
|
||||
<LogisticsCardStatistics :isDate="date" :overview="store.getters.getAnalyticsOverview"/>
|
||||
</VCol>
|
||||
|
||||
<VCol cols="12" md="4">
|
||||
|
||||
<VCard title="Patient Stats">
|
||||
|
||||
<VCardText class="d-flex">
|
||||
<!-- 👉 Standard Chip -->
|
||||
<VRow>
|
||||
<VCol cols="6" class="text-center">
|
||||
<p class="mb-3">New Users</p>
|
||||
<h1>{{ store.getters.getAnalyticsOverview.patient_stats.new_users[0] }}</h1>
|
||||
</VCol>
|
||||
<VCol cols="6" class="text-center">
|
||||
<p class="mb-3">Return Visitors</p>
|
||||
<h1>{{ store.getters.getAnalyticsOverview.patient_stats.returning_users[0]}}</h1>
|
||||
</VCol>
|
||||
</VRow>
|
||||
|
||||
</VCardText>
|
||||
<VSpacer />
|
||||
<VCardText>
|
||||
|
||||
<VDivider/>
|
||||
<div class="my-6">
|
||||
<div class="d-flex mt-3 mb-2">
|
||||
<h6 class="text-h6 font-weight-medium">
|
||||
New Users
|
||||
</h6>
|
||||
<VSpacer />
|
||||
<h6 class="text-h6 font-weight-medium">
|
||||
{{ store.getters.getAnalyticsOverview.patient_stats.new_users[1]}}
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Progress -->
|
||||
<VProgressLinear
|
||||
rounded
|
||||
:model-value="porgressPercentage(store.getters.getAnalyticsOverview.patient_stats.new_users[1])"
|
||||
height="3"
|
||||
color="success"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="my-6">
|
||||
<div class="d-flex mt-3 mb-2">
|
||||
<h6 class="text-h6 font-weight-medium">
|
||||
Return Visitors
|
||||
</h6>
|
||||
<VSpacer />
|
||||
<h6 class="text-h6 font-weight-medium">
|
||||
{{ store.getters.getAnalyticsOverview.patient_stats.returning_users[1]}}
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Progress -->
|
||||
<VProgressLinear
|
||||
rounded
|
||||
:model-value="porgressPercentage(store.getters.getAnalyticsOverview.patient_stats.returning_users[1])"
|
||||
height="3"
|
||||
color="warning"
|
||||
/>
|
||||
</div>
|
||||
<div class="my-6">
|
||||
<div class="d-flex mt-3 mb-2">
|
||||
<h6 class="text-h6 font-weight-medium">
|
||||
Engagement
|
||||
</h6>
|
||||
<VSpacer />
|
||||
<h6 class="text-h6 font-weight-medium">
|
||||
10%
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Progress -->
|
||||
<VProgressLinear
|
||||
rounded
|
||||
:model-value="10"
|
||||
height="3"
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol cols="12" md="8">
|
||||
<VCard title="Chart">
|
||||
<VCardText>
|
||||
<ApexChart/>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol cols="12" md="12">
|
||||
<VCardTitle>
|
||||
Leadboards
|
||||
</VCardTitle>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<DashboardTable :downloadable="false"/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
208
resources/js/pages/analytics/products.vue
Normal file
208
resources/js/pages/analytics/products.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<script setup>
|
||||
import ProductsAnalyticsTable from '@/pages/analytics/ProductsAnalyticsTable.vue';
|
||||
import ProductsCardStatistics from '@/views/apps/logistics/ProductsCardStatistics.vue';
|
||||
import { getLineChartConfig } from '@core/libs/chartjs/chartjsConfig';
|
||||
import LineChart from '@core/libs/chartjs/components/LineChart';
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
const store = useStore();
|
||||
const date = ref('');
|
||||
const orderStartdate = ref('');
|
||||
const orderEnddate = ref('');
|
||||
const orderData = ref([]);
|
||||
const analyticsData = ref(null);
|
||||
const productData = ref([]);
|
||||
|
||||
const vuetifyTheme = useTheme()
|
||||
|
||||
const data = computed(() => ({
|
||||
labels: store.getters.getProductsAnalytics.chart.chart_dates,
|
||||
datasets: [
|
||||
{
|
||||
fill: false,
|
||||
tension: 0.5,
|
||||
pointRadius: 1,
|
||||
label: 'Orders',
|
||||
pointHoverRadius: 5,
|
||||
pointStyle: 'circle',
|
||||
borderColor: 'orange',
|
||||
backgroundColor: 'orange',
|
||||
pointHoverBorderWidth: 5,
|
||||
pointHoverBorderColor: 'white',
|
||||
pointBorderColor: 'transparent',
|
||||
pointHoverBackgroundColor: 'orange',
|
||||
data: store.getters.getProductsAnalytics.chart.chart_data,
|
||||
}
|
||||
],
|
||||
}));
|
||||
|
||||
const chartConfig = computed(() => getLineChartConfig(vuetifyTheme.current.value))
|
||||
|
||||
const filter = ref({
|
||||
show_by: 'all_products',
|
||||
product: 'all',
|
||||
});
|
||||
|
||||
// Change this to a regular function that returns a computed ref
|
||||
const useSortedProduct = () => {
|
||||
const isLoading = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
const sortedProduct = computed(() => {
|
||||
const allOption = { id: 'all', title: 'All' };
|
||||
const sortedData = productData.value.slice().sort((a, b) => {
|
||||
return a.title.localeCompare(b.title);
|
||||
});
|
||||
return [allOption, ...sortedData];
|
||||
});
|
||||
|
||||
const fetchProductData = async () => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
await store.dispatch('getAllProductsList');
|
||||
productData.value = store.getters.getProductsList || [];
|
||||
console.log('Fetched Product data:', productData.value);
|
||||
} catch (e) {
|
||||
console.error('Error fetching Product data:', e);
|
||||
error.value = 'Failed to fetch Product data';
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(fetchProductData);
|
||||
|
||||
return { sortedProduct, isLoading, error, fetchProductData };
|
||||
};
|
||||
|
||||
const { sortedProduct, isLoading, error, fetchProductData } = useSortedProduct();
|
||||
|
||||
const setDateRange = () => {
|
||||
|
||||
const today = new Date();
|
||||
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
date.value = [startOfMonth, today];
|
||||
console.log("xxxxxxxx", date.value);
|
||||
};
|
||||
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
let productRange = store.getters.getCurrentFilterDate.filter_date;
|
||||
console.log("productRange",productRange);
|
||||
if(productRange){
|
||||
try {
|
||||
date.value = productRange;
|
||||
const dateString = typeof productRange === 'string' ? productRange : '';
|
||||
const [startDate, endDate] = dateString.split(" to ");
|
||||
if (startDate && endDate) {
|
||||
orderStartdate.value = startDate;
|
||||
orderEnddate.value = endDate;
|
||||
await fetchOrder();
|
||||
} else {
|
||||
console.warn('Invalid date range');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing date range:', error);
|
||||
}
|
||||
await store.dispatch('getAllProductsList');
|
||||
await fetchOrder();
|
||||
|
||||
}else{
|
||||
|
||||
setDateRange();
|
||||
const now = new Date();
|
||||
let startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const currentDate = formatDate(now);
|
||||
const monthStart = formatDate(startOfMonth);
|
||||
orderStartdate.value = monthStart;
|
||||
orderEnddate.value = currentDate;
|
||||
await store.dispatch('getAllProductsList');
|
||||
await fetchOrder();
|
||||
}
|
||||
});
|
||||
|
||||
const fetchOrder = async () => {
|
||||
await store.dispatch('getAdminProductsAnalytics', {
|
||||
start_date: orderStartdate.value,
|
||||
end_date: orderEnddate.value,
|
||||
single_product: filter.value.product
|
||||
});
|
||||
};
|
||||
|
||||
const changeDateRange = async () => {
|
||||
console.log('changed date', date.value, 'type:', typeof date.value);
|
||||
try {
|
||||
const dateString = typeof date.value === 'string' ? date.value : '';
|
||||
const [startDate, endDate] = dateString.split(" to ");
|
||||
if (startDate && endDate) {
|
||||
orderStartdate.value = startDate;
|
||||
orderEnddate.value = endDate;
|
||||
await fetchOrder();
|
||||
} else {
|
||||
console.warn('Invalid date range');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing date range:', error);
|
||||
}
|
||||
};
|
||||
const showRecordsByList = [
|
||||
{ title: 'All Products', slug: 'all_products' },
|
||||
{ title: 'Single Product', slug: 'single_product' },
|
||||
];
|
||||
|
||||
const onOrderStatusChange = () => {
|
||||
if (filter.value.show_by !== 'single_product')
|
||||
fetchOrder();
|
||||
};
|
||||
|
||||
const onProductChange = () => {
|
||||
fetchOrder();
|
||||
};
|
||||
// Watch for changes in the store state
|
||||
watch(() => store.getters.getProductsAnalytics, () => {
|
||||
// Force re-render of the chart
|
||||
data.value = { ...data.value };
|
||||
}, { deep: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VRow class="match-height">
|
||||
<VCol cols="12" md="3" class="px-3">
|
||||
<AppDateTimePicker v-model="date" label="Date Range" :config="{ mode: 'range' }"
|
||||
@change="changeDateRange" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="3">
|
||||
<VAutocomplete v-model="filter.show_by" label="Show" density="comfortable" :items="showRecordsByList"
|
||||
placeholder="Show" item-title="title" item-value="slug" @update:model-value="onOrderStatusChange" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="3" v-if="filter.show_by === 'single_product'">
|
||||
<VAutocomplete v-model="filter.product" label="Products" placeholder="Products" density="comfortable"
|
||||
:items="sortedProduct" item-title="title" item-value="id" :loading="isLoading"
|
||||
:error-messages="error" @update:model-value="onProductChange" />
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VRow>
|
||||
<VCol cols="12" md="12">
|
||||
<ProductsCardStatistics :isDate="date" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="12">
|
||||
<VCard title="Chart">
|
||||
<VCardText>
|
||||
<LineChart :chart-options="chartConfig" :height="400" :chart-data="data" />
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<ProductsAnalyticsTable />
|
||||
</VCol>
|
||||
</VRow>
|
||||
</template>
|
Reference in New Issue
Block a user