fix bug of product-modal

This commit is contained in:
2026-10-17 13:33:33 +03:30
parent cf8a46ec9c
commit 9487490981
12 changed files with 67 additions and 19 deletions
@@ -28,8 +28,10 @@
- 2026-09-09 | ماشین حساب | `useUserPage.ts` + `GoldDayCalculatorModal.vue` | «قیمت روز طلا» → «ماشین حساب»؛ برچسب فلز/واحد از settingsStore (metalTypeLabel + tradeWeightUnit) نه هاردکد طلا/گرم - 2026-09-09 | ماشین حساب | `useUserPage.ts` + `GoldDayCalculatorModal.vue` | «قیمت روز طلا» → «ماشین حساب»؛ برچسب فلز/واحد از settingsStore (metalTypeLabel + tradeWeightUnit) نه هاردکد طلا/گرم
- 2026-10-05 | ????? ????? ??????? | desktop/components/DesktopAuthShell.vue + desktop/styles/desktop-auth.less | ????? stretch? ??? ???????? bleed? tagline ? form-links ?? margin-top:auto ???????? support ??? ???? ?? __top - 2026-10-05 | ????? ????? ??????? | desktop/components/DesktopAuthShell.vue + desktop/styles/desktop-auth.less | ????? stretch? ??? ???????? bleed? tagline ? form-links ?? margin-top:auto ???????? support ??? ???? ?? __top
- 2026-10-05 | نمای کلی پروژه | `boursecu/BOURSECU.md` | چهار ریپو: user:3100، admin:3600، server:8000، landing:3200؛ فلز مس از settings - 2026-10-05 | نمای کلی پروژه | `boursecu/BOURSECU.md` | چهار ریپو: user:3100، admin:3600، server:8000، landing:3200؛ فلز مس از settings
- 2026-10-17 | کلیک کارت محصول دسکتاپ | `products/index.vue` + `DesktopProductCard.vue` + `useProductsPage.ts` | کاتد مس: `isMeltedTradeGroup` → indexGold در مدال؛ رویداد `select`؛ بسته بودن معامله با `shouldBlockStoreTrading`
- 2026-10-05 | ???? ????? ????? | DesktopAuthShell.vue + desktop-auth.less | status ???? form-column__foot ??? ???????? body/top ?? margin-top:auto ???????? tagline ??????? foot - 2026-10-05 | ???? ????? ????? | DesktopAuthShell.vue + desktop-auth.less | status ???? form-column__foot ??? ???????? body/top ?? margin-top:auto ???????? tagline ??????? foot
- 2026-10-05 | ??? ????? ?????? | home/components/AppHeader.vue + guestHome.ts | ???? ????? ???? ?????login? ????????? ????? ?????/??/???? ?? guest ???? - 2026-10-05 | ??? ????? ?????? | home/components/AppHeader.vue + guestHome.ts | ???? ????? ???? ?????login? ????????? ????? ?????/??/???? ?? guest ????
- 2026-10-05 | FAB ???????? ????? ?????? | DesktopAuthShell.vue + useDraggableFloatingButton | ??????: ????? ???? ????????? ??????: ???? inline ??? ???? - 2026-10-05 | FAB ???????? ????? ?????? | DesktopAuthShell.vue + useDraggableFloatingButton | ??????: ????? ???? ????????? ??????: ???? inline ??? ????
- 2026-10-05 | ?????? ?? ??? ????? | boutUs/components/AboutUsContentPanel.vue | ??? ?????? ???? ??? ???? ?? ????? ???? ?? ??? ?? - 2026-10-05 | ?????? ?? ??? ????? | boutUs/components/AboutUsContentPanel.vue | ??? ?????? ???? ??? ???? ?? ????? ???? ?? ??? ??
- 2026-10-06 | بیلد آموزش ENOENT 1.png | EducateContentPanel.vue + assets/img/1.png,2.png,4.png + banner1/2 | فایل‌ها در گیت بودند و از دیسک پاک شده بودند؛ git restore - 2026-10-06 | بیلد آموزش ENOENT 1.png | EducateContentPanel.vue + assets/img/1.png,2.png,4.png + banner1/2 | فایل‌ها در گیت بودند و از دیسک پاک شده بودند؛ git restore
- 2026-10-17 | باز/بسته خرید فروش محصول | `utils/productTradeOpen.ts` + `gold/index.vue` | `open_buy`/`open_sell`؛ بدون ProductItem هر دو باز
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

-1
View File
@@ -14,7 +14,6 @@ export const useConfigStore = defineStore('config', () => {
async function getConfigData() { async function getConfigData() {
config.value = window.__APP_CONFIG__?.user config.value = window.__APP_CONFIG__?.user
console.log(config.value)
} }
return { return {
+21
View File
@@ -0,0 +1,21 @@
import type { Product } from '@/models/products'
type TradeOpenProduct = Pick<Product, 'open_buy' | 'open_sell'> | null | undefined
function asBool(value: boolean | number | null | undefined) {
return value === true || Number(value) === 1
}
export function isProductBuyOpen(product: TradeOpenProduct) {
if (!product) return true
return asBool(product.open_buy)
}
export function isProductSellOpen(product: TradeOpenProduct) {
if (!product) return true
return asBool(product.open_sell)
}
export function isProductTradeOpen(product: TradeOpenProduct, isBuy: boolean) {
return isBuy ? isProductBuyOpen(product) : isProductSellOpen(product)
}
+3
View File
@@ -308,6 +308,7 @@ import {
productMaxOrderCash, productMaxOrderCash,
productMinOrderCash productMinOrderCash
} from '@/utils/productOrderLimit' } from '@/utils/productOrderLimit'
import { isProductBuyOpen, isProductSellOpen } from '@/utils/productTradeOpen'
const infoVisible = ref(false) const infoVisible = ref(false)
const walletStore = useWalletStore() const walletStore = useWalletStore()
@@ -689,6 +690,8 @@ function useStyle() {
function setIsBuy(val: boolean) { function setIsBuy(val: boolean) {
if (val && !isProductBuyOpen(props?.ProductItem)) return
if (!val && !isProductSellOpen(props?.ProductItem)) return
isBuy.value = val isBuy.value = val
form.value.goldValue = undefined form.value.goldValue = undefined
form.value.goldCash = undefined form.value.goldCash = undefined
@@ -1,5 +1,6 @@
import { import {
inject, inject,
nextTick,
onMounted, onMounted,
onUnmounted, onUnmounted,
provide, provide,
@@ -8,12 +9,13 @@ import {
computed, computed,
type InjectionKey, type InjectionKey,
} from 'vue' } from 'vue'
import { message } from 'ant-design-vue'
import router from '@/router' import router from '@/router'
import { loading } from '@/utils' import { loading } from '@/utils'
import type { Product } from '@/models/products' import type { Product } from '@/models/products'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { isProductPriceInactive } from '@/utils/productPrice' import { isProductPriceInactive } from '@/utils/productPrice'
import { getStoreClosedHint, shouldBlockStoreTrading } from '@/utils/storeHours' import { getStoreClosedHint, resolveStoreClosedNotice, shouldBlockStoreTrading } from '@/utils/storeHours'
import { useUserStore } from '@/store/userStore' import { useUserStore } from '@/store/userStore'
import { lastPrice } from '@/utils/price' import { lastPrice } from '@/utils/price'
import { import {
@@ -61,10 +63,21 @@ export function useProductsPageProvider() {
getStoreClosedHint(userStore.getValueByKey('closed_message')), getStoreClosedHint(userStore.getValueByKey('closed_message')),
) )
function openStoreClosedModal() {
showFilter.value = false
if (isAfterCloseTime.value) {
isAfterCloseTime.value = false
nextTick(() => {
isAfterCloseTime.value = true
})
return
}
isAfterCloseTime.value = true
}
function syncStoreClosedState() { function syncStoreClosedState() {
if (shouldBlockStoreTrading()) { if (shouldBlockStoreTrading()) {
showFilter.value = false openStoreClosedModal()
isAfterCloseTime.value = true
} }
} }
@@ -78,8 +91,8 @@ export function useProductsPageProvider() {
if (!item?.show) return if (!item?.show) return
if (shouldBlockStoreTrading()) { if (shouldBlockStoreTrading()) {
showFilter.value = false message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message')))
isAfterCloseTime.value = true openStoreClosedModal()
return return
} }
@@ -100,8 +113,8 @@ export function useProductsPageProvider() {
watch(showFilter, (open) => { watch(showFilter, (open) => {
if (open && shouldBlockStoreTrading()) { if (open && shouldBlockStoreTrading()) {
showFilter.value = false message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message')))
isAfterCloseTime.value = true openStoreClosedModal()
return return
} }
if (!open) { if (!open) {
@@ -43,7 +43,7 @@
:product="item" :product="item"
:inactive="isProductPriceInactive(item)" :inactive="isProductPriceInactive(item)"
:locked="storeClosed" :locked="storeClosed"
@click="clickProduct(item)" @select="clickProduct(item)"
/> />
<div v-if="!loading && !items?.length" class="dproducts-empty"> <div v-if="!loading && !items?.length" class="dproducts-empty">
محصولی برای نمایش وجود ندارد. محصولی برای نمایش وجود ندارد.
@@ -58,7 +58,7 @@
import DesktopPageTopbar from '@/layouts/components/DesktopPageTopbar.vue' import DesktopPageTopbar from '@/layouts/components/DesktopPageTopbar.vue'
import DesktopProductCard from './components/DesktopProductCard.vue' import DesktopProductCard from './components/DesktopProductCard.vue'
import { useProductsPageContext } from '../composables/useProductsPage' import { useProductsPageContext } from '../composables/useProductsPage'
import { isStoreClosed, STORE_CLOSED_TITLE } from '@/utils/storeHours' import { isStoreClosed, shouldBlockStoreTrading, STORE_CLOSED_TITLE } from '@/utils/storeHours'
import { computed } from 'vue' import { computed } from 'vue'
const { const {
@@ -72,7 +72,7 @@ const {
storeClosedMessage, storeClosedMessage,
} = useProductsPageContext() } = useProductsPageContext()
const storeClosed = computed(() => isStoreClosed()) const storeClosed = computed(() => isStoreClosed() || shouldBlockStoreTrading())
</script> </script>
<style lang="less" src="./styles/desktop-products.less"></style> <style lang="less" src="./styles/desktop-products.less"></style>
@@ -7,7 +7,7 @@
'dproducts-card--locked': locked, 'dproducts-card--locked': locked,
}" }"
:disabled="!isClickable" :disabled="!isClickable"
@click="$emit('click')" @click="handleClick"
> >
<div class="dproducts-card__image-wrap"> <div class="dproducts-card__image-wrap">
<img :src="displayImage" class="dproducts-card__image" alt=""> <img :src="displayImage" class="dproducts-card__image" alt="">
@@ -48,12 +48,17 @@ const props = withDefaults(
{ inactive: false, locked: false }, { inactive: false, locked: false },
) )
defineEmits<{ const emit = defineEmits<{
click: [] select: []
}>() }>()
const isClickable = computed(() => props.product.show && !props.inactive && !props.locked) const isClickable = computed(() => props.product.show && !props.inactive && !props.locked)
function handleClick() {
if (!isClickable.value) return
emit('select')
}
const displayImage = computed(() => getProductDisplayImage(props.product)) const displayImage = computed(() => getProductDisplayImage(props.product))
const price = computed(() => getProductBuyPrice(props.product)) const price = computed(() => getProductBuyPrice(props.product))
+9 -4
View File
@@ -12,7 +12,7 @@
<BasicActionSheet v-if="!isDesktop" placement="bottom" v-model:show="showFilter"> <BasicActionSheet v-if="!isDesktop" placement="bottom" v-model:show="showFilter">
<div v-if="showFilter" :key="orderSheetKey"> <div v-if="showFilter" :key="orderSheetKey">
<indexGold <indexGold
v-if="usesQuantityTrade(selectedProduct)" v-if="usesMeltedOrQuantityTrade(selectedProduct)"
:ProductItem="selectedProduct" :ProductItem="selectedProduct"
/> />
<DealProduct v-else :ProductItem="selectedProduct" @ordered="onProductOrdered" /> <DealProduct v-else :ProductItem="selectedProduct" @ordered="onProductOrdered" />
@@ -22,14 +22,14 @@
<BasicModal <BasicModal
v-else v-else
v-model:visible="showFilter" v-model:visible="showFilter"
class="dproducts-order-panel" wrap-class-name="dproducts-order-panel"
:title="selectedProduct?.title ?? 'ثبت سفارش'" :title="selectedProduct?.title ?? 'ثبت سفارش'"
width="560px" width="560px"
destroy-on-close destroy-on-close
> >
<div v-if="showFilter" :key="orderSheetKey"> <div v-if="showFilter" :key="orderSheetKey">
<indexGold <indexGold
v-if="usesQuantityTrade(selectedProduct)" v-if="usesMeltedOrQuantityTrade(selectedProduct)"
:ProductItem="selectedProduct" :ProductItem="selectedProduct"
/> />
<DealProduct v-else :ProductItem="selectedProduct" @ordered="onProductOrdered" /> <DealProduct v-else :ProductItem="selectedProduct" @ordered="onProductOrdered" />
@@ -73,7 +73,12 @@ import DealProduct from '@/views/base/products/components/DealProduct.vue'
import BasicModal from '@/components/BasicPacks/BasicModal.vue' import BasicModal from '@/components/BasicPacks/BasicModal.vue'
import ResponsiveViewPair from '@/layouts/components/ResponsiveViewPair.vue' import ResponsiveViewPair from '@/layouts/components/ResponsiveViewPair.vue'
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout' import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
import { usesQuantityTrade } from '@/utils/productCategories' import type { Product } from '@/models/products'
import { isMeltedTradeGroup, usesQuantityTrade } from '@/utils/productCategories'
function usesMeltedOrQuantityTrade(product?: Product) {
return usesQuantityTrade(product) || isMeltedTradeGroup(product?.group_type)
}
import { STORE_CLOSED_TITLE } from '@/utils/storeHours' import { STORE_CLOSED_TITLE } from '@/utils/storeHours'
import { useProductsPageProvider } from './composables/useProductsPage' import { useProductsPageProvider } from './composables/useProductsPage'
import MobileProductsView from './mobile/MobileProductsView.vue' import MobileProductsView from './mobile/MobileProductsView.vue'
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

@@ -106,7 +106,7 @@ import router from '@/router'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue' import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { getProjectLoginLogo } from '@/utils/config' import { getProjectLoginLogo } from '@/utils/config'
import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton' import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton'
import copperProducts from '../../assets/img/login-copper-hero.jpg' import copperProducts from '../../assets/img/login-copper-hero.webp'
const pageLogo = getProjectLoginLogo() const pageLogo = getProjectLoginLogo()