ui(product): restructure product specs tab with sections and fix pricing tab gap
- Product specs tab: group fields into bordered sections (اطلاعات پایه, وزن و واحد, تنظیمات نمایش) - Visibility switches in a compact panel with divider lines - Weight/unit/inventory fields in same grid row - Pricing tab: wrap all content in flex-col gap-4 - Remove unnecessary product-editor-panel border from non-melted pricing block Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
@update:activeKey="$emit('update:activeKey', $event)"
|
||||
>
|
||||
<a-tab-pane key="0" tab="قیمتگذاری" force-render>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div
|
||||
v-if="usesMeltedPricing"
|
||||
class="product-editor-panel flex flex-col gap-3"
|
||||
@@ -112,7 +113,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!usesMeltedPricing" class="product-editor-panel flex flex-col gap-4">
|
||||
<div v-if="!usesMeltedPricing" class="flex flex-col gap-4">
|
||||
<div class="product-spec-switch-row">
|
||||
<div class="product-spec-label">
|
||||
<DashboardLabelWithHelp label="دریافت قیمت از" :help="priceSourceHelp" size="sm" />
|
||||
@@ -265,91 +266,128 @@
|
||||
</AButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="1" tab="مشخصات محصول" force-render>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<a-form-item name="title" :rules="inputRules()" class="!mb-0">
|
||||
<div class="flex flex-col gap-5">
|
||||
<!-- اطلاعات پایه -->
|
||||
<div class="product-section">
|
||||
<div class="product-section__title">اطلاعات پایه</div>
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<a-form-item name="title" :rules="inputRules()" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="عنوان" :help="titleHelp" size="sm" />
|
||||
</template>
|
||||
<BasicInput v-model:value="form.title" />
|
||||
</a-form-item>
|
||||
<a-form-item name="group_type" :rules="inputRules()" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="دستهبندی" :help="categoryHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.group_type" :items="categoryItems" valueName="value" keyName="key" />
|
||||
</a-form-item>
|
||||
<a-form-item name="metal_id" :rules="inputRules()" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="جنس فلز" :help="metalHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.metal_id" :items="metalItems" valueName="value" keyName="key" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
<a-form-item name="description" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="عنوان" :help="titleHelp" size="sm" />
|
||||
<DashboardLabelWithHelp label="توضیح محصول" :help="productDescriptionHelp" size="sm" />
|
||||
</template>
|
||||
<BasicInput v-model:value="form.title" />
|
||||
</a-form-item>
|
||||
<a-form-item name="group_type" :rules="inputRules()" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="دستهبندی" :help="categoryHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.group_type" :items="categoryItems" valueName="value" keyName="key" />
|
||||
</a-form-item>
|
||||
<a-form-item name="metal_id" :rules="inputRules()" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="جنس فلز" :help="metalHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.metal_id" :items="metalItems" valueName="value" keyName="key" />
|
||||
<a-textarea
|
||||
v-model:value="form.description"
|
||||
:rows="2"
|
||||
placeholder="متن توضیح برای نمایش در اپ مشتری (اختیاری)"
|
||||
:maxlength="2000"
|
||||
show-count
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<a-form-item name="description" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="توضیح محصول" :help="productDescriptionHelp" size="sm" />
|
||||
</template>
|
||||
<a-textarea
|
||||
v-model:value="form.description"
|
||||
:rows="3"
|
||||
placeholder="متن توضیح برای نمایش در اپ مشتری (اختیاری)"
|
||||
:maxlength="2000"
|
||||
show-count
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<div v-if="!isMeltedGroup" class="product-editor-panel flex flex-col gap-4">
|
||||
<div class="product-spec-switch-row">
|
||||
<div class="product-spec-label">
|
||||
<DashboardLabelWithHelp label="نوع معامله" :help="tradeByQuantityHelp" size="sm" />
|
||||
<!-- وزن و واحد -->
|
||||
<div class="product-section">
|
||||
<div class="product-section__title">وزن و واحد</div>
|
||||
<div v-if="!isMeltedGroup" class="flex flex-col gap-4">
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<DashboardLabelWithHelp label="نوع معامله" :help="tradeByQuantityHelp" size="sm" />
|
||||
<a-radio-group
|
||||
v-if="!editId"
|
||||
v-model:value="tradeTypeOption"
|
||||
name="tradeTypeGroup"
|
||||
>
|
||||
<a-radio value="count">تعدادی</a-radio>
|
||||
<a-radio value="quantity">مقداری</a-radio>
|
||||
</a-radio-group>
|
||||
<span
|
||||
v-else
|
||||
class="inline-flex items-center rounded-full px-3 py-1 text-sm font-600"
|
||||
:class="form.trade_by_quantity ? 'bg-emerald-100 text-emerald-800' : 'bg-sky-100 text-sky-800'"
|
||||
>
|
||||
{{ resolveProductTradeTypeLabel(form.trade_by_quantity) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<DashboardLabelWithHelp label="وزن محصول" :help="weightHelp" size="sm" />
|
||||
<a-radio-group :value="weightOption" name="weightGroup" @update:value="$emit('update:weightOption', $event)">
|
||||
<a-radio value="1">دارد</a-radio>
|
||||
<a-radio value="2">ندارد</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<a-radio-group
|
||||
v-if="!editId"
|
||||
v-model:value="tradeTypeOption"
|
||||
name="tradeTypeGroup"
|
||||
<div
|
||||
v-if="isQuantityTrade"
|
||||
class="rounded-md bg-amber-50 px-3 py-1.5 text-xs leading-5 text-amber-800"
|
||||
>
|
||||
<a-radio value="count">معامله تعدادی</a-radio>
|
||||
<a-radio value="quantity">معامله مقداری</a-radio>
|
||||
</a-radio-group>
|
||||
<span
|
||||
v-else
|
||||
class="inline-flex items-center rounded-full px-3 py-1 text-sm font-600"
|
||||
:class="form.trade_by_quantity ? 'bg-emerald-100 text-emerald-800' : 'bg-sky-100 text-sky-800'"
|
||||
>
|
||||
{{ resolveProductTradeTypeLabel(form.trade_by_quantity) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="isQuantityTrade"
|
||||
class="rounded-lg border border-solid border-amber-200 bg-amber-50 px-3 py-2 text-xs leading-6 text-amber-800"
|
||||
>
|
||||
معامله مقداری: مشتری بر اساس مقدار (گرم/کیلوگرم) خرید میکند. قیمتگذاری این محصول در تب «قیمتگذاری» بهصورت مقداری تنظیم میشود.
|
||||
</div>
|
||||
|
||||
<div class="product-spec-switch-row">
|
||||
<div class="product-spec-label">
|
||||
<DashboardLabelWithHelp label="وزن محصول" :help="weightHelp" size="sm" />
|
||||
مشتری بر اساس مقدار (گرم/کیلوگرم) خرید میکند.
|
||||
</div>
|
||||
<a-radio-group :value="weightOption" name="weightGroup" @update:value="$emit('update:weightOption', $event)">
|
||||
<a-radio value="1">دارد</a-radio>
|
||||
<a-radio value="2">ندارد</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
|
||||
<div v-if="weightOption === '1'" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
<a-form-item name="amount" :rules="inputRulesNumber('وزن')" class="!mb-0">
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<a-form-item v-if="weightOption === '1' && !isMeltedGroup" name="amount" :rules="inputRulesNumber('وزن')" class="!mb-0">
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp :label="weightFieldLabel" :help="weightAmountHelp" size="sm" />
|
||||
</template>
|
||||
<BasicInput v-model:value="form.amount" type="number" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="showUnitField"
|
||||
name="unit"
|
||||
:rules="inputRules()"
|
||||
class="!mb-0"
|
||||
>
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="واحد" :help="unitHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.unit" :items="unitItems" valueName="value" keyName="value" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="showDirectPriceField"
|
||||
name="direct_price"
|
||||
:rules="inputRules()"
|
||||
class="!mb-0"
|
||||
>
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="نوع قیمت" :help="directPriceHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.direct_price" :items="priceItems" valueName="value" keyName="key" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="isStore && !isMeltedGroup"
|
||||
name="inventory"
|
||||
:rules="inputRules()"
|
||||
class="!mb-0"
|
||||
>
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="تعداد موجودی" :help="inventoryHelp" size="sm" />
|
||||
</template>
|
||||
<BasicInput v-model:value="form.inventory" type="number" />
|
||||
</a-form-item>
|
||||
<div
|
||||
v-if="form.amount && form.amount < 1 && 0 < form.amount && tradeWeightUnit === 'گرم'"
|
||||
v-if="weightOption === '1' && !isMeltedGroup && form.amount && form.amount < 1 && 0 < form.amount && tradeWeightUnit === 'گرم'"
|
||||
class="flex items-end pb-1 text-sm text-gray-500"
|
||||
>
|
||||
معادل {{ form.amount * 1000 }} سوت
|
||||
@@ -357,73 +395,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="showUnitField || showDirectPriceField || (isStore && !isMeltedGroup)"
|
||||
class="grid gap-4 md:grid-cols-2 xl:grid-cols-3"
|
||||
>
|
||||
<a-form-item
|
||||
v-if="showUnitField"
|
||||
name="unit"
|
||||
:rules="inputRules()"
|
||||
class="!mb-0"
|
||||
>
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="واحد" :help="unitHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.unit" :items="unitItems" valueName="value" keyName="value" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="showDirectPriceField"
|
||||
name="direct_price"
|
||||
:rules="inputRules()"
|
||||
class="!mb-0"
|
||||
>
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="نوع قیمت" :help="directPriceHelp" size="sm" />
|
||||
</template>
|
||||
<BasicSelect v-model:value="form.direct_price" :items="priceItems" valueName="value" keyName="key" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="isStore && !isMeltedGroup"
|
||||
name="inventory"
|
||||
:rules="inputRules()"
|
||||
class="!mb-0"
|
||||
>
|
||||
<template #label>
|
||||
<DashboardLabelWithHelp label="تعداد موجودی" :help="inventoryHelp" size="sm" />
|
||||
</template>
|
||||
<BasicInput v-model:value="form.inventory" type="number" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<div class="product-editor-panel flex flex-col gap-0 rounded-lg overflow-hidden">
|
||||
<div class="product-visibility-row">
|
||||
<DashboardLabelWithHelp label="نمایش در لیست محصولات" :help="showInListHelp" size="sm" />
|
||||
<a-form-item name="show_in_list" class="!mb-0">
|
||||
<!-- نمایش -->
|
||||
<div class="product-section">
|
||||
<div class="product-section__title">تنظیمات نمایش</div>
|
||||
<div class="product-visibility-panel">
|
||||
<div class="product-visibility-row">
|
||||
<span class="text-sm">نمایش در لیست محصولات</span>
|
||||
<a-switch v-model:checked="form.show_in_list" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="product-visibility-row">
|
||||
<DashboardLabelWithHelp label="نمایش در داراییها" :help="showInAssetsHelp" size="sm" />
|
||||
<a-form-item name="show_in_assets" class="!mb-0">
|
||||
</div>
|
||||
<div class="product-visibility-row">
|
||||
<span class="text-sm">نمایش در داراییها</span>
|
||||
<a-switch v-model:checked="form.show_in_assets" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="product-visibility-row">
|
||||
<DashboardLabelWithHelp label="نمایش در تابلو TV" :help="showOnTvHelp" size="sm" />
|
||||
<a-form-item name="show_on_tv" class="!mb-0">
|
||||
</div>
|
||||
<div class="product-visibility-row">
|
||||
<span class="text-sm">نمایش در تابلو TV</span>
|
||||
<a-switch v-model:checked="form.show_on_tv" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<TvFormulaPriceSection
|
||||
v-if="form.show_on_tv"
|
||||
:model-value="form"
|
||||
:reference-middle-price="formulaReferenceMiddlePrice"
|
||||
:product-amount="Number(form.amount) || 0"
|
||||
@update:model-value="onTvFormulaFormPatch"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TvFormulaPriceSection
|
||||
v-if="form.show_on_tv"
|
||||
:model-value="form"
|
||||
:reference-middle-price="formulaReferenceMiddlePrice"
|
||||
:product-amount="Number(form.amount) || 0"
|
||||
@update:model-value="onTvFormulaFormPatch"
|
||||
/>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
|
||||
@@ -980,8 +976,23 @@ defineExpose({
|
||||
@apply flex flex-col items-stretch gap-2;
|
||||
}
|
||||
|
||||
.product-section {
|
||||
@apply flex flex-col gap-4 rounded-lg p-4;
|
||||
border: 1px solid var(--ant-color-border-secondary, rgba(0, 0, 0, 0.06));
|
||||
}
|
||||
|
||||
.product-section__title {
|
||||
@apply text-sm font-bold;
|
||||
color: var(--ant-color-text-secondary, rgba(0, 0, 0, 0.45));
|
||||
}
|
||||
|
||||
.product-visibility-panel {
|
||||
@apply flex flex-col rounded-md overflow-hidden;
|
||||
border: 1px solid var(--ant-color-border-secondary, rgba(0, 0, 0, 0.06));
|
||||
}
|
||||
|
||||
.product-visibility-row {
|
||||
@apply flex items-center justify-between gap-3 px-3 py-2;
|
||||
@apply flex items-center justify-between gap-3 px-3 py-2.5;
|
||||
border-bottom: 1px solid var(--ant-color-border-secondary, rgba(0, 0, 0, 0.06));
|
||||
}
|
||||
.product-visibility-row:last-child {
|
||||
|
||||
Reference in New Issue
Block a user