show price in product editor

This commit is contained in:
2026-06-10 10:56:35 +03:30
parent 39f7ea00db
commit b7abe34f7e
3 changed files with 25 additions and 49 deletions
@@ -117,28 +117,30 @@
</div>
</div>
<div class="mt-2 rounded-lg border border-solid border-blue-200 bg-blue-50 p-3">
<div class="flex flex-wrap items-center justify-between gap-2">
<div class="text-sm font-600 text-gray-700">قیمت لحظه‌ای</div>
<AButton size="small" :loading="pricesLoading || appPriceLoading" @click="$emit('refreshPrices')">
<div class="mt-2 rounded-lg border border-solid border-blue-200 bg-blue-50 px-3 py-2">
<div class="flex flex-col gap-2 md:flex-row md:items-center md:justify-between md:gap-3">
<div class="flex flex-wrap items-center gap-x-3 gap-y-1 md:min-w-0 md:flex-1">
<span class="shrink-0 text-sm font-600 text-gray-700">قیمت لحظه‌ای:</span>
<span v-if="livePricePreview.status === 'ready'" class="text-base font-700 text-blue-700">
{{ usePrice(livePricePreview.amount) }}
</span>
<span v-else-if="livePricePreview.message" class="text-sm text-gray-500">
{{ livePricePreview.message }}
</span>
<span
v-if="livePricePreview.status === 'ready'"
class="truncate text-xs text-gray-500"
>
مبنا: {{ livePricePreview.source }}
<span v-if="Number(form.price_offset_percent) !== 0">
— تعدیل {{ form.price_offset_percent }}٪
</span>
</span>
</div>
<AButton size="small" class="shrink-0 self-end md:self-auto" @click="$emit('refreshPrices')">
بروزرسانی
</AButton>
</div>
<div v-if="livePricePreview.status === 'ready'" class="mt-2 text-lg font-700 text-blue-700">
{{ usePrice(livePricePreview.amount) }}
</div>
<div v-else-if="livePricePreview.status === 'loading'" class="mt-2 text-sm text-gray-500">
{{ livePricePreview.message }}
</div>
<div v-else class="mt-2 text-sm text-gray-500">
{{ livePricePreview.message }}
</div>
<div v-if="livePricePreview.status === 'ready'" class="mt-1 text-xs text-gray-500">
مبنا: {{ livePricePreview.source }}
<span v-if="Number(form.price_offset_percent) !== 0">
— تعدیل {{ form.price_offset_percent }}٪
</span>
</div>
</div>
<div
@@ -247,9 +249,7 @@ const props = defineProps<{
activeKey: string[]
pricesList: Array<{ id: string; name: string }>
pricesData: MethodePrices[]
pricesLoading: boolean
appLastPrice: (last & { price?: number }) | null
appPriceLoading: boolean
categoryItems: any[]
metalItems: any[]
priceItems: any[]
@@ -268,9 +268,7 @@ const livePricePreview = computed(() =>
methodOption: props.methodOption,
meltedPriceOption: props.meltedPriceOption as 'app' | 'fixed' | 'reference',
pricesData: props.pricesData,
appLastPrice: props.appLastPrice,
pricesLoading: props.pricesLoading,
appPriceLoading: props.appPriceLoading
appLastPrice: props.appLastPrice
})
)
@@ -24,9 +24,7 @@
:activeKey="activeKey_"
:pricesList="pricesList"
:pricesData="pricesData"
:pricesLoading="pricesLoading"
:appLastPrice="appLastPrice"
:appPriceLoading="appPriceLoading"
:categoryItems="categorySelectItems"
:metalItems="metalItems"
:priceItems="priceItems"
@@ -129,9 +127,7 @@ const priceItems: Array<Item> = [
]
const pricesData = ref<MethodePrices[]>([])
const pricesLoading = ref(false)
const appLastPrice = ref<(last & { price?: number }) | null>(null)
const appPriceLoading = ref(false)
let pricePollTimer: ReturnType<typeof setInterval> | undefined
const pricesList = computed(() =>
@@ -142,25 +138,19 @@ const pricesList = computed(() =>
)
async function fetchPrices() {
pricesLoading.value = true
try {
pricesData.value = await methodePrices()
} catch (err) {
console.error(err)
} finally {
pricesLoading.value = false
}
}
async function fetchAppPrice() {
appPriceLoading.value = true
try {
appLastPrice.value = await getLastPrice()
} catch (err) {
console.error(err)
appLastPrice.value = null
} finally {
appPriceLoading.value = false
}
}
+3 -15
View File
@@ -55,7 +55,6 @@ export function resolveAppBasePrice(lastPrice?: Partial<last> & { price?: number
export type ProductEditorPricePreview =
| { status: 'ready'; amount: number; source: string }
| { status: 'empty'; message: string }
| { status: 'loading'; message: string }
export function computeProductEditorPricePreview(input: {
form: {
@@ -68,8 +67,6 @@ export function computeProductEditorPricePreview(input: {
meltedPriceOption: MeltedPriceSource
pricesData: MethodePrices[]
appLastPrice?: (Partial<last> & { price?: number }) | null
pricesLoading?: boolean
appPriceLoading?: boolean
}): ProductEditorPricePreview {
const offsetPercent = Number(input.form.price_offset_percent ?? 0)
const melted = isMeltedTradeGroup(input.form.group_type)
@@ -83,12 +80,9 @@ export function computeProductEditorPricePreview(input: {
}
if (input.meltedPriceOption === 'app') {
if (input.appPriceLoading) {
return { status: 'loading', message: 'در حال دریافت قیمت اپ...' }
}
const base = resolveAppBasePrice(input.appLastPrice)
if (base <= 0) {
return { status: 'empty', message: 'قیمت اپ در دسترس نیست' }
return { status: 'empty', message: '' }
}
return {
status: 'ready',
@@ -100,12 +94,9 @@ export function computeProductEditorPricePreview(input: {
if (!input.form.reading_method) {
return { status: 'empty', message: 'مرجع قیمت را انتخاب کنید' }
}
if (input.pricesLoading) {
return { status: 'loading', message: 'در حال دریافت قیمت مرجع...' }
}
const entry = findMethodPriceEntry(input.pricesData, input.form.reading_method)
if (!entry) {
return { status: 'empty', message: 'مرجع قیمت یافت نشد' }
return { status: 'empty', message: '' }
}
const { base, profit } = normalizeReferenceBase(entry)
return {
@@ -125,12 +116,9 @@ export function computeProductEditorPricePreview(input: {
if (!input.form.reading_method) {
return { status: 'empty', message: 'مرجع قیمت را انتخاب کنید' }
}
if (input.pricesLoading) {
return { status: 'loading', message: 'در حال دریافت قیمت مرجع...' }
}
const entry = findMethodPriceEntry(input.pricesData, input.form.reading_method)
if (!entry) {
return { status: 'empty', message: 'مرجع قیمت یافت نشد' }
return { status: 'empty', message: '' }
}
const { base, profit } = normalizeReferenceBase(entry)
return {