From 83cce69069d1faeaaa702e842623a03d357ada72 Mon Sep 17 00:00:00 2001 From: adonis Date: Thu, 2 Jul 2026 19:53:25 +0330 Subject: [PATCH] price calulator changed --- src/utils/serviceFee.ts | 87 ++++++++++++++++++++++++++++---- src/views/base/gold/index.vue | 95 +++++++++++++++++++++++------------ 2 files changed, 140 insertions(+), 42 deletions(-) diff --git a/src/utils/serviceFee.ts b/src/utils/serviceFee.ts index c91b6aa..1143a8e 100644 --- a/src/utils/serviceFee.ts +++ b/src/utils/serviceFee.ts @@ -6,6 +6,13 @@ export const serviceFeePercentage = ref(0.01) /** true = مبالغ رند: فروش → ریال دقیق (کارمزد از طلا)؛ خرید → وزن دقیق (کارمزد از ریال) */ export const feeDeductFromGold = ref(false) +/** آخرین فیلدی که کاربر مستقیم ویرایش کرده — مبنای به‌روزرسانی هنگام تغییر قیمت */ +export type TradeInputLock = 'gram' | 'rial' | null + +function feeRate() { + return Number(serviceFeePercentage.value) +} + export async function loadServiceFeeFromSettings() { try { const settings = await getSettings() @@ -42,6 +49,47 @@ export function calcGoldAmountFromTargetRial(rialAmount: number, unitPriceRial: return parseFloat((rialAmount / unitPriceRial).toFixed(6)) } +/** وقتی کاربر گرم را قفل کرده — ریال نمایشی/قابل پرداخت از همان گرم */ +export function calcRialFromLockedGram(displayGram: number, unitPriceRial: number, isBuy: boolean) { + const grams = Number(displayGram) + const unit = Number(unitPriceRial) + if (!grams || !unit) return 0 + const fee = feeRate() + + if (isBuy) { + if (feeDeductFromGold.value) { + return Math.round(grams * unit * (1 + fee)) + } + return Math.round(grams * unit) + } + + if (feeDeductFromGold.value) { + return Math.round(grams * unit) + } + return Math.round(grams * unit * (1 - fee)) +} + +/** وقتی کاربر ریال را قفل کرده — گرم نمایشی از همان مبلغ */ +export function calcGramFromLockedRial(rialAmount: number, unitPriceRial: number, isBuy: boolean) { + const rial = Number(rialAmount) + const unit = Number(unitPriceRial) + if (!rial || !unit) return 0 + const fee = feeRate() + + if (isBuy) { + if (feeDeductFromGold.value) { + return parseFloat((rial / (unit * (1 + fee))).toFixed(6)) + } + const grossGrams = rial / unit + return parseFloat((grossGrams * (1 - fee)).toFixed(6)) + } + + if (feeDeductFromGold.value) { + return parseFloat((rial / unit).toFixed(6)) + } + return parseFloat((rial / (unit * (1 - fee))).toFixed(6)) +} + /** مبلغ نهایی قابل پرداخت (خرید) یا دریافت (فروش) به ریال */ export function calcPayablePriceRial( finalPriceRial: number, @@ -57,22 +105,35 @@ export function calcPayablePriceRial( return isBuy ? finalPriceRial : Math.max(0, finalPriceRial - feeInRial) } -/** وزن ارسالی به سرور — فروش رند: از مبلغ ریالی هدف */ +/** وزن ارسالی به سرور */ export function calcOrderGoldAmount( goldValue?: number | null, goldCash?: number | null, unitPriceRial?: number, - isBuy?: boolean + isBuy?: boolean, + inputLock?: TradeInputLock ) { const gold = Number(goldValue ?? 0) - if (isBuy || !feeDeductFromGold.value) { - return parseFloat(gold.toFixed(6)) - } - const targetCash = calcSellTargetCash(goldCash, goldValue, unitPriceRial) + const cash = Number(goldCash ?? 0) const unit = Number(unitPriceRial ?? 0) - if (targetCash != null && unit > 0) { - return calcGoldAmountFromTargetRial(targetCash, unit) + + if (isBuy && inputLock === 'rial' && !feeDeductFromGold.value && cash > 0 && unit > 0) { + return parseFloat((cash / unit).toFixed(6)) } + + if (!isBuy && feeDeductFromGold.value) { + if (inputLock === 'rial' && cash > 0 && unit > 0) { + return calcGoldAmountFromTargetRial(cash, unit) + } + if (inputLock !== 'rial') { + return parseFloat(gold.toFixed(6)) + } + const targetCash = calcSellTargetCash(goldCash, goldValue, unitPriceRial, inputLock) + if (targetCash != null && unit > 0) { + return calcGoldAmountFromTargetRial(targetCash, unit) + } + } + return parseFloat(gold.toFixed(6)) } @@ -80,10 +141,16 @@ export function calcOrderGoldAmount( export function calcSellTargetCash( goldCash?: number | null, goldValue?: number | null, - unitPriceRial?: number + unitPriceRial?: number, + inputLock?: TradeInputLock ) { + if (!feeDeductFromGold.value) return undefined + if (inputLock === 'gram') return undefined + const cash = Number(goldCash ?? 0) - if (!feeDeductFromGold.value || cash <= 0) return undefined + if (cash <= 0) return undefined + if (inputLock === 'rial') return Math.round(cash) + const gold = Number(goldValue ?? 0) const unit = Number(unitPriceRial ?? 0) if (gold > 0 && unit > 0) { diff --git a/src/views/base/gold/index.vue b/src/views/base/gold/index.vue index a95506f..3d5fe87 100644 --- a/src/views/base/gold/index.vue +++ b/src/views/base/gold/index.vue @@ -330,7 +330,19 @@ import { getLastPrices, getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@ import type { Product } from '@/models/products' import { useFundUserStore } from '@/store/fundStore' import {useConfigStore} from "@/store/configStore"; -import { calcFeeInGrams, calcOrderGoldAmount, calcPayablePriceRial, calcSellGoldDebit, calcSellTargetCash, feeDeductFromGold, loadServiceFeeFromSettings } from '@/utils/serviceFee' +import { + calcFeeInGrams, + calcGramFromLockedRial, + calcOrderGoldAmount, + calcPayablePriceRial, + calcRialFromLockedGram, + calcSellGoldDebit, + calcSellTargetCash, + feeDeductFromGold, + loadServiceFeeFromSettings, + serviceFeePercentage, + type TradeInputLock, +} from '@/utils/serviceFee' import { isStoreClosed, getStoreClosedMessage } from '@/utils/storeHours' import { formatCashWalletBalanceText, getWeightUnit } from '@/utils/productDealMethod' import { formatProductWalletBalanceText, getCashWalletBalance, getProductInventoryQuantity } from '@/utils/productAssets' @@ -386,6 +398,7 @@ const contentClass = computed(() => { return 'mt-5 px-3 pb-4' }) const isBuy = ref(true) +const inputLock = ref(null) const tradeProductLabel = computed(() => { const title = props.ProductItem?.title?.trim() @@ -436,7 +449,13 @@ const unitPrice = computed(() => { return isBuy.value ? getTradeBuyPrice(lastPrice.value) : getTradeSellPrice(lastPrice.value) }) const orderGoldAmount = computed(() => - calcOrderGoldAmount(form.value?.goldValue, form.value?.goldCash, unitPrice.value, isBuy.value) + calcOrderGoldAmount( + form.value?.goldValue, + form.value?.goldCash, + unitPrice.value, + isBuy.value, + inputLock.value + ) ) const feeInGrams = computed(() => calcFeeInGrams(orderGoldAmount.value)) const finalPrice = computed(() => orderGoldAmount.value * unitPrice.value) @@ -447,7 +466,7 @@ const payablePrice = computed(() => finalPrice.value, feeInRial.value, isBuy.value, - !isBuy.value ? form.value?.goldCash : undefined + !isBuy.value && inputLock.value === 'rial' ? form.value?.goldCash : undefined ) ) const sellGoldDebit = computed(() => calcSellGoldDebit(orderGoldAmount.value, feeInGrams.value)) @@ -620,20 +639,18 @@ onMounted(() => { }) function percentChange(val: number) { - if (val !== 0) + if (val !== 0) { if (isBuy.value) { form.value.goldCash = unitCashCalculator.value * val calculateGold(form.value.goldCash) - calculateCash(form.value.goldValue) } else { - // console.log((unitGoldCalculator.value * val).toFixed(2)) - // form.value.goldValue = parseFloat((unitGoldCalculator.value * val).toFixed(2)) - form.value.goldValue = toFixedDownThreeChar(parseFloat(unitGoldCalculator.value * val)) + form.value.goldValue = toFixedDownThreeChar(parseFloat(String(unitGoldCalculator.value * val))) calculateCash(form.value.goldValue) } - else { + } else { form.value.goldValue = undefined form.value.goldCash = undefined + inputLock.value = null } } @@ -643,13 +660,22 @@ const unitCashCalculator = computed(() => { return cashWalletBalance.value / 100 }) +function formatTradeGramDisplay(grams: number) { + if (Number(serviceFeePercentage.value) > 0) { + return parseFloat(grams.toFixed(6)) + } + return toFixedDownThreeChar(grams) +} + function syncFormWithLatestPrice() { const unit = unitPrice.value - if (!unit || Number.isNaN(unit)) return + if (!unit || Number.isNaN(unit) || !inputLock.value) return - const goldValue = form.value.goldValue - if (goldValue !== undefined && goldValue !== null && goldValue !== '' && !isNaN(Number(goldValue))) { - calculateCash(Number(goldValue)) + if (inputLock.value === 'gram') { + const goldValue = form.value.goldValue + if (goldValue !== undefined && goldValue !== null && goldValue !== '' && !isNaN(Number(goldValue))) { + calculateCash(Number(goldValue)) + } return } @@ -666,39 +692,37 @@ watch( } ) +watch([feeDeductFromGold, () => serviceFeePercentage.value], () => { + syncFormWithLatestPrice() +}) + function calculateCash(val: number) { + inputLock.value = 'gram' priceErrorVisible.value = false const unit = unitPrice.value if (!unit || Number.isNaN(unit)) return - form.value.goldCash = val ? parseFloat((val * unit).toFixed(0)) : undefined + if (val === undefined || val === null || Number.isNaN(val)) { + form.value.goldCash = undefined + inputLock.value = null + return + } + + form.value.goldCash = calcRialFromLockedGram(val, unit, isBuy.value) } function calculateGold(val: number) { + inputLock.value = 'rial' const unit = unitPrice.value if (!unit || Number.isNaN(unit)) return - if (isBuy.value) { - if (val) { - form.value.goldValue = toFixedDownThreeChar(parseFloat(String(val / unit))) - priceErrorVisible.value = parseInt(String(finalPrice.value)) > 0 - } else if (val.toString() === '') { - form.value.goldValue = undefined - priceErrorVisible.value = false - } else { - form.value.goldValue = 0 - priceErrorVisible.value = false - } - } else if (val) { - if (!isBuy.value && feeDeductFromGold.value) { - form.value.goldValue = parseFloat((val / unit).toFixed(6)) - } else { - form.value.goldValue = toFixedDownThreeChar(parseFloat(String(val / unit))) - } + if (val) { + form.value.goldValue = formatTradeGramDisplay(calcGramFromLockedRial(val, unit, isBuy.value)) priceErrorVisible.value = parseInt(String(finalPrice.value)) > 0 } else if (val.toString() === '') { form.value.goldValue = undefined priceErrorVisible.value = false + inputLock.value = null } else { form.value.goldValue = 0 priceErrorVisible.value = false @@ -725,6 +749,7 @@ function setIsBuy(val: boolean) { form.value.goldCash = undefined form.value.percentWallet = 0 priceErrorVisible.value = false + inputLock.value = null // console.log(bganim.value.classList) // bganim?.value?.classList.add(val?'right':'left') // bganim?.value?.style.transform = `translateX(${val ? '0' : '-100'});` @@ -778,7 +803,12 @@ async function ok() { direction: isBuy.value ? 1 : 2, price: Math.round(unitPrice.value), amount: orderGoldAmount.value, - target_cash: calcSellTargetCash(form.value.goldCash, form.value.goldValue, unitPrice.value), + target_cash: calcSellTargetCash( + form.value.goldCash, + form.value.goldValue, + unitPrice.value, + inputLock.value + ), abshode_id: props.ProductItem?.id, }) confirmAction.value = false @@ -790,6 +820,7 @@ async function ok() { goldCash: undefined, percentWallet: undefined } + inputLock.value = null message.success('سفارش شما با موفقیت انجام شد') await fundStore.getMyFund() } catch (e) {