Refine catalog product cards

This commit is contained in:
Ruslan Bakiev
2026-04-09 18:43:25 +07:00
parent 848b491a90
commit 21e40d3fa1

View File

@@ -50,6 +50,12 @@ const DEFAULT_CATALOG_PRODUCT_TYPE_SETTING: CatalogProductTypeSettingNode = {
customLengthStepM: null, customLengthStepM: null,
allowCustomSleeveBrand: false, allowCustomSleeveBrand: false,
allowCustomLabel: false, allowCustomLabel: false,
widthOptionsMm: [],
lengthOptionsM: [],
thicknessOptionsMicron: [],
sleeveOptions: [],
colorOptions: [],
labelOptions: [],
}; };
const parameterFields: Array<{ key: ParamFieldKey; label: string }> = [ const parameterFields: Array<{ key: ParamFieldKey; label: string }> = [
{ key: 'widthMm', label: 'Ширина' }, { key: 'widthMm', label: 'Ширина' },
@@ -481,23 +487,75 @@ function variantCountLabel(count: number) {
return `${count} вариантов`; return `${count} вариантов`;
} }
function customizationNotes(group: ProductGroup) { function formatLengthRange(setting: CatalogProductTypeSettingNode) {
const setting = groupCatalogSetting(group); if (!setting.customLengthMinM || !setting.customLengthMaxM || !setting.customLengthStepM) {
const notes: string[] = []; return null;
}
if (setting.allowCustomLength && setting.customLengthMinM && setting.customLengthMaxM && setting.customLengthStepM) { return `${setting.customLengthMinM}-${setting.customLengthMaxM} м, шаг ${setting.customLengthStepM} м`;
notes.push(`Любая длина ${setting.customLengthMinM}-${setting.customLengthMaxM} м, шаг ${setting.customLengthStepM} м`); }
function fieldHelperText(group: ProductGroup, field: ParamFieldKey) {
const setting = groupCatalogSetting(group);
if (field === 'widthMm') {
return 'Ширина рулона. От неё зависит, насколько широкую полосу материала вы получите.';
}
if (field === 'lengthM') {
const customRange = formatLengthRange(setting);
if (setting.allowCustomLength && customRange) {
return `Выберите стандартную длину или закажите свою. Доступный диапазон: ${customRange}.`;
}
return 'Длина рулона в метрах. Здесь выбирается стандартный доступный размер.';
}
if (field === 'thicknessMicron') {
return 'Толщина материала. Чем выше значение, тем плотнее и заметнее сама лента.';
}
if (field === 'sleeveBrand') {
if (setting.allowCustomSleeveBrand) {
return 'Тип втулки внутри рулона. При необходимости можем сделать втулку с вашим логотипом.';
}
return 'Тип втулки внутри рулона. Выберите подходящий стандартный вариант.';
}
if (field === 'colorTag') {
return 'Цвет или визуальное исполнение ленты. Он влияет на внешний вид готового продукта.';
}
if (field === 'labelTag') {
if (setting.allowCustomLabel) {
return 'Готовая надпись или маркировка. Если нужно, можем нанести и вашу собственную надпись.';
}
return 'Готовая надпись или маркировка на ленте для стандартных сценариев использования.';
}
return 'Выберите подходящий параметр для этой позиции.';
}
function customizationDetails(group: ProductGroup) {
const setting = groupCatalogSetting(group);
const details: string[] = [];
const customRange = formatLengthRange(setting);
if (setting.allowCustomLength && customRange) {
details.push(`Длина под заказ: ${customRange}.`);
} }
if (setting.allowCustomSleeveBrand) { if (setting.allowCustomSleeveBrand) {
notes.push('Втулка с логотипом'); details.push('Втулка под заказ: можно сделать с вашим логотипом.');
} }
if (setting.allowCustomLabel) { if (setting.allowCustomLabel) {
notes.push('Нанесение надписи'); details.push('Надпись под заказ: можно нанести вашу маркировку или текст.');
} }
return notes; return details;
} }
function toggleExpanded(group: ProductGroup) { function toggleExpanded(group: ProductGroup) {
@@ -572,23 +630,32 @@ function decrementSelected(group: ProductGroup) {
<div class="p-4 md:p-5 xl:col-span-4"> <div class="p-4 md:p-5 xl:col-span-4">
<div class="mb-4"> <div class="mb-4">
<h2 class="text-2xl font-bold text-[#163624]">{{ group.typeLabel }}</h2> <h2 class="text-2xl font-bold text-[#163624]">{{ group.typeLabel }}</h2>
<div v-if="customizationNotes(group).length" class="mt-3 flex flex-wrap gap-2"> <p class="mt-2 max-w-3xl text-sm leading-6 text-[#5d7468]">
Выберите параметры внутри карточки, а ниже при необходимости можно открыть полный список вариантов по этой позиции.
</p>
<div v-if="customizationDetails(group).length" class="mt-4 rounded-[24px] bg-[#eef8f1] p-4">
<p class="text-xs font-bold uppercase tracking-[0.12em] text-[#15613d]">Под заказ</p>
<div class="mt-3 flex flex-wrap gap-2">
<span <span
v-for="note in customizationNotes(group)" v-for="note in customizationDetails(group)"
:key="`${group.key}-${note}`" :key="`${group.key}-${note}`"
class="rounded-full bg-[#eef8f1] px-3 py-1 text-xs font-semibold text-[#15613d]" class="rounded-full bg-white px-3 py-1 text-xs font-semibold text-[#15613d]"
> >
{{ note }} {{ note }}
</span> </span>
</div> </div>
</div> </div>
</div>
<div class="grid content-start gap-4 md:grid-cols-2 2xl:grid-cols-3"> <div class="space-y-3">
<div <div
v-for="field in visibleFields(group)" v-for="field in visibleFields(group)"
:key="`${group.key}-${field.key}`" :key="`${group.key}-${field.key}`"
class="rounded-[22px] border border-base-200 bg-[#fbfcfb] p-4" class="rounded-[22px] border border-base-200 bg-[#fbfcfb] p-4"
> >
<div class="grid gap-4 xl:grid-cols-[minmax(0,1fr)_260px] xl:items-start">
<div>
<p class="text-sm font-semibold text-[#163624]">{{ field.label }}</p> <p class="text-sm font-semibold text-[#163624]">{{ field.label }}</p>
<div class="mt-3 flex flex-wrap gap-2"> <div class="mt-3 flex flex-wrap gap-2">
@@ -616,6 +683,12 @@ function decrementSelected(group: ProductGroup) {
</label> </label>
</div> </div>
</div> </div>
<div class="rounded-[18px] bg-white p-3 text-sm leading-6 text-[#5d7468]">
{{ fieldHelperText(group, field.key) }}
</div>
</div>
</div>
</div> </div>
</div> </div>
@@ -624,6 +697,10 @@ function decrementSelected(group: ProductGroup) {
<div /> <div />
<div class="space-y-3"> <div class="space-y-3">
<div class="rounded-[22px] bg-[#f5faf7] px-4 py-3 text-center text-sm font-medium text-[#4c6a5a]">
Артикул: <span class="font-semibold text-[#163624]">{{ articleLabel(group) }}</span>
</div>
<button <button
v-if="selectedQty(group) === 0" v-if="selectedQty(group) === 0"
class="btn h-11 w-full rounded-full border-0 bg-[#139957] text-sm font-semibold text-white hover:bg-[#0d854a]" class="btn h-11 w-full rounded-full border-0 bg-[#139957] text-sm font-semibold text-white hover:bg-[#0d854a]"
@@ -648,8 +725,6 @@ function decrementSelected(group: ProductGroup) {
</button> </button>
</div> </div>
</div> </div>
<p class="text-center text-sm font-medium text-base-content/55">{{ articleLabel(group) }}</p>
</div> </div>
</div> </div>
</aside> </aside>