some trigger handled

This commit is contained in:
2026-06-10 18:40:29 +03:30
parent 5b525bd2c7
commit 84db7b013d
13 changed files with 264 additions and 117 deletions
+1
View File
@@ -17,6 +17,7 @@ export function useWalletAssets() {
return assetsPromise
}
// سرور مرجع دارایی‌هاست (main_wallet_products هم سمت سرور هندل می‌شود)؛ کلاینت فقط نمایش می‌دهد
assetsPromise = Promise.all([getWalletAssets(), getProducts()])
.then(([data, catalog]) => {
assetsSummary.value = {
+1
View File
@@ -12,6 +12,7 @@ export interface Product {
unit: string
active: boolean
show: boolean
show_in_assets?: boolean
open_sell: boolean
open_buy: boolean
group_type:string
+2
View File
@@ -20,6 +20,8 @@ export interface WalletInventoryCard {
unit_weight?: string | null
show_in_assets: boolean
is_melted?: boolean
/** محصول متصل به کیف اصلی (main_wallet_products) — موجودی = gold کیف اصلی */
is_main_wallet?: boolean
file?: ProductFile | null
}
+32 -16
View File
@@ -2,7 +2,10 @@ import { getLastPrice, getPrice } from '@/api/home'
import type { Price, PriceUp } from '@/models/home'
import { ref } from 'vue'
let interval: ReturnType<typeof setInterval> | undefined
const LAST_INTERVAL_MS = 10000
let lastInterval: ReturnType<typeof setInterval> | undefined
let lastSubscribers = 0
/** @deprecated از lastPrice استفاده کنید — برای سازگاری با کد قدیمی sync می‌شود */
export const price = ref<Price>()
@@ -23,18 +26,38 @@ export function normalizePriceResponse(data: Price): Price {
return data
}
/** polling /api/price/last — فقط صفحه اصلی */
export function startLastPricePolling() {
lastSubscribers++
if (lastInterval) {
return
}
lastInterval = setInterval(() => {
void getLastPrices()
}, LAST_INTERVAL_MS)
}
/** @deprecated از startLastPricePolling استفاده کنید */
export async function setIntervalGetAllPrice() {
try {
interval = setInterval(async () => {
await getLastPrices()
}, 10000)
} catch (e) {
console.log(e)
startLastPricePolling()
}
/** @deprecated از startLastPricePolling استفاده کنید */
export async function setIntervalGetLastPrice() {
startLastPricePolling()
}
export function stopLastPricePolling() {
lastSubscribers = Math.max(0, lastSubscribers - 1)
if (lastSubscribers === 0 && lastInterval) {
clearInterval(lastInterval)
lastInterval = undefined
}
}
export async function setIntervalGetLastPrice() {
return setIntervalGetAllPrice()
/** @deprecated از stopLastPricePolling استفاده کنید */
export function stopPriceInterval() {
stopLastPricePolling()
}
/** @deprecated فقط getLastPrices را صدا بزنید */
@@ -79,13 +102,6 @@ export async function getLastPrices() {
}
}
export function stopPriceInterval() {
if (interval) {
clearInterval(interval)
interval = undefined
}
}
export function percentPriceChanged() {
if (!olderPrice.value) {
return 0
+84 -10
View File
@@ -1,8 +1,9 @@
import type { Product } from '@/models/products'
import type { UserWalletLine } from '@/models/wallet'
import type { ProductFile } from '@/utils/file'
import type { WalletInventoryCard, WalletMetalTotal } from '@/models/walletAssets'
import { getFileUrl } from '@/utils/file'
import { isCountBasedProduct, type ProductUnitSource } from '@/utils/productDealMethod'
import { isCountBasedProduct, getProductQuantityUnit, type ProductUnitSource } from '@/utils/productDealMethod'
import { isMeltedTradeGroup, normalizeProductGroupType, LEGACY_GROUP_KATOD } from '@/utils/productCategories'
import defaultImg from '@/assets/img/defaultAbshodeh.svg'
import goyImg from '@/assets/img/goyImg.svg'
@@ -54,16 +55,47 @@ export function sumInventoryCardsWeight(
.reduce((sum, card) => sum + Number(card.quantity ?? 0), 0)
}
export function resolveSummaryMetalWeight(
metal: { metal_id: number; total_weight: number },
cards: Array<{ metal_id?: number; quantity?: number }>
): number {
const cardWeight = sumInventoryCardsWeight(cards, metal.metal_id)
if (cardWeight > 0) {
return Number(cardWeight.toFixed(3))
}
/** ردیف‌های جزئی action sheet — فقط محصولاتی که show_in_assets روشن است. */
export function assetSheetInventoryCards<T extends { metal_id?: number; show_in_assets?: boolean }>(
cards: T[],
metalId?: number
): T[] {
return cards.filter((card) => {
if (!card.show_in_assets) {
return false
}
if (metalId == null) {
return true
}
return Number(card.metal_id) === metalId
})
}
return metal.total_weight
/** همه کارت‌های صفحه دارایی‌ها — بدون فیلتر show_in_assets. */
export function fundPageInventoryCards<T>(cards: T[]): T[] {
return cards.filter((card) => Number((card as { quantity?: number }).quantity ?? 0) > 0)
}
export function resolveSummaryMetalWeight(
metal: { total_weight: number },
_cards?: Array<{ metal_id?: number; quantity?: number }>
): number {
return Number(metal.total_weight ?? 0)
}
/** متن توضیح مودال دارایی فلزی — بر اساس metal_totals سرور، بدون هاردکد طلا */
export function formatMetalAssetsInfoText(metal: WalletMetalTotal): string {
const unit = metal.unit || 'گرم'
return `${metal.label}: مجموع کیف محصولات (${metal.product_weight} ${unit}) + موجودی کیف اصلی (${metal.melted_weight} ${unit})`
}
function formatRialNumber(value: number): string {
return Math.round(value).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
/** متن توضیح مودال دارایی ریالی — cash_wallet + assets_rial_value */
export function formatRialAssetsInfoText(cashWallet: number, assetsRialValue: number): string {
return `مجموع کیف پول ریالی (${formatRialNumber(cashWallet)} ریال) + معادل ریالی محصولات (${formatRialNumber(assetsRialValue)} ریال)`
}
export function formatInventoryCardValue(card: {
@@ -76,6 +108,48 @@ export function formatInventoryCardValue(card: {
return `${quantity} ${unit}`
}
export function findProductInventoryCard(
cards: WalletInventoryCard[],
productId?: number | null
): WalletInventoryCard | undefined {
if (!productId) {
return undefined
}
return cards.find((item) => Number(item.product_id) === Number(productId))
}
/**
* موجودی کیف یک محصول از inventory_cards.
* fallback: پروژه‌های ساختار قدیم (مثل گلد علی) کیف محصول ندارند و موجودی روی gold کیف اصلی است.
*/
export function getProductInventoryQuantity(
cards: WalletInventoryCard[],
productId?: number | null,
mainWalletGold?: number | null
): number {
const card = findProductInventoryCard(cards, productId)
if (card) {
return Number(card.quantity ?? 0)
}
return Number(mainWalletGold ?? 0)
}
/** برچسب موجودی کیف محصول — برای فرم خرید/فروش */
export function formatProductWalletBalanceText(
product: { id?: number; title?: string | null; unit?: string | null; group_type?: string | null } | null | undefined,
cards: WalletInventoryCard[] = [],
mainWalletGold?: number | null
): string {
const card = findProductInventoryCard(cards, product?.id)
const quantity = card ? Number(card.quantity ?? 0) : Number(mainWalletGold ?? 0)
const unit = card?.unit ?? getProductQuantityUnit(product)
const title = product?.title?.trim() || 'محصول'
return `موجودی کیف ${title}: ${quantity} ${unit}`
}
export function isSingleMetalCatalog(metalIds: number[]): boolean {
return metalIds.length === 1
}
+2 -9
View File
@@ -204,7 +204,7 @@
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import img1 from '@/assets/img/home_ly2.svg'
import { usePrice, usePriceWithoutType } from '@/utils/usePrice'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
@@ -232,7 +232,7 @@ import type { Transaction } from '@/models/transaction'
import type { TableEngineInput, TableOutput } from '@/models/table'
import { useInfiniteScroll } from '@vueuse/core'
import { getTransactionTable } from '@/api/transaction'
import { getLastPrices, getTradeBuyPrice, getTradeSellPrice, lastPrice, setIntervalGetAllPrice, stopPriceInterval } from '@/utils/price'
import { getLastPrices, getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price'
import type { Product } from '@/models/products'
import { useFundUserStore } from '@/store/fundStore'
import {useConfigStore} from "@/store/configStore";
@@ -434,10 +434,6 @@ onMounted(async () => {
await initBuyTable()*/
})
onUnmounted(() => {
stopPriceInterval()
})
const form = ref<Gold>({
goldCash: undefined,
goldValue: undefined,
@@ -630,15 +626,12 @@ const goldPriceValue = computed(() => {
async function initPrice() {
try {
// chartLoading.value = true
await getLastPrices()
await setIntervalGetAllPrice()
loading.value = true
} catch (e) {
console.log(e)
} finally {
loading.value = false
// chartLoading.value = false
}
}
+2 -2
View File
@@ -82,13 +82,13 @@ import { usePriceWithoutType } from '@/utils/usePrice'
import { useConfigStore } from '@/store/configStore'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
import { resolveSummaryMetalWeight } from '@/utils/productAssets'
import { resolveSummaryMetalWeight, fundPageInventoryCards } from '@/utils/productAssets'
const nameProject = useConfigStore().config.name
const { assetsSummary, loadWalletAssets } = useWalletAssets()
const meta = computed(() => assetsSummary.value?.meta)
const inventoryCards = computed(() => assetsSummary.value?.inventory_cards ?? [])
const inventoryCards = computed(() => fundPageInventoryCards(assetsSummary.value?.inventory_cards ?? []))
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
const primaryMetalTotal = computed(() => metalTotals.value[0])
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
+29 -18
View File
@@ -64,7 +64,7 @@
<!-- {{walletStore?.walletInfo?.gold}}-->
<Transition mode="out-in" name="fade">
<div v-if="!isBuy" class="font-bold text-xs">
<div>{{ formatGoldWalletBalanceText(walletStore?.walletInfo?.gold ?? 0, props?.ProductItem?.group_type) }}</div>
<div>{{ productWalletBalanceText }}</div>
<!-- <div v-if="walletStore?.walletInfo?.gold_block !== 0">
{{ `موجودی قابل برداشت طلا: ${walletStore?.walletInfo?.gold_block ?? 0} گرم` }}
</div>-->
@@ -116,10 +116,10 @@
<div v-else>{{ !isBuy ? 'فروش' : 'خرید' }}</div>
</div>
</BasicButton>
<div v-if="!isBuy && form.goldValue > walletStore?.walletInfo?.gold"
<div v-if="!isBuy && form.goldValue > productWalletBalance"
class="text-red-700 text-xs font-bold mt-2">
مقدار گرم طلای وارد شده جهت فروش ({{ form.goldValue }}گرم) بیشتر از مقدار موجودی شما
({{ walletStore?.walletInfo?.gold }}گرم) می باشد.
مقدار {{ weightUnit }} وارد شده جهت فروش ({{ form.goldValue }}{{ weightUnit }}) بیشتر از مقدار موجودی شما
({{ productWalletBalance }}{{ weightUnit }}) می باشد.
</div>
<!-- <div>{{form?.goldValue? true: false}}</div>-->
<div v-if="isBuy ? (form?.goldCash > walletStore?.walletInfo?.cash) : false"
@@ -202,7 +202,7 @@
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import img1 from '@/assets/img/home_ly2.svg'
import { usePrice, usePriceWithoutType } from '@/utils/usePrice'
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
@@ -231,12 +231,14 @@ import type { TableEngineInput, TableOutput } from '@/models/table'
import { useInfiniteScroll } from '@vueuse/core'
import { getTransactionTable } from '@/api/transaction'
import { getProductBuyPrice, getProductSellPrice } from '@/utils/productPrice'
import { getLastPrices, getTradeBuyPrice, getTradeSellPrice, lastPrice, setIntervalGetAllPrice, stopPriceInterval } from '@/utils/price'
import { getLastPrices, getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price'
import type { Product } from '@/models/products'
import { useFundUserStore } from '@/store/fundStore'
import {useConfigStore} from "@/store/configStore";
import { calcFeeInGrams, loadServiceFeeFromSettings } from '@/utils/serviceFee'
import { formatCashWalletBalanceText, formatGoldWalletBalanceText, getWeightUnit } from '@/utils/productDealMethod'
import { formatCashWalletBalanceText, getWeightUnit } from '@/utils/productDealMethod'
import { formatProductWalletBalanceText, getProductInventoryQuantity } from '@/utils/productAssets'
import { useWalletAssets } from '@/composables/useWalletAssets'
import { isMeltedTradeGroup } from '@/utils/productCategories'
import { useSettingsStore } from '@/store/settingsStore'
import { storeToRefs } from 'pinia'
@@ -253,6 +255,7 @@ const settingsStore = useSettingsStore()
const { meltedGoldLabel } = storeToRefs(settingsStore)
const weightUnit = computed(() => getWeightUnit())
const fundStore = useFundUserStore()
const { assetsSummary, loadWalletAssets } = useWalletAssets()
const confirmAction = ref<boolean>(false)
const noCompleteVisible = ref<boolean>(false)
const buyItems = ref<Transaction[]>([])
@@ -275,6 +278,22 @@ const tradeProductLabel = computed(() => {
})
const amountFieldLabel = computed(() => `مقدار ${tradeProductLabel.value}`)
const productWalletBalance = computed(() =>
getProductInventoryQuantity(
assetsSummary.value?.inventory_cards ?? [],
props.ProductItem?.id,
walletStore?.walletInfo?.gold
)
)
const productWalletBalanceText = computed(() =>
formatProductWalletBalanceText(
props.ProductItem,
assetsSummary.value?.inventory_cards ?? [],
walletStore?.walletInfo?.gold
)
)
const buyPagination = ref<TableEngineInput>({
filters: [{
field: 'type',
@@ -441,10 +460,6 @@ onMounted(async () => {
await initBuyTable()*/
})
onUnmounted(() => {
stopPriceInterval()
})
const form = ref<Gold>({
goldCash: undefined,
goldValue: undefined,
@@ -471,6 +486,7 @@ watch(form.value, () => {
})
onMounted(() => {
void loadWalletAssets()
console.log(userStore.userInfo?.is_legal === 2)
if (userStore.userInfo?.is_legal === 0) {
noCompleteVisible.value = true
@@ -495,10 +511,7 @@ function percentChange(val: number) {
}
}
const unitGoldCalculator = computed(() => {
// console.log(walletStore?.walletInfo?.gold / 100)
return (walletStore?.walletInfo?.gold ?? 0) / 100
})
const unitGoldCalculator = computed(() => productWalletBalance.value / 100)
const unitCashCalculator = computed(() => {
return (walletStore?.walletInfo?.cash ?? 0) / 100
@@ -607,15 +620,12 @@ const goldPriceValue = computed(() => unitPrice.value)
async function initPrice() {
try {
// chartLoading.value = true
await getLastPrices()
await setIntervalGetAllPrice()
loading.value = true
} catch (e) {
console.log(e)
} finally {
loading.value = false
// chartLoading.value = false
}
}
@@ -639,6 +649,7 @@ async function ok() {
})
confirmAction.value = false
await walletStore.getMyWallet()
await loadWalletAssets(true)
await router.push({ name: 'transactions' })
form.value = {
goldValue: undefined,
@@ -12,7 +12,7 @@
icon="vuesax-linear:info-circle"
size="18"
color="tertiary"
@click="$emit('openGoldModal')"
@click="$emit('openGoldModal', primaryMetalTotal)"
/>
</div>
</template>
@@ -29,13 +29,13 @@
icon="vuesax-linear:info-circle"
size="18"
color="tertiary"
@click="$emit('openGoldModal')"
@click="$emit('openGoldModal', metal)"
/>
</div>
</template>
<div class="flex mt-2 justify-center text-tertiary w-full z-20">
دارایی ریالی:
<div class="text-l mr-2 font-bold">{{ usePriceWithoutType(cashWallet) }} ریال</div>
<div class="text-l mr-2 font-bold">{{ usePriceWithoutType(totalRialValue) }} ریال</div>
<BasicIcon @click="$emit('openRialModal')" icon="vuesax-linear:info-circle" size="18" color="tertiary" />
</div>
</div>
@@ -52,14 +52,14 @@ import { resolveSummaryMetalWeight } from '@/utils/productAssets'
const { assetsSummary, loadWalletAssets } = useWalletAssets()
defineEmits<{
openGoldModal: []
openGoldModal: [metal: WalletMetalTotal]
openRialModal: []
}>()
const meta = computed(() => assetsSummary.value?.meta)
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
const primaryMetalTotal = computed(() => metalTotals.value[0])
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
const totalRialValue = computed(() => assetsSummary.value?.total_rial_value ?? 0)
const inventoryCards = computed(() => assetsSummary.value?.inventory_cards ?? [])
const countBasedInventory = computed(() =>
(assetsSummary.value?.count_products ?? []).reduce((sum, item) => sum + Number(item.quantity ?? 0), 0)
@@ -31,7 +31,14 @@
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="معادل ریالی مجموع دارایی ها"
title="معادل ریالی محصولات"
is-line
:value="usePrice(assetsRialValue)"
/>
<a-divider class="!my-1" />
<BasicInfoItem
class="flex justify-between"
title="مجموع دارایی ریالی"
is-line
:value="usePrice(totalRialValue)"
/>
@@ -49,7 +56,7 @@ import BasicInfoItem from '@/components/BasicPacks/BasicInfoItem.vue'
import { usePrice } from '@/utils/usePrice'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
import { formatInventoryCardValue } from '@/utils/productAssets'
import { formatInventoryCardValue, assetSheetInventoryCards } from '@/utils/productAssets'
const props = defineProps<{
show: boolean
@@ -71,6 +78,7 @@ const visible = computed({
const inventoryCards = computed(() => assetsSummary.value?.inventory_cards ?? [])
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
const assetsRialValue = computed(() => assetsSummary.value?.assets_rial_value ?? 0)
const totalRialValue = computed(() => assetsSummary.value?.total_rial_value ?? 0)
onMounted(() => {
@@ -87,7 +95,7 @@ watch(
)
function cardsByMetal(metalId: number) {
return inventoryCards.value.filter((card) => Number(card.metal_id) === metalId)
return assetSheetInventoryCards(inventoryCards.value, metalId)
}
function formatMetalTotal(metal: WalletMetalTotal) {
+15 -11
View File
@@ -83,10 +83,12 @@ import {loading, removeToken} from '@/utils'
import {useUserStore} from '@/store/userStore'
import {useWalletStore} from '@/store/walletStore'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
import { formatMetalAssetsInfoText, formatRialAssetsInfoText } from '@/utils/productAssets'
import {useConfigStore} from '@/store/configStore'
import {useFundUserStore} from '@/store/fundStore'
import {usePrice, usePriceWithoutType} from '../../../utils/usePrice'
import {getLastPrices, lastPrice, price, setIntervalGetAllPrice, stopPriceInterval} from '@/utils/price'
import {usePriceWithoutType} from '../../../utils/usePrice'
import {getLastPrices, lastPrice, price, startLastPricePolling, stopLastPricePolling} from '@/utils/price'
import {getConstByKey} from '@/api/const'
import {message, Modal} from 'ant-design-vue'
@@ -119,6 +121,7 @@ const userStore = useUserStore()
const walletStore = useWalletStore()
const configStore = useConfigStore()
const fundStore = useFundUserStore()
const { assetsSummary, loadWalletAssets } = useWalletAssets()
// Config
const isGaroosi = computed(() => configStore.config.name === 'garoosi')
@@ -211,11 +214,9 @@ async function logout() {
window.location.reload()
}
function openGoldModal() {
const goldAmount = (walletStore.walletInfo?.gold ?? 0).toFixed(3)
const walletsAmount = (walletStore.walletInfo?.count_gold_wallets ?? 0).toFixed(3)
function openGoldModal(metal: WalletMetalTotal) {
Modal.confirm({
title: `مجموع کل وزن طلای آبشده (${goldAmount}) + ارزش دارایی ها (${walletsAmount}) گرم`,
title: formatMetalAssetsInfoText(metal),
okText: 'متوجه شدم',
centered: true,
cancelButtonProps: {style: {display: 'none'}}
@@ -223,10 +224,12 @@ function openGoldModal() {
}
function openRialModal() {
const cashWallet = usePrice(walletStore?.walletInfo?.count_cash_wallet ?? 0)
const cashWallets = usePrice(walletStore?.walletInfo?.count_cash_wallets ?? 0)
const summary = assetsSummary.value
Modal.confirm({
title: `مجموع کیف پول ریالی (${cashWallet}) + معادل ریالی محصولات (${cashWallets}) ریال`,
title: formatRialAssetsInfoText(
summary?.cash_wallet ?? 0,
summary?.assets_rial_value ?? 0
),
okText: 'متوجه شدم',
centered: true,
cancelButtonProps: {style: {display: 'none'}}
@@ -261,9 +264,10 @@ onMounted(async () => {
loading.value = true
await Promise.all([
loadFunds(),
loadWalletAssets(),
getLastPrices(),
fetchPrices(),
setIntervalGetAllPrice(),
startLastPricePolling(),
loadBanners()
])
@@ -274,7 +278,7 @@ onMounted(async () => {
onUnmounted(() => {
clearInterval(updateInterval)
stopPriceInterval()
stopLastPricePolling()
})
} catch (error) {
console.error('Initialization error:', error)
@@ -67,7 +67,7 @@
size="large" type="text" inputmode="numeric" @onchange="handleGoldValueChange" />
</a-form-item>
<a-form-item v-else name="goldValue"
:rules="[justNumber3(props?.ProductItem?.sellPrice, productNum ,false)]">
:rules="[justNumber3(props?.ProductItem?.sellPrice, productNum.value ,false)]">
<BasicInput v-model:value="form.goldValue" addon-before="تعداد" addon-bg-color="#000000FF"
addon-text-color="white"
place-holder="تعداد"
@@ -104,8 +104,7 @@
{{ cashWalletBalanceText }}
</div>
<div class="font-bold text-xs" v-else>
<div>{{ `موجودی محصول: ${getInventoryById(props?.ProductItem?.id)} ${getProductQuantityUnit(props?.ProductItem)}` }}</div>
<div v-if="isMetalReceiveDeal" class="mt-1">{{ sellMetalWalletBalanceText }}</div>
<div>{{ productWalletBalanceText }}</div>
</div>
</Transition>
<Transition mode="out-in" name="fade">
@@ -296,6 +295,8 @@ import {
productMaxOrderCash,
productMinOrderCash
} from '@/utils/productOrderLimit'
import { useWalletAssets } from '@/composables/useWalletAssets'
import { formatProductWalletBalanceText, getProductInventoryQuantity } from '@/utils/productAssets'
const typeDeal = computed(() => getProductDealMethodOptions(props?.ProductItem?.group_type, isBuy.value))
@@ -329,16 +330,28 @@ const goldWalletBalanceText = computed(() =>
formatGoldWalletBalanceText(walletStore?.walletInfo?.gold ?? 0, productGroupType.value)
)
const productWalletBalance = computed(() =>
getProductInventoryQuantity(
assetsSummary.value?.inventory_cards ?? [],
props?.ProductItem?.id,
walletStore?.walletInfo?.gold
)
)
const productWalletBalanceText = computed(() =>
formatProductWalletBalanceText(
props?.ProductItem,
assetsSummary.value?.inventory_cards ?? [],
walletStore?.walletInfo?.gold
)
)
const buyMetalWalletBalanceText = computed(() =>
form.value.method === 'katod'
? formatMainMetalWalletBalanceText(walletStore?.walletInfo?.gold ?? 0)
: goldWalletBalanceText.value
)
const sellMetalWalletBalanceText = computed(() =>
formatMainMetalWalletBalanceText(walletStore?.walletInfo?.gold ?? 0)
)
const cashWalletBalanceText = computed(() =>
formatCashWalletBalanceText(
usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0),
@@ -347,6 +360,7 @@ const cashWalletBalanceText = computed(() =>
)
const infoVisible = ref(false)
const walletStore = useWalletStore()
const { assetsSummary, loadWalletAssets } = useWalletAssets()
const userStore = useUserStore()
const confirmAction = ref<boolean>(false)
const noCompleteVisible = ref<boolean>(false)
@@ -525,6 +539,7 @@ async function initSellTable() {
// }
onMounted(async () => {
void loadWalletAssets()
switch (router.currentRoute.value.query.state) {
case 'sell':
isBuy.value = false
@@ -581,15 +596,7 @@ onMounted(() => {
noCompleteVisible.value = true
}
})
const productNum = ref<number>(0)
const getInventoryById = (id: number) => {
userStore?.productWallet?.forEach((val) => {
if (val.product_id == id)
productNum.value = val.gold
})
return productNum.value ?? 0
}
const productNum = computed(() => productWalletBalance.value)
/*function percentChange(val: number) {
if (val !== 0)
@@ -802,6 +809,7 @@ async function ok() {
emit('ordered')
await userStore.getMyInfo()
await walletStore.getMyWallet()
await loadWalletAssets(true)
await fundStore.getMyFund()
message.success('سفارش شما با موفقیت انجام شد')
await router.push({ name: 'transactions' })
+56 -27
View File
@@ -89,13 +89,7 @@ import { onMounted, onUnmounted, ref, watch } from 'vue'
import router from '@/router'
import ProductItem from '@/views/base/products/components/ProductItem.vue'
import { getProducts } from '@/api/products'
import {
getLastPrices,
lastPrice,
stopPriceInterval
} from '@/utils/price'
import { loading } from '@/utils'
import { Price } from '@/models/home'
import type { Product } from '@/models/products'
import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
import indexGold from '@/views/base/gold/index.vue'
@@ -162,9 +156,57 @@ function changeTab() {
}
const firstItems = ref<Product[]>()
const price = ref<Price>()
const items = ref<Product[]>()
const typeItems = ref([])
let productListInterval: ReturnType<typeof setInterval> | undefined
/**
* رفرش بی‌صدای لیست محصولات (هر ۱۰ ثانیه تا وقتی در این صفحه‌ایم).
* آپدیت درجا انجام می‌شود تا لیست re-render کامل نشود و نپرد؛
* فقط اگر محصولی اضافه/حذف شده باشد ساختار لیست عوض می‌شود.
*/
async function refreshProducts() {
try {
const fresh = await getProducts()
if (!fresh?.length) {
return
}
fresh.forEach((val) => {
if (!typeItems.value.includes(val.group_type)) {
typeItems.value.push(val.group_type)
}
})
const freshById = new Map(fresh.map((p) => [p.id, p]))
const current = firstItems.value
if (!current?.length) {
firstItems.value = fresh
changeTab()
return
}
// آپدیت فیلدهای محصولات موجود روی همان آبجکت‌ها (items همین رفرنس‌ها را دارد)
current.forEach((item) => {
const updated = freshById.get(item.id)
if (updated) {
Object.assign(item, updated)
}
})
const currentIds = new Set(current.map((p) => p.id))
const hasAdded = fresh.some((p) => !currentIds.has(p.id))
const hasRemoved = current.some((p) => !freshById.has(p.id))
if (hasAdded || hasRemoved) {
firstItems.value = fresh
changeTab()
}
} catch (e) {
console.log(e)
}
}
onMounted(async () => {
try {
loading.value = true
@@ -182,9 +224,9 @@ onMounted(async () => {
// typeItems.value[index] = val.group_type
})
firstItems.value = items.value
await Promise.all([initPrice(), loadServiceFeeFromSettings()])
// await setIntervalGetLastPrice()
// console.log('run product')
await loadServiceFeeFromSettings()
// فقط لیست محصولات هر ۱۰ ثانیه — last فقط در صفحه اصلی poll می‌شود
productListInterval = setInterval(refreshProducts, 10000)
} catch (e) {
console.log(e)
@@ -205,10 +247,10 @@ onMounted(async () => {
}
})
onUnmounted(() => {
stopPriceInterval()
// console.log('stop product')
// console.log('okgold')
if (productListInterval) {
clearInterval(productListInterval)
productListInterval = undefined
}
})
// watch(lastPrice, async () => {
// // console.log(items);
@@ -226,19 +268,6 @@ onUnmounted(() => {
//
// })
// })
async function initPrice() {
try {
// chartLoading.value = true
await getLastPrices()
loading.value = true
} catch (e) {
console.log(e)
} finally {
loading.value = false
// chartLoading.value = false
}
}
</script>
<style lang="less">