+analytics update
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
Reference in New Issue
Block a user