some trigger handled
This commit is contained in:
@@ -17,6 +17,7 @@ export function useWalletAssets() {
|
||||
return assetsPromise
|
||||
}
|
||||
|
||||
// سرور مرجع داراییهاست (main_wallet_products هم سمت سرور هندل میشود)؛ کلاینت فقط نمایش میدهد
|
||||
assetsPromise = Promise.all([getWalletAssets(), getProducts()])
|
||||
.then(([data, catalog]) => {
|
||||
assetsSummary.value = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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' })
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user