initial commit

This commit is contained in:
Inshal
2024-10-25 19:58:19 +05:00
commit 2046156f90
1558 changed files with 210706 additions and 0 deletions

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>