fixed amount
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { Product } from '@/models/products'
|
||||
import { formatWeightAmount, usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { formatGoldAmount, formatWeightAmount, usePriceWithoutType } from '@/utils/usePrice'
|
||||
import type { UserWalletLine } from '@/models/wallet'
|
||||
import type { ProductFile } from '@/utils/file'
|
||||
import type { WalletInventoryCard, WalletMetalTotal } from '@/models/walletAssets'
|
||||
@@ -587,8 +587,10 @@ export function formatProductWalletBalanceText(
|
||||
const quantity = card ? Number(card.quantity ?? 0) : Number(mainWalletGold ?? 0)
|
||||
const unit = card?.unit ?? getProductQuantityUnit(product)
|
||||
const title = product?.title?.trim() || 'محصول'
|
||||
const formattedQty =
|
||||
unit === 'عدد' ? usePriceWithoutType(quantity, false) : formatGoldAmount(quantity)
|
||||
|
||||
return `موجودی کیف ${title}: ${quantity} ${unit}`
|
||||
return `موجودی کیف ${title}: ${formattedQty} ${unit}`
|
||||
}
|
||||
|
||||
export function isSingleMetalCatalog(metalIds: number[]): boolean {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
usesQuantityTrade,
|
||||
} from '@/utils/productCategories'
|
||||
import { formatInventoryCardValue } from '@/utils/productAssets'
|
||||
import { TRADE_GRAM_DISPLAY_DECIMALS } from '@/utils/serviceFee'
|
||||
import { formatGoldAmount } from '@/utils/usePrice'
|
||||
|
||||
/** @deprecated از isMeltedTradeGroup استفاده کنید */
|
||||
@@ -636,8 +637,6 @@ export function resolveTransactionTradeProduct(
|
||||
return item.wallet?.product ?? null
|
||||
}
|
||||
|
||||
const MELTED_GOLD_TRANSACTION_DECIMALS = 5
|
||||
|
||||
/** معامله آبشده / کیف طلای اصلی — نه سکه و محصول تعدادی */
|
||||
export function isMeltedGoldTransaction(
|
||||
item?: (TransactionTradeProductSource & { type?: number | null; title?: string | null }) | null,
|
||||
@@ -685,7 +684,7 @@ export function formatTransactionGoldAmount(
|
||||
item?: (TransactionTradeProductSource & { type?: number | null; title?: string | null }) | null,
|
||||
amount?: number | null,
|
||||
): string {
|
||||
const decimals = isMeltedGoldTransaction(item) ? MELTED_GOLD_TRANSACTION_DECIMALS : 3
|
||||
const decimals = isMeltedGoldTransaction(item) ? TRADE_GRAM_DISPLAY_DECIMALS : 3
|
||||
return formatGoldAmount(amount, decimals)
|
||||
}
|
||||
|
||||
|
||||
+31
-10
@@ -9,6 +9,24 @@ export const feeDeductFromGold = ref(false)
|
||||
/** آخرین فیلدی که کاربر مستقیم ویرایش کرده — مبنای بهروزرسانی هنگام تغییر قیمت */
|
||||
export type TradeInputLock = 'gram' | 'rial' | null
|
||||
|
||||
/** حداکثر اعشار ذخیره/ارسال به سرور (مطابق orders.amount) */
|
||||
export const TRADE_GRAM_STORAGE_DECIMALS = 10
|
||||
|
||||
/** حداکثر اعشار نمایش به کاربر در اپ */
|
||||
export const TRADE_GRAM_DISPLAY_DECIMALS = 5
|
||||
|
||||
export function normalizeOrderGoldAmount(grams?: number | null): number {
|
||||
const value = Number(grams ?? 0)
|
||||
if (!Number.isFinite(value) || value === 0) return 0
|
||||
return parseFloat(value.toFixed(TRADE_GRAM_STORAGE_DECIMALS))
|
||||
}
|
||||
|
||||
export function formatTradeGramDisplay(grams?: number | null): number {
|
||||
const value = Number(grams ?? 0)
|
||||
if (!Number.isFinite(value)) return 0
|
||||
return parseFloat(value.toFixed(TRADE_GRAM_DISPLAY_DECIMALS))
|
||||
}
|
||||
|
||||
function feeRate() {
|
||||
return Number(serviceFeePercentage.value)
|
||||
}
|
||||
@@ -46,7 +64,7 @@ export function calcFeeInGrams(goldValue?: number | null) {
|
||||
/** گرم معادل برای دریافت دقیق مبلغ ریالی در فروش */
|
||||
export function calcGoldAmountFromTargetRial(rialAmount: number, unitPriceRial: number) {
|
||||
if (!rialAmount || !unitPriceRial) return 0
|
||||
return parseFloat((rialAmount / unitPriceRial).toFixed(6))
|
||||
return normalizeOrderGoldAmount(rialAmount / unitPriceRial)
|
||||
}
|
||||
|
||||
/** وقتی کاربر گرم را قفل کرده — ریال نمایشی/قابل پرداخت از همان گرم */
|
||||
@@ -78,16 +96,15 @@ export function calcGramFromLockedRial(rialAmount: number, unitPriceRial: number
|
||||
|
||||
if (isBuy) {
|
||||
if (feeDeductFromGold.value) {
|
||||
return parseFloat((rial / (unit * (1 + fee))).toFixed(6))
|
||||
return rial / (unit * (1 + fee))
|
||||
}
|
||||
const grossGrams = rial / unit
|
||||
return parseFloat((grossGrams * (1 - fee)).toFixed(6))
|
||||
return (rial / unit) * (1 - fee)
|
||||
}
|
||||
|
||||
if (feeDeductFromGold.value) {
|
||||
return parseFloat((rial / unit).toFixed(6))
|
||||
return rial / unit
|
||||
}
|
||||
return parseFloat((rial / (unit * (1 - fee))).toFixed(6))
|
||||
return rial / (unit * (1 - fee))
|
||||
}
|
||||
|
||||
/** مبلغ ریالی قفلشده توسط کاربر — برای ارسال به سرور */
|
||||
@@ -131,8 +148,12 @@ export function calcOrderGoldAmount(
|
||||
const cash = Number(goldCash ?? 0)
|
||||
const unit = Number(unitPriceRial ?? 0)
|
||||
|
||||
if (isBuy && inputLock === 'rial' && !feeDeductFromGold.value && cash > 0 && unit > 0) {
|
||||
return parseFloat((cash / unit).toFixed(6))
|
||||
if (isBuy && inputLock === 'rial' && cash > 0 && unit > 0) {
|
||||
if (feeDeductFromGold.value) {
|
||||
const fee = feeRate()
|
||||
return normalizeOrderGoldAmount(cash / (unit * (1 + fee)))
|
||||
}
|
||||
return normalizeOrderGoldAmount(cash / unit)
|
||||
}
|
||||
|
||||
if (!isBuy && feeDeductFromGold.value) {
|
||||
@@ -140,7 +161,7 @@ export function calcOrderGoldAmount(
|
||||
return calcGoldAmountFromTargetRial(cash, unit)
|
||||
}
|
||||
if (inputLock !== 'rial') {
|
||||
return parseFloat(gold.toFixed(6))
|
||||
return normalizeOrderGoldAmount(gold)
|
||||
}
|
||||
const targetCash = calcSellTargetCash(goldCash, goldValue, unitPriceRial, inputLock)
|
||||
if (targetCash != null && unit > 0) {
|
||||
@@ -148,7 +169,7 @@ export function calcOrderGoldAmount(
|
||||
}
|
||||
}
|
||||
|
||||
return parseFloat(gold.toFixed(6))
|
||||
return normalizeOrderGoldAmount(gold)
|
||||
}
|
||||
|
||||
/** مبلغ ریالی دقیق دریافتی در فروش (فقط وقتی کاربر با ریال وارد کرده) */
|
||||
|
||||
@@ -143,7 +143,7 @@ export function getTransactionGoldAmount(item: TransactionPriceSource): number {
|
||||
return gold
|
||||
}
|
||||
|
||||
export function formatGoldAmount(amount?: number | null, decimals = 3): string {
|
||||
export function formatGoldAmount(amount?: number | null, decimals = 5): string {
|
||||
const num = Number(amount)
|
||||
if (!Number.isFinite(num)) return '0'
|
||||
return formatGroupedPrice(Number(num.toFixed(decimals)), false)
|
||||
|
||||
@@ -102,20 +102,6 @@
|
||||
@change="percentChange" />
|
||||
</a-form-item>
|
||||
</Transition>
|
||||
<!-- <Transition mode="out-in" name="fade">
|
||||
<div v-if="priceErrorVisible" class="flex gap-1 items-center text-xs mt-[-15px] text-orange-600">
|
||||
<BasicIcon icon="vuesax-linear:danger" />
|
||||
ارزش کل وارد شده بر حسب گرم طلا محاسبه خواهد شد و قیمت وارد شده معادل {{ usePrice(finalPrice) }} می
|
||||
باشد!
|
||||
</div>
|
||||
</Transition>-->
|
||||
<Transition mode="out-in" name="fade">
|
||||
<div v-if="priceErrorVisible" class="flex gap-1 items-center text-xs mt-[-15px] text-blue-600">
|
||||
<BasicIcon icon="vuesax-linear:info-circle" />
|
||||
ارزش کل وارد شده بر حسب گرم طلا محاسبه خواهد شد و قیمت وارد شده معادل {{ usePrice(parseInt(finalPrice.toFixed(0))) }} می
|
||||
باشد!
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
<GoldLoading v-model:show="infoVisible" />
|
||||
@@ -173,7 +159,7 @@
|
||||
<div class="flex justify-between ">
|
||||
<div>وزن:</div>
|
||||
<div class="flex items-center">
|
||||
<div class="font-bold">{{ form.goldValue }}</div>
|
||||
<div class="font-bold">{{ displayTradeGoldAmount }}</div>
|
||||
<div class="text-xs mr-1">{{ weightUnit }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -195,7 +181,7 @@
|
||||
<div v-if="isBuy && feeDeductFromGold" class="flex justify-between mt-3">
|
||||
<div>طلا دریافتی:</div>
|
||||
<div class="flex items-center">
|
||||
<div class="font-bold">{{ form.goldValue }}</div>
|
||||
<div class="font-bold">{{ displayTradeGoldAmount }}</div>
|
||||
<div class="text-xs mr-1">{{ weightUnit }} (دقیق — کارمزد از ریال)</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -235,7 +221,7 @@
|
||||
<div class="flex justify-between ">
|
||||
<div>وزن:</div>
|
||||
<div class="flex items-center">
|
||||
<div class="font-bold">{{ form.goldValue }}</div>
|
||||
<div class="font-bold">{{ displayTradeGoldAmount }}</div>
|
||||
<div class="text-xs mr-1">{{ weightUnit }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -257,7 +243,7 @@
|
||||
<div v-if="isBuy && feeDeductFromGold" class="flex justify-between mt-3">
|
||||
<div>طلا دریافتی:</div>
|
||||
<div class="flex items-center">
|
||||
<div class="font-bold">{{ form.goldValue }}</div>
|
||||
<div class="font-bold">{{ displayTradeGoldAmount }}</div>
|
||||
<div class="text-xs mr-1">{{ weightUnit }} (دقیق — کارمزد از ریال)</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -306,7 +292,7 @@ import img1 from '@/assets/img/home_ly2.svg'
|
||||
import { usePrice, usePriceWithoutType } from '@/utils/usePrice'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import type { Gold } from '@/models/gold'
|
||||
import { isIphone, loading, loadingMore, toFixedDownThreeChar } from '@/utils'
|
||||
import { isIphone, loading, loadingMore } from '@/utils'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import router from '@/router'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
@@ -347,7 +333,9 @@ import {
|
||||
calcSellTargetCash,
|
||||
calcTradeTargetCash,
|
||||
feeDeductFromGold,
|
||||
formatTradeGramDisplay,
|
||||
loadServiceFeeFromSettings,
|
||||
normalizeOrderGoldAmount,
|
||||
serviceFeePercentage,
|
||||
type TradeInputLock,
|
||||
} from '@/utils/serviceFee'
|
||||
@@ -380,7 +368,6 @@ const confirmAction = ref<boolean>(false)
|
||||
const noCompleteVisible = ref<boolean>(false)
|
||||
const buyItems = ref<Transaction[]>([])
|
||||
const sellItems = ref<Transaction[]>([])
|
||||
const priceErrorVisible = ref<boolean>(false)
|
||||
const buyTableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
const sellTableOutput = ref<TableOutput<Transaction> | null>(null)
|
||||
const el = ref()
|
||||
@@ -480,6 +467,10 @@ const payablePrice = computed(() =>
|
||||
)
|
||||
const sellGoldDebit = computed(() => calcSellGoldDebit(orderGoldAmount.value, feeInGrams.value))
|
||||
|
||||
const displayTradeGoldAmount = computed(() =>
|
||||
formatTradeGramDisplay(orderGoldAmount.value)
|
||||
)
|
||||
|
||||
const minOrderCash = computed(() => productMinOrderCash(props.ProductItem, isBuy.value))
|
||||
const maxOrderCash = computed(() => productMaxOrderCash(props.ProductItem))
|
||||
const cashValidationMessage = computed(() =>
|
||||
@@ -653,7 +644,7 @@ function percentChange(val: number) {
|
||||
form.value.goldCash = unitCashCalculator.value * val
|
||||
calculateGold(form.value.goldCash)
|
||||
} else {
|
||||
form.value.goldValue = toFixedDownThreeChar(parseFloat(String(unitGoldCalculator.value * val)))
|
||||
form.value.goldValue = formatTradeGramDisplay(parseFloat(String(unitGoldCalculator.value * val)))
|
||||
calculateCash(form.value.goldValue)
|
||||
}
|
||||
} else {
|
||||
@@ -669,13 +660,6 @@ 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) || !inputLock.value) return
|
||||
@@ -707,7 +691,6 @@ watch([feeDeductFromGold, () => serviceFeePercentage.value], () => {
|
||||
|
||||
function calculateCash(val: number) {
|
||||
inputLock.value = 'gram'
|
||||
priceErrorVisible.value = false
|
||||
const unit = unitPrice.value
|
||||
if (!unit || Number.isNaN(unit)) return
|
||||
|
||||
@@ -727,14 +710,11 @@ function calculateGold(val: number) {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -757,7 +737,6 @@ function setIsBuy(val: boolean) {
|
||||
form.value.goldValue = undefined
|
||||
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')
|
||||
@@ -814,7 +793,7 @@ async function ok() {
|
||||
await createOrder({
|
||||
direction: isBuy.value ? 1 : 2,
|
||||
price: Math.round(unitPrice.value),
|
||||
amount: orderGoldAmount.value,
|
||||
amount: normalizeOrderGoldAmount(orderGoldAmount.value),
|
||||
target_cash: calcTradeTargetCash(form.value.goldCash, inputLock.value)
|
||||
?? calcSellTargetCash(
|
||||
form.value.goldCash,
|
||||
|
||||
Reference in New Issue
Block a user