206 lines
7.6 KiB
Vue
206 lines
7.6 KiB
Vue
<script setup>
|
|
import {
|
|
NFlex, NButton, NDataTable, NTag,
|
|
NText, NEl, NIcon, NInput, NTabs, NTabPane,
|
|
} from 'naive-ui'
|
|
import {
|
|
TbChartBar, TbPlus, TbPencil, TbSearch,
|
|
TbLayoutDashboard, TbStack2, TbAdjustments,
|
|
} from 'vue-icons-plus/tb'
|
|
import AppLayout from '../../../Layouts/AppLayout.vue'
|
|
import AppContainer from '../../../Components/AppContainer.vue'
|
|
import SectionCard from '../../../Components/SectionCard.vue'
|
|
import PageBanner from '../../../Components/PageBanner.vue'
|
|
import { Link } from '@inertiajs/vue3'
|
|
import { computed, h, ref } from 'vue'
|
|
|
|
const props = defineProps({
|
|
groups: { type: Array, default: () => [] },
|
|
items: { type: Array, default: () => [] },
|
|
})
|
|
|
|
const searchGroups = ref('')
|
|
const searchItems = ref('')
|
|
|
|
const filteredGroups = computed(() => {
|
|
const q = searchGroups.value.toLowerCase().trim()
|
|
if (!q) return props.groups
|
|
return props.groups.filter(g => g.name.toLowerCase().includes(q))
|
|
})
|
|
|
|
const filteredItems = computed(() => {
|
|
const q = searchItems.value.toLowerCase().trim()
|
|
if (!q) return props.items
|
|
return props.items.filter(i => i.name.toLowerCase().includes(q) || i.code.toLowerCase().includes(q))
|
|
})
|
|
|
|
const dataTypeLabel = (type) => ({
|
|
integer: 'Целое',
|
|
float: 'Дробное',
|
|
string: 'Строка',
|
|
text: 'Текст',
|
|
boolean: 'Да/Нет',
|
|
select: 'Список',
|
|
}[type] ?? type)
|
|
|
|
const dataTypeColor = (type) => ({
|
|
integer: 'info',
|
|
float: 'info',
|
|
string: 'default',
|
|
text: 'default',
|
|
boolean: 'warning',
|
|
select: 'success',
|
|
}[type] ?? 'default')
|
|
|
|
const groupColumns = computed(() => [
|
|
{
|
|
key: 'name',
|
|
title: 'Название',
|
|
render: (row) => h(NFlex, { vertical: true, size: 2 }, () => [
|
|
h(NText, { style: 'font-weight: 500; font-size: 13px;' }, () => row.name),
|
|
row.description ? h(NText, { depth: 3, style: 'font-size: 12px;' }, () => row.description) : null,
|
|
])
|
|
},
|
|
{
|
|
key: 'items_count',
|
|
title: 'Показателей',
|
|
width: 130,
|
|
render: (row) => h(NTag, { size: 'small', round: true, bordered: false }, () => `${row.items_count}`)
|
|
},
|
|
{
|
|
key: 'actions',
|
|
title: '',
|
|
width: 60,
|
|
align: 'center',
|
|
render: (row) => h(NButton, {
|
|
text: true, size: 'small', tag: Link,
|
|
href: `/admin/metrics/groups/${row.id}`,
|
|
title: 'Редактировать',
|
|
}, { icon: () => h(NIcon, { size: 18 }, () => h(TbPencil)) })
|
|
},
|
|
])
|
|
|
|
const itemColumns = computed(() => [
|
|
{
|
|
key: 'name',
|
|
title: 'Название',
|
|
render: (row) => h(NFlex, { vertical: true, size: 2 }, () => [
|
|
h(NText, { style: 'font-weight: 500; font-size: 13px;' }, () => row.name),
|
|
h(NText, { depth: 3, style: 'font-size: 12px; font-family: monospace;' }, () => row.code),
|
|
])
|
|
},
|
|
{
|
|
key: 'data_type',
|
|
title: 'Тип',
|
|
width: 120,
|
|
render: (row) => h(NTag, {
|
|
type: dataTypeColor(row.data_type),
|
|
size: 'small', round: true, bordered: false,
|
|
}, () => dataTypeLabel(row.data_type))
|
|
},
|
|
{
|
|
key: 'is_active',
|
|
title: 'Статус',
|
|
width: 110,
|
|
render: (row) => h(NTag, {
|
|
type: row.is_active ? 'success' : 'error',
|
|
size: 'small', round: true, bordered: false,
|
|
}, () => row.is_active ? 'Активен' : 'Отключён')
|
|
},
|
|
{
|
|
key: 'actions',
|
|
title: '',
|
|
width: 60,
|
|
align: 'center',
|
|
render: (row) => h(NButton, {
|
|
text: true, size: 'small', tag: Link,
|
|
href: `/admin/metrics/items/${row.id}`,
|
|
title: 'Редактировать',
|
|
}, { icon: () => h(NIcon, { size: 18 }, () => h(TbPencil)) })
|
|
},
|
|
])
|
|
</script>
|
|
|
|
<template>
|
|
<AppLayout>
|
|
<AppContainer>
|
|
|
|
<PageBanner
|
|
title="Метрики"
|
|
:icon="TbChartBar"
|
|
:breadcrumbs="[{ label: 'Администратор', href: '/admin', icon: TbLayoutDashboard, tag: Link }]"
|
|
>
|
|
<template #meta>
|
|
<NFlex align="center" :size="8">
|
|
<NText depth="3" style="font-size: 13px;">
|
|
{{ groups.length }} {{ groups.length === 1 ? 'группа' : 'групп' }}
|
|
</NText>
|
|
<NEl style="width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .3;" />
|
|
<NText depth="3" style="font-size: 13px;">{{ items.length }} показателей</NText>
|
|
</NFlex>
|
|
</template>
|
|
<template #actions>
|
|
<NButton :tag="Link" href="/admin/metrics/groups/new">
|
|
<template #icon><NIcon><TbPlus /></NIcon></template>
|
|
Новая группа
|
|
</NButton>
|
|
<NButton type="primary" :tag="Link" href="/admin/metrics/items/new">
|
|
<template #icon><NIcon><TbPlus /></NIcon></template>
|
|
Новый показатель
|
|
</NButton>
|
|
</template>
|
|
</PageBanner>
|
|
|
|
<NTabs type="line" animated>
|
|
|
|
<NTabPane name="groups" tab="Группы">
|
|
<SectionCard :icon="TbStack2" title="Группы показателей" no-padding style="margin-top: 4px;">
|
|
<template #header-extra>
|
|
<NInput v-model:value="searchGroups" size="small" placeholder="Поиск..." clearable style="width: 200px;">
|
|
<template #prefix><NIcon depth="3"><TbSearch /></NIcon></template>
|
|
</NInput>
|
|
</template>
|
|
<NDataTable
|
|
:columns="groupColumns"
|
|
:data="filteredGroups"
|
|
:bordered="false"
|
|
size="small"
|
|
flex-height
|
|
style="height: calc(100vh - 356px); min-height: 200px;"
|
|
/>
|
|
</SectionCard>
|
|
</NTabPane>
|
|
|
|
<NTabPane name="items" tab="Показатели">
|
|
<SectionCard :icon="TbAdjustments" title="Показатели" no-padding style="margin-top: 4px;">
|
|
<template #header-extra>
|
|
<NInput v-model:value="searchItems" size="small" placeholder="Поиск..." clearable style="width: 200px;">
|
|
<template #prefix><NIcon depth="3"><TbSearch /></NIcon></template>
|
|
</NInput>
|
|
</template>
|
|
<NDataTable
|
|
:columns="itemColumns"
|
|
:data="filteredItems"
|
|
:bordered="false"
|
|
size="small"
|
|
flex-height
|
|
style="height: calc(100vh - 356px); min-height: 200px;"
|
|
/>
|
|
</SectionCard>
|
|
</NTabPane>
|
|
|
|
</NTabs>
|
|
|
|
</AppContainer>
|
|
</AppLayout>
|
|
</template>
|
|
|
|
<style scoped>
|
|
:deep(.n-data-table-th) { background: transparent !important; }
|
|
:deep(.n-data-table) { background: transparent; }
|
|
:deep(.n-data-table-wrapper) { border-radius: 0; }
|
|
:deep(.n-data-table-th .n-data-table-th__title) { font-size: 12px; }
|
|
:deep(.n-data-table-td) { font-size: 13px; }
|
|
:deep(.n-tabs-pane-wrapper) { padding-top: 0; }
|
|
</style>
|