Merge origin/modular into feature/responsive-layout-refactor.
Keep the responsive layout refactor while bringing in modular updates for support UI, pricing, categories, and config loading. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -68,14 +68,14 @@
|
||||
</div>-->
|
||||
</div>
|
||||
<div v-else class="font-bold text-xs">
|
||||
{{ formatCashWalletBalanceText(usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0), props?.ProductItem?.group_type) }}
|
||||
{{ formatCashWalletBalanceText(usePriceWithoutType(cashWalletBalance), props?.ProductItem?.group_type) }}
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition mode="out-in" name="fade">
|
||||
<a-form-item v-if="walletStore?.walletInfo" class="!mt-3 ">
|
||||
<!-- {{ isBuy }}-->
|
||||
<a-slider v-model:value="form.percentWallet"
|
||||
:disabled="isBuy? walletStore?.walletInfo?.cash <= 0: false"
|
||||
:disabled="isBuy? cashWalletBalance <= 0: false"
|
||||
:max="100"
|
||||
:min="0"
|
||||
:step="10"
|
||||
@@ -238,10 +238,14 @@ import { useFundUserStore } from '@/store/fundStore'
|
||||
import {useConfigStore} from "@/store/configStore";
|
||||
import { calcFeeInGrams } from '@/utils/serviceFee'
|
||||
import { formatCashWalletBalanceText, formatGoldWalletBalanceText } from '@/utils/productDealMethod'
|
||||
import { getCashWalletBalance } from '@/utils/productAssets'
|
||||
|
||||
const infoVisible = ref(false)
|
||||
const walletStore = useWalletStore()
|
||||
const userStore = useUserStore()
|
||||
const cashWalletBalance = computed(() =>
|
||||
getCashWalletBalance(walletStore.walletInfo, userStore.userInfo?.wallets)
|
||||
)
|
||||
const fundStore = useFundUserStore()
|
||||
const confirmAction = ref<boolean>(false)
|
||||
const noCompleteVisible = ref<boolean>(false)
|
||||
@@ -490,7 +494,7 @@ const unitGoldCalculator = computed(() => {
|
||||
})
|
||||
|
||||
const unitCashCalculator = computed(() => {
|
||||
return (walletStore?.walletInfo?.cash ?? 0) / 100
|
||||
return cashWalletBalance.value / 100
|
||||
})
|
||||
|
||||
const limitedPrice = computed(() => {
|
||||
|
||||
@@ -81,14 +81,14 @@
|
||||
</div>-->
|
||||
</div>
|
||||
<div v-else class="font-bold text-xs">
|
||||
{{ formatCashWalletBalanceText(usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0), props?.ProductItem?.group_type) }}
|
||||
{{ formatCashWalletBalanceText(usePriceWithoutType(cashWalletBalance), props?.ProductItem?.group_type) }}
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition mode="out-in" name="fade">
|
||||
<a-form-item v-if="walletStore?.walletInfo" class="!mt-3 ">
|
||||
<!-- {{ isBuy }}-->
|
||||
<a-slider v-model:value="form.percentWallet"
|
||||
:disabled="isBuy? walletStore?.walletInfo?.cash <= 0: false"
|
||||
:disabled="isBuy? cashWalletBalance <= 0: false"
|
||||
:max="100"
|
||||
:min="0"
|
||||
:step="10"
|
||||
@@ -133,7 +133,7 @@
|
||||
({{ productWalletBalance }}{{ weightUnit }}) می باشد.
|
||||
</div>
|
||||
<!-- <div>{{form?.goldValue? true: false}}</div>-->
|
||||
<div v-if="isBuy ? (form?.goldCash > walletStore?.walletInfo?.cash) : false"
|
||||
<div v-if="isBuy ? (form?.goldCash > cashWalletBalance) : false"
|
||||
class="text-red-700 text-xs font-bold mt-2">
|
||||
موجودی کیف پول ناکافی می باشد.
|
||||
</div>
|
||||
@@ -297,7 +297,7 @@ import { useFundUserStore } from '@/store/fundStore'
|
||||
import {useConfigStore} from "@/store/configStore";
|
||||
import { calcFeeInGrams, loadServiceFeeFromSettings } from '@/utils/serviceFee'
|
||||
import { formatCashWalletBalanceText, getWeightUnit } from '@/utils/productDealMethod'
|
||||
import { formatProductWalletBalanceText, getProductInventoryQuantity } from '@/utils/productAssets'
|
||||
import { formatProductWalletBalanceText, getCashWalletBalance, getProductInventoryQuantity } from '@/utils/productAssets'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import { isMeltedTradeGroup } from '@/utils/productCategories'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
@@ -316,6 +316,9 @@ const { meltedGoldLabel } = storeToRefs(settingsStore)
|
||||
const weightUnit = computed(() => getWeightUnit())
|
||||
const fundStore = useFundUserStore()
|
||||
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
||||
const cashWalletBalance = computed(() =>
|
||||
getCashWalletBalance(walletStore.walletInfo, userStore.userInfo?.wallets)
|
||||
)
|
||||
const confirmAction = ref<boolean>(false)
|
||||
const noCompleteVisible = ref<boolean>(false)
|
||||
const buyItems = ref<Transaction[]>([])
|
||||
@@ -576,7 +579,7 @@ function percentChange(val: number) {
|
||||
const unitGoldCalculator = computed(() => productWalletBalance.value / 100)
|
||||
|
||||
const unitCashCalculator = computed(() => {
|
||||
return (walletStore?.walletInfo?.cash ?? 0) / 100
|
||||
return cashWalletBalance.value / 100
|
||||
})
|
||||
|
||||
const limitedPrice = computed(() => {
|
||||
|
||||
@@ -49,4 +49,4 @@ const props = withDefaults(
|
||||
|
||||
const highPrice = computed(() => props.price?.up?.buy ?? getTradeBuyPrice(props.price))
|
||||
const lowPrice = computed(() => props.price?.up?.sell ?? getTradeSellPrice(props.price))
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -296,7 +296,7 @@ import {
|
||||
productMinOrderCash
|
||||
} from '@/utils/productOrderLimit'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import { formatProductWalletBalanceText, getProductInventoryQuantity } from '@/utils/productAssets'
|
||||
import { formatProductWalletBalanceText, getCashWalletBalance, getProductInventoryQuantity } from '@/utils/productAssets'
|
||||
|
||||
const typeDeal = computed(() => getProductDealMethodOptions(props?.ProductItem?.group_type, isBuy.value))
|
||||
|
||||
@@ -352,16 +352,20 @@ const buyMetalWalletBalanceText = computed(() =>
|
||||
: goldWalletBalanceText.value
|
||||
)
|
||||
|
||||
const cashWalletBalanceText = computed(() =>
|
||||
formatCashWalletBalanceText(
|
||||
usePriceWithoutType(walletStore?.walletInfo?.cash ?? 0),
|
||||
productGroupType.value
|
||||
)
|
||||
)
|
||||
const infoVisible = ref(false)
|
||||
const walletStore = useWalletStore()
|
||||
const { assetsSummary, loadWalletAssets } = useWalletAssets()
|
||||
const userStore = useUserStore()
|
||||
const cashWalletBalance = computed(() =>
|
||||
getCashWalletBalance(walletStore.walletInfo, userStore.userInfo?.wallets)
|
||||
)
|
||||
|
||||
const cashWalletBalanceText = computed(() =>
|
||||
formatCashWalletBalanceText(
|
||||
usePriceWithoutType(cashWalletBalance.value),
|
||||
productGroupType.value
|
||||
)
|
||||
)
|
||||
const confirmAction = ref<boolean>(false)
|
||||
const noCompleteVisible = ref<boolean>(false)
|
||||
const buyItems = ref<Transaction[]>([])
|
||||
@@ -622,7 +626,7 @@ const unitGoldCalculator = computed(() => {
|
||||
})
|
||||
|
||||
const unitCashCalculator = computed(() => {
|
||||
return (walletStore?.walletInfo?.cash ?? 0) / 100
|
||||
return cashWalletBalance.value / 100
|
||||
})
|
||||
|
||||
const limitedPrice = computed(() => {
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
<!-- <div v-if="props.ProductItem.group_type!='آبشده'" class="text-secondary font-500">{{ props.ProductItem.amount }}گرم</div>-->
|
||||
<!-- <div v-else class="text-secondary font-500">حداقل خرید یک گرم</div>-->
|
||||
<!-- <div>{{usePrice((props.ProductItem.price ?? 0) + (props.ProductItem.cash_fee_buy ?? 0))}}</div>-->
|
||||
<div v-if="isMeltedTradeGroup(props.ProductItem.group_type)">{{usePrice(goldPriceValue)}}</div>
|
||||
<div v-else>{{usePrice(price)}}</div>
|
||||
<div>{{ usePrice(getProductBuyPrice(props.ProductItem)) }}</div>
|
||||
<!-- <div v-if="props.ProductItem.group_type!='آبشده'" class="text-xs text-gray-400">شامل 33 هزار تومان اجرت</div>-->
|
||||
<!-- <div v-else class="text-xs text-gray-400">محاسبه بر اساس قیمت روز</div>-->
|
||||
</div>
|
||||
@@ -33,7 +32,6 @@ import {usePrice} from '@/utils/usePrice';
|
||||
import {getFileUrl} from '@/utils/file';
|
||||
import {computed, ref} from "vue";
|
||||
import { getProductBuyPrice } from '@/utils/productPrice'
|
||||
import { isMeltedTradeGroup } from '@/utils/productCategories'
|
||||
|
||||
interface Prop {
|
||||
ProductItem: Product
|
||||
@@ -68,29 +66,6 @@ const displayImage = computed(() => {
|
||||
if (fileUrl) return fileUrl
|
||||
return defaultImages[props.ProductItem.group_type] ?? defaultImg
|
||||
})
|
||||
// const typeOfProduct=(val:string)=>{
|
||||
// if (val.includes('گوی'))
|
||||
// return 'گوی'
|
||||
// if (val.includes('شمش'))
|
||||
// return 'شمش'
|
||||
// if (val.includes('مکعب'))
|
||||
// return 'مکعب'
|
||||
// if (val.includes('24 عیار'))
|
||||
// return '24 عیار'
|
||||
//
|
||||
// return 'آب شده'
|
||||
// }
|
||||
|
||||
const price = computed(()=>{
|
||||
if(props.ProductItem.direct_price === 0){
|
||||
return ((props.ProductItem.price ?? 0) + (props.ProductItem.cash_fee_buy ?? 0)) * props.ProductItem.amount
|
||||
}
|
||||
else {
|
||||
return ((props.ProductItem.price ?? 0) + (props.ProductItem.cash_fee_buy ?? 0))
|
||||
}
|
||||
})
|
||||
|
||||
const goldPriceValue = computed(() => getProductBuyPrice(props.ProductItem))
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,11 +3,14 @@ import { getProductsCatalog } from '@/composables/useProductsCatalog'
|
||||
import { loading } from '@/utils'
|
||||
import type { Product } from '@/models/products'
|
||||
import { loadServiceFeeFromSettings } from '@/utils/serviceFee'
|
||||
import { loadProductCategoryTabNames } from '@/utils/categoryTabs'
|
||||
import { getLastPrices, startLastPricePolling, stopLastPricePolling } from '@/utils/price'
|
||||
|
||||
/** Shared products page datasets — mobile/desktop views read this module state only. */
|
||||
let initPromise: Promise<void> | null = null
|
||||
let productListInterval: ReturnType<typeof setInterval> | undefined
|
||||
let providerMountCount = 0
|
||||
let pricePollingMountCount = 0
|
||||
|
||||
const initialized = ref(false)
|
||||
|
||||
@@ -40,6 +43,17 @@ function syncTypeItems(products: Product[]) {
|
||||
})
|
||||
}
|
||||
|
||||
async function loadCategoryTabs() {
|
||||
try {
|
||||
const tabs = await loadProductCategoryTabNames()
|
||||
if (tabs.length) {
|
||||
productsTypeItems.value = tabs
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Product category tabs error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
function applyProductsList(products: Product[]) {
|
||||
if (products.length) {
|
||||
productsCloseTime.value = products[0].auto_close_at
|
||||
@@ -100,10 +114,19 @@ function stopProductListPolling() {
|
||||
|
||||
export function onProductsPageProviderMounted() {
|
||||
providerMountCount += 1
|
||||
pricePollingMountCount += 1
|
||||
if (pricePollingMountCount === 1) {
|
||||
void getLastPrices()
|
||||
startLastPricePolling()
|
||||
}
|
||||
}
|
||||
|
||||
export function onProductsPageProviderUnmounted() {
|
||||
providerMountCount = Math.max(0, providerMountCount - 1)
|
||||
pricePollingMountCount = Math.max(0, pricePollingMountCount - 1)
|
||||
if (pricePollingMountCount === 0) {
|
||||
stopLastPricePolling()
|
||||
}
|
||||
if (providerMountCount === 0) {
|
||||
stopProductListPolling()
|
||||
}
|
||||
@@ -124,7 +147,10 @@ export async function initProductsPageData(force = false) {
|
||||
loading.value = true
|
||||
const products = await getProductsCatalog(force)
|
||||
applyProductsList(products ?? [])
|
||||
await loadServiceFeeFromSettings()
|
||||
await Promise.all([
|
||||
loadServiceFeeFromSettings(),
|
||||
loadCategoryTabs(),
|
||||
])
|
||||
initialized.value = true
|
||||
startProductListPolling()
|
||||
} catch (error) {
|
||||
@@ -142,6 +168,8 @@ export function resetProductsPageData() {
|
||||
initialized.value = false
|
||||
initPromise = null
|
||||
providerMountCount = 0
|
||||
pricePollingMountCount = 0
|
||||
stopLastPricePolling()
|
||||
stopProductListPolling()
|
||||
productsActiveKey.value = 'همه'
|
||||
productsTypeItems.value = []
|
||||
|
||||
Reference in New Issue
Block a user