+analytics update

This commit is contained in:
Vladimir Voronin
2025-01-24 15:25:43 +03:00
parent a685c67395
commit 26dd9c5202
3 changed files with 81 additions and 32 deletions

View File

@@ -7,7 +7,7 @@
<div class="flex flex-row rounded-full px-2 justify-between overflow-x">
<div class="flex flex-col gap-2 p-2">
<router-link to="/analytics" class="items-center flex flex-col gap-2">
<i class="pi pi-briefcase text-2xl" style="font-size: 1.5rem"></i>
<i class="pi pi-chart-line text-2xl" style="font-size: 1.5rem"></i>
<p>Аналитика</p>
</router-link>
</div>

View File

@@ -7,6 +7,9 @@ import Column from "primevue/column";
import Chart from "primevue/chart";
import Listbox from "primevue/listbox";
import Select from "primevue/select";
import InputText from "primevue/inputtext";
import IconField from "primevue/iconfield"
import InputIcon from "primevue/inputicon";
import Accordion from "primevue/accordion";
import AccordionPanel from "primevue/accordionpanel";
import AccordionHeader from "primevue/accordionheader";
@@ -27,8 +30,15 @@ const dataTableCategories = ref([]);
const tableColumns = ref([]);
const chartData = ref(null)
const selectedCategory = ref()
const formatter = ref(new Intl.NumberFormat('ru-RU', {style: 'currency', currency: 'RUB', minimumFractionDigits: 0, maximumFractionDigits:0}))
const formatter = ref(new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}))
const isChartOpen = ref(false)
const filterText = ref(null)
const closeChart = () => {
setTimeout(() => {
@@ -148,12 +158,12 @@ const prepareTableData = (categories) => {
if (found.difference != 0) {
if (found.difference > 0) {
row[dateStr] = found ? formatter.value.format(found.total) + "<p class='text-red-500 text-sm'> (+ " + found.difference + "%)</p>" : 0;
row[dateStr] = found ? "<p>" + formatter.value.format(found.total) + "</p><p class='text-red-500 text-sm'> (+ " + found.difference + "%)</p>" : 0;
} else {
row[dateStr] = found ? formatter.value.format(found.total) + "<p class='text-green-600 text-sm'> (" + found.difference + "%)</p>" : 0;
row[dateStr] = found ? "<p>" + formatter.value.format(found.total) + "</p><p class='text-green-600 text-sm'> (" + found.difference + "%)</p>" : 0;
}
} else {
row[dateStr] = found ? formatter.value.format(found.total) : 0;
row[dateStr] = found ? "<p>" + formatter.value.format(found.total) + "</p>" : 0;
}
if (!sums[dateStr]) {
sums[dateStr] = 0
@@ -161,7 +171,7 @@ const prepareTableData = (categories) => {
sums[dateStr] += found.total
categorySum += found.total
});
row["avg"] = formatter.value.format(categorySum/allDates.length);
row["avg"] = "<p>" + formatter.value.format(categorySum / allDates.length) + "</p>";
return row;
});
@@ -179,7 +189,7 @@ const prepareTableData = (categories) => {
if (difference > 0) {
color = "text-red-500"
} else color = "text-green-600"
sums[key] = formatter.value.format(sums[key]) + `<p class='${color}'>(` + difference.toFixed(0) + "%)</p>";
sums[key] = "<p>" + formatter.value.format(sums[key]) + `</p><p class='${color}'>(` + difference.toFixed(0) + "%)</p>";
});
@@ -221,32 +231,54 @@ onMounted(async () => {
<template>
<LoadingView v-if="loading"/>
<div v-else class="p-4 bg-gray-100 h-full flex flex-col gap-4 items-center justify-items-center ">
<div v-else class="p-4 bg-gray-100 flex flex-col gap-4 items-center justify-items-center ">
<div class="!items-center w-5/6 bg-white">
<Accordion value="1" class=" " @tab-open="isChartOpen=true"
@tab-close="closeChart">
<AccordionPanel value="0">
<AccordionHeader>График</AccordionHeader>
<AccordionContent>
<Accordion value="0" class=" !w-5/6 !items-center !justify-items-start" @tab-open="isChartOpen=true"
@tab-close="closeChart">
<AccordionPanel value="1">
<AccordionHeader>График</AccordionHeader>
<AccordionContent class="items-center justify-items-center ">
<!-- <Select v-model="selectedCategory" :options="categoriesCatalog" optionLabel="name"-->
<!-- placeholder="Выберите категории"-->
<!-- :maxSelectedLabels="3" class="w-full md:w-80"/>-->
<div v-if="isChartOpen"
class="grid grid-cols-1 sm:grid-cols-6 w-full items-start justify-items-start">
<!-- Список категорий -->
<div class="sm:col-span-1 w-full h-56 sm:h-[42rem] p-2 overflow-y-scroll outline outline-1 outline-gray-300 rounded-lg">
<!-- <IconField>-->
<!-- <Select v-model="selectedCategory" :options="categoriesCatalog" optionLabel="name"-->
<!-- placeholder="Выберите категории"-->
<!-- :maxSelectedLabels="3" class="w-full md:w-80"/>-->
<div v-if="isChartOpen" class="flex flex-row items-start justify-items-start w-full">
<Listbox v-model="selectedCategory" :options="categoriesCatalog" filter optionLabel="name"
class="!w-fit !h-5/6 md:w-56">
<!-- <InputText v-model="filterText" placeholder="Поиск категории"/>-->
<!-- <InputIcon class="pi pi-search"/>-->
<!-- </IconField>-->
<ul class="w-5/6">
<template #option="slotProps">
<div>{{ slotProps.option.icon }} {{ slotProps.option.name }}</div>
</template>
<li v-for="category in categoriesCatalog"
class="tpx-4 py-2 hover:bg-blue-50 rounded-md "
:class="selectedCategory.id == category.id? '!bg-emerald-50 text-emerald-700': '' " @click="selectedCategory=category">
{{ category.icon }} {{ category.name }}
</li>
</ul>
</div>
</Listbox>
<Chart type="line" :data="preparedChartData" :options="chartOptions" class="!w-5/6 !h-full"/>
</div>
</AccordionContent>
</AccordionPanel>
</Accordion>
<!-- Контейнер для графика с горизонтальной прокруткой -->
<div class="sm:col-span-5 overflow-x-auto w-full">
<!-- «Растяжка», чтобы было за что «скроллить» -->
<div class="min-w-[550px] ">
<Chart
type="line"
:data="preparedChartData"
:options="chartOptions"
class="h-64 sm:h-full sm:w-full "
/>
</div>
</div>
</div>
</AccordionContent>
</AccordionPanel>
</Accordion>
</div>
<DataTable :value="dataTableCategories" responsiveLayout="scroll" filter stripedRows class="w-5/6 items-center">
<Column
@@ -281,7 +313,18 @@ onMounted(async () => {
justify-content: center;
}
.p-listbox-list-container {
max-height: 100% !important;
.p-listbox {
//height: 80% !important;
}
.p-listbox-list-container {
//height: 100% !important;
//max-height: 90% !important;
}
.p-chart {
//width: 100% !important;
overflow: auto;
}
</style>

View File

@@ -4,8 +4,14 @@ import {Category} from "@/models/Category"; // Импортируете нас
export const getCategories = async (type = null) => {
type = type ? type : ''
return await apiClient.get('/categories?type=' + type);
const params = {};
if (type) {
params.type = type;
}
return await apiClient.get('/categories', {
params: params
});
};
export const getCategoryTypes = async () => {