93 lines
4.1 KiB
Vue
93 lines
4.1 KiB
Vue
<script setup>
|
|
import { NSelect, NInput, NTransfer, NDynamicInput, NFlex, NText, NEmpty, NFormItem, NForm } from 'naive-ui'
|
|
import { computed } from 'vue'
|
|
|
|
const props = defineProps({
|
|
section: { type: Object, required: true },
|
|
sources: { type: Array, default: () => [] },
|
|
})
|
|
|
|
const sourceOptions = computed(() => props.sources.map(s => ({ label: s.label, value: s.key })))
|
|
|
|
const selectedSource = computed(() => props.sources.find(s => s.key === props.section.source) ?? null)
|
|
|
|
const columnTransferOptions = computed(() => Object.entries(selectedSource.value?.columns ?? {})
|
|
.map(([value, label]) => ({ label, value })))
|
|
|
|
const filterableFieldOptions = computed(() => Object.entries(selectedSource.value?.filterableFields ?? {})
|
|
.map(([value, def]) => ({ label: def.label, value })))
|
|
|
|
const filterValueOptions = (fieldKey) => {
|
|
const options = selectedSource.value?.filterableFields?.[fieldKey]?.options
|
|
return options ? Object.entries(options).map(([value, label]) => ({ label, value })) : null
|
|
}
|
|
|
|
const createFilter = () => ({
|
|
field: filterableFieldOptions.value[0]?.value ?? null,
|
|
value: null,
|
|
})
|
|
|
|
const onSourceChange = () => {
|
|
// Колонки и фильтры принадлежат конкретному источнику — при смене источника они теряют смысл
|
|
props.section.columns = []
|
|
props.section.filters = []
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<NFlex vertical :size="12" style="width: 100%;">
|
|
<NForm label-placement="top">
|
|
<NFlex :size="12" :wrap="true">
|
|
<NFormItem label="Источник данных" style="min-width: 240px; margin-bottom: 0;">
|
|
<NSelect v-model:value="section.source" :options="sourceOptions" @update:value="onSourceChange" />
|
|
</NFormItem>
|
|
<NFormItem label="Заголовок секции" style="min-width: 240px; flex: 1; margin-bottom: 0;">
|
|
<NInput v-model:value="section.title" :placeholder="selectedSource?.label" />
|
|
</NFormItem>
|
|
</NFlex>
|
|
</NForm>
|
|
|
|
<div>
|
|
<NText depth="3" style="font-size: 12px; display: block; margin-bottom: 6px;">Колонки</NText>
|
|
<NTransfer
|
|
v-model:value="section.columns"
|
|
:options="columnTransferOptions"
|
|
source-filterable
|
|
source-title="Доступные колонки"
|
|
target-title="Колонки секции (в этом порядке)"
|
|
style="height: 280px;"
|
|
/>
|
|
</div>
|
|
|
|
<div v-if="filterableFieldOptions.length">
|
|
<NText depth="3" style="font-size: 12px; display: block; margin-bottom: 6px;">Фильтры (необязательно)</NText>
|
|
<NDynamicInput v-model:value="section.filters" :on-create="createFilter">
|
|
<template #default="{ value }">
|
|
<NFlex align="center" :size="8" style="flex: 1;">
|
|
<NSelect
|
|
v-model:value="value.field"
|
|
:options="filterableFieldOptions"
|
|
style="width: 220px;"
|
|
placeholder="Поле"
|
|
/>
|
|
<NSelect
|
|
v-if="filterValueOptions(value.field)"
|
|
v-model:value="value.value"
|
|
:options="filterValueOptions(value.field)"
|
|
style="width: 220px;"
|
|
placeholder="Значение"
|
|
/>
|
|
<NInput
|
|
v-else
|
|
v-model:value="value.value"
|
|
style="width: 220px;"
|
|
placeholder="Значение"
|
|
/>
|
|
</NFlex>
|
|
</template>
|
|
</NDynamicInput>
|
|
<NEmpty v-if="!section.filters.length" description="Без фильтров — попадут все записи" size="small" style="padding: 8px 0;" />
|
|
</div>
|
|
</NFlex>
|
|
</template>
|