diff --git a/app/pages/catalog-settings.vue b/app/pages/catalog-settings.vue index 70525d6..03efdc8 100644 --- a/app/pages/catalog-settings.vue +++ b/app/pages/catalog-settings.vue @@ -2,8 +2,10 @@ import { useMutation, useQuery } from '@vue/apollo-composable'; import { CatalogProductTypeSettingsDocument, + ClientProductsDocument, UpsertCatalogProductTypeSettingDocument, type CatalogProductTypeSettingsQuery, + type ClientProductsQuery, } from '~/composables/graphql/generated'; definePageMeta({ @@ -12,6 +14,7 @@ definePageMeta({ }); type CatalogSettingItem = CatalogProductTypeSettingsQuery['catalogProductTypeSettings'][number]; +type ProductNode = ClientProductsQuery['clientProducts'][number]; type CatalogSettingForm = { productType: string; allowCustomLength: boolean; @@ -21,8 +24,16 @@ type CatalogSettingForm = { allowCustomSleeveBrand: boolean; allowCustomLabel: boolean; }; +type StandardOptionGroup = { + label: string; + values: string[]; +}; + +const COLOR_TAGS = ['прозрачный', 'коричневый', 'белый', 'черный', 'желтый', 'зеленый', 'красный', 'синий', 'оранжевый', 'красно-белый']; +const LABEL_TAGS = ['хрупкое', 'подарок', 'акция']; const settingsQuery = useQuery(CatalogProductTypeSettingsDocument); +const catalogProductsQuery = useQuery(ClientProductsDocument); const saveSettingMutation = useMutation(UpsertCatalogProductTypeSettingDocument, { throws: 'never' }); const forms = reactive>({}); @@ -31,6 +42,59 @@ const saveSuccess = ref(''); const saveError = ref(''); const settings = computed(() => settingsQuery.result.value?.catalogProductTypeSettings ?? []); +const isLoading = computed(() => settingsQuery.loading.value || catalogProductsQuery.loading.value); + +function normalizeText(value: string | null | undefined) { + return String(value ?? '').replaceAll(/\s+/g, ' ').trim(); +} + +function formatNumberOptions(values: Array, suffix: string) { + return [...new Set(values.filter((value): value is number => typeof value === 'number'))] + .sort((a, b) => a - b) + .map((value) => `${value} ${suffix}`); +} + +function formatTextOptions(values: Array) { + return [...new Set(values.map((value) => normalizeText(value)).filter(Boolean))] + .sort((a, b) => a.localeCompare(b, 'ru')); +} + +const standardOptionsByType = computed>(() => { + const products = catalogProductsQuery.result.value?.clientProducts ?? []; + const grouped = new Map(); + + for (const product of products) { + const typeLabel = normalizeText(product.productType) || 'Без типа'; + const existing = grouped.get(typeLabel); + if (existing) { + existing.push(product); + } else { + grouped.set(typeLabel, [product]); + } + } + + return Object.fromEntries( + [...grouped.entries()].map(([typeLabel, items]) => { + const colorValues = formatTextOptions( + items.flatMap((product) => product.tags.filter((tag) => COLOR_TAGS.includes(normalizeText(tag)))), + ); + const labelValues = formatTextOptions( + items.flatMap((product) => product.tags.filter((tag) => LABEL_TAGS.includes(normalizeText(tag)))), + ); + + const optionGroups: StandardOptionGroup[] = [ + { label: 'Ширина', values: formatNumberOptions(items.map((product) => product.widthMm), 'мм') }, + { label: 'Длина', values: formatNumberOptions(items.map((product) => product.lengthM), 'м') }, + { label: 'Толщина', values: formatNumberOptions(items.map((product) => product.thicknessMicron), 'мкм') }, + { label: 'Втулка', values: formatTextOptions(items.map((product) => product.sleeveBrand)) }, + { label: 'Цвет', values: colorValues }, + { label: 'Надпись', values: labelValues }, + ].filter((group) => group.values.length > 0); + + return [typeLabel, optionGroups]; + }), + ); +}); function toInputValue(value: number | null | undefined) { return value == null ? '' : String(value); @@ -62,6 +126,10 @@ function formFor(item: CatalogSettingItem) { return forms[item.productType]; } +function standardOptionsFor(item: CatalogSettingItem) { + return standardOptionsByType.value[item.productType] ?? []; +} + watch( settings, (items) => { @@ -118,7 +186,7 @@ async function saveAllSettings() {

Каталог

-
+
Загружаем настройки каталога...
@@ -135,20 +203,20 @@ async function saveAllSettings() {

{{ item.productType }}

-
-
+ +
+
Стандартные параметры
+
+
+
{{ group.label }}
+
+ + {{ value }} + +
+
+
+