diff --git a/components.d.ts b/components.d.ts index 751269f..43ea738 100644 --- a/components.d.ts +++ b/components.d.ts @@ -15,16 +15,13 @@ declare module 'vue' { AInputPassword: typeof import('ant-design-vue/es')['InputPassword'] AModal: typeof import('ant-design-vue/es')['Modal'] AppCreditLink: typeof import('./src/components/AppCreditLink.vue')['default'] - ARadio: typeof import('ant-design-vue/es')['Radio'] ARadioButton: typeof import('ant-design-vue/es')['RadioButton'] ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup'] ASelect: typeof import('ant-design-vue/es')['Select'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] ASlider: typeof import('ant-design-vue/es')['Slider'] ASpin: typeof import('ant-design-vue/es')['Spin'] - ASwitch: typeof import('ant-design-vue/es')['Switch'] ATag: typeof import('ant-design-vue/es')['Tag'] - ATextarea: typeof import('ant-design-vue/es')['Textarea'] ATooltip: typeof import('ant-design-vue/es')['Tooltip'] BaseDatePicker: typeof import('./src/components/BasicPacks/BaseDatePicker/src/BaseDatePicker.vue')['default'] Basic: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/basic.vue')['default'] @@ -70,6 +67,5 @@ declare module 'vue' { TransactionSkeleton: typeof import('./src/components/TransactionSkeleton.vue')['default'] VanActionSheet: typeof import('vant/es')['ActionSheet'] VanDialog: typeof import('vant/es')['Dialog'] - VanField: typeof import('vant/es')['Field'] } } diff --git a/src/utils/storeHours.ts b/src/utils/storeHours.ts index 5232cc3..ecad229 100644 --- a/src/utils/storeHours.ts +++ b/src/utils/storeHours.ts @@ -128,39 +128,69 @@ export function isStoreClosedBySchedule(now = new Date()): boolean { return false } + return isOutsideStoreTradingHours(now, start, end) +} + +export function isOutsideStoreTradingHours( + now = new Date(), + start?: string, + end?: string, +): boolean { + const hours = start != null && end != null + ? { start, end } + : getEffectiveTradingHours() + const currentSeconds = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds() - const openSeconds = parseTimeToSeconds(start) - const closeSeconds = parseTimeToSeconds(end) + const openSeconds = parseTimeToSeconds(hours.start) + const closeSeconds = parseTimeToSeconds(hours.end) return currentSeconds < openSeconds || currentSeconds > closeSeconds } +export function hasLivePriceQuote(): boolean { + const p = lastPrice.value + return getTradeBuyPrice(p) > 0 || getTradeSellPrice(p) > 0 +} + export function isStoreClosed(): boolean { void productTradingHoursVersion.value - const { closePriceEnabled } = getStoreTradingHours() - if (closePriceEnabled) { - if (lastPrice.value?.closed === true) { - return true - } - - return isStoreClosedBySchedule() + if (lastPrice.value?.closed === true) { + return true } - // وقتی close_price خاموش است، صفر بودن قیمت مرجع به معنی بسته بودن فروشگاه نیست. return isStoreClosedBySchedule() } -export function getStoreClosedMessage(): string { - const { start, end } = getEffectiveTradingHours() - const open = formatTradingTimeDisplay(start) - const close = formatTradingTimeDisplay(end) +export const STORE_CLOSED_TITLE = 'فروشگاه بسته است' - if (!open || !close) { - return 'فروشگاه در حال حاضر بسته است.' +export function stripHtmlMessage(message: string): string { + return message.replace(/<[^>]*>/g, '').trim() +} + +export function getStoreClosedHint(customMessage?: unknown): string { + const custom = typeof customMessage === 'string' ? customMessage.trim() : '' + if (custom) { + return stripHtmlMessage(custom) } + return '' +} - return `فروشگاه در حال حاضر بسته است. ساعت کاری از ${open} تا ${close} میباشد.` +export function getStoreClosedMessage(): string { + return '' +} + +/** برای toast/اعلان: پیام ادمین یا عنوان پیشفرض */ +export function resolveStoreClosedNotice(customMessage?: unknown): string { + return getStoreClosedHint(customMessage) || STORE_CLOSED_TITLE +} + +export function isMarketClosedForDisplay(): boolean { + return getPriceDisplayState() === 'closed' +} + +export function shouldBlockStoreTrading(): boolean { + return isMarketClosedForDisplay() } export type PriceDisplayState = 'open' | 'closed' | 'no_quote' @@ -168,34 +198,27 @@ export type PriceDisplayState = 'open' | 'closed' | 'no_quote' export const NO_QUOTE_MESSAGE = 'مظنه در دسترس نیست' /** - * وضعیت نمایش قیمت در صفحه اصلی: - * - closed → فروشگاه بسته است (خارج از ساعت کاری close_price یا بازه محصول) - * - no_quote → مظنه در دسترس نیست (قیمت زنده نداریم و show_last_price خاموش است) - * - open → نمایش عادی قیمت - * - * اولویت با status ارسالی از سرور است؛ اگر نبود به منطق سمت کلاینت برمیگردیم. + * وضعیت نمایش قیمت: + * - closed → فروشگاه بسته است (ساعت کاری، سیگنال سرور، یا نبود مظنه) + * - open → نمایش عادی قیمت */ export function getPriceDisplayState(): PriceDisplayState { void productTradingHoursVersion.value const p = lastPrice.value - const status = p?.status - if (status === 'closed') { + if (p?.status === 'closed' || p?.closed === true) { return 'closed' } - if (status === 'no_quote') { - return getTradeBuyPrice(p) > 0 ? 'open' : 'no_quote' - } - if (status === 'open') { - return getTradeBuyPrice(p) > 0 || getTradeSellPrice(p) > 0 ? 'open' : 'no_quote' - } - // سرور status نفرستاده (سازگاری با نسخه قدیمی) → استنتاج سمت کلاینت if (isStoreClosed()) { return 'closed' } - return getTradeBuyPrice(p) > 0 || getTradeSellPrice(p) > 0 ? 'open' : 'no_quote' + if (!hasLivePriceQuote()) { + return 'closed' + } + + return 'open' } export function getPriceDisplayMessage(state: PriceDisplayState = getPriceDisplayState()): string { diff --git a/src/views/base/copper&silver/index.vue b/src/views/base/copper&silver/index.vue index 58dafe6..89f9bba 100644 --- a/src/views/base/copper&silver/index.vue +++ b/src/views/base/copper&silver/index.vue @@ -242,7 +242,7 @@ import { calcFeeInGrams, calcPayablePriceRial, calcSellGoldDebit, feeDeductFromG import { resolveProductCashFeeBuyRial, resolveProductCashFeeSellRial } from '@/utils/productCashFee' import { formatCashWalletBalanceText, formatGoldWalletBalanceText } from '@/utils/productDealMethod' import { getCashWalletBalance } from '@/utils/productAssets' -import { isStoreClosed, getStoreClosedMessage } from '@/utils/storeHours' +import { isStoreClosed, resolveStoreClosedNotice } from '@/utils/storeHours' import { resetTransactionsPageData } from '@/views/base/transactions/composables/useTransactionsPageData' const infoVisible = ref(false) @@ -663,7 +663,7 @@ async function initPrice() { function okConfirm() { if (isStoreClosed()) { - message.warning(getStoreClosedMessage()) + message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message'))) return } confirmAction.value = true @@ -671,7 +671,7 @@ function okConfirm() { async function ok() { if (isStoreClosed()) { - message.warning(getStoreClosedMessage()) + message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message'))) return } try { diff --git a/src/views/base/gold/index.vue b/src/views/base/gold/index.vue index ad23ae1..0134c65 100644 --- a/src/views/base/gold/index.vue +++ b/src/views/base/gold/index.vue @@ -346,7 +346,7 @@ import { serviceFeePercentage, type TradeInputLock, } from '@/utils/serviceFee' -import { isStoreClosed, getStoreClosedMessage } from '@/utils/storeHours' +import { isStoreClosed, resolveStoreClosedNotice } from '@/utils/storeHours' import { resetTransactionsPageData } from '@/views/base/transactions/composables/useTransactionsPageData' import { formatCashWalletBalanceText, getWeightUnit } from '@/utils/productDealMethod' import { formatProductWalletBalanceText, getCashWalletBalance, getProductInventoryQuantity } from '@/utils/productAssets' @@ -776,7 +776,7 @@ async function initPrice() { function okConfirm() { if (isStoreClosed()) { - message.warning(getStoreClosedMessage()) + message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message'))) return } if (cashValidationMessage.value) { @@ -791,7 +791,7 @@ async function ok() { return } if (isStoreClosed()) { - message.warning(getStoreClosedMessage()) + message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message'))) return } try { diff --git a/src/views/base/home/components/CurrentPrice.vue b/src/views/base/home/components/CurrentPrice.vue index 7c8dce9..46c41d8 100644 --- a/src/views/base/home/components/CurrentPrice.vue +++ b/src/views/base/home/components/CurrentPrice.vue @@ -13,7 +13,7 @@ />
{{ statusTitle }}
-{{ statusHint }}
+{{ statusHint }}
@@ -55,8 +55,9 @@ import { useUserStore } from '@/store/userStore' import { getTradeBuyPrice, lastPrice, percentPriceChanged } from '@/utils/price' import { NO_QUOTE_MESSAGE, + STORE_CLOSED_TITLE, getPriceDisplayState, - getStoreClosedMessage, + getStoreClosedHint, } from '@/utils/storeHours' import { formatSignedPercentChange } from '@/utils/usePrice' @@ -65,16 +66,12 @@ const userStore = useUserStore() const displayState = computed(() => getPriceDisplayState()) const statusTitle = computed(() => - displayState.value === 'closed' ? 'فروشگاه بسته است' : NO_QUOTE_MESSAGE + displayState.value === 'closed' ? STORE_CLOSED_TITLE : NO_QUOTE_MESSAGE ) const statusHint = computed(() => { if (displayState.value === 'closed') { - const custom = userStore.getValueByKey('closed_message') - if (typeof custom === 'string' && custom.trim()) { - return custom.replace(/<[^>]*>/g, '').trim() - } - return getStoreClosedMessage() + return getStoreClosedHint(userStore.getValueByKey('closed_message')) } return 'در حال حاضر مظنهای برای نمایش وجود ندارد.' }) diff --git a/src/views/base/products/components/DealProduct.vue b/src/views/base/products/components/DealProduct.vue index 2470a65..526b0e8 100644 --- a/src/views/base/products/components/DealProduct.vue +++ b/src/views/base/products/components/DealProduct.vue @@ -321,7 +321,7 @@ import { } from '@/utils/productOrderLimit' import { useWalletAssets } from '@/composables/useWalletAssets' import { formatProductWalletBalanceText, formatInventoryCardValue, getCashWalletBalance, getProductInventoryQuantity } from '@/utils/productAssets' -import { isStoreClosed, getStoreClosedMessage } from '@/utils/storeHours' +import { isStoreClosed, resolveStoreClosedNotice } from '@/utils/storeHours' const catalogProducts = getProductsCatalogRef() @@ -864,7 +864,7 @@ async function initPrice() { function okConfirm() { if (isStoreClosed()) { - message.warning(getStoreClosedMessage()) + message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message'))) return } confirmAction.value = true @@ -873,7 +873,7 @@ function okConfirm() { async function ok() { if (isStoreClosed()) { - message.warning(getStoreClosedMessage()) + message.warning(resolveStoreClosedNotice(userStore.getValueByKey('closed_message'))) return } try { diff --git a/src/views/base/products/composables/useProductsPage.ts b/src/views/base/products/composables/useProductsPage.ts index 3b57e92..bb4cc22 100644 --- a/src/views/base/products/composables/useProductsPage.ts +++ b/src/views/base/products/composables/useProductsPage.ts @@ -13,7 +13,8 @@ import { loading } from '@/utils' import type { Product } from '@/models/products' import { cloneDeep } from 'lodash' import { isProductPriceInactive } from '@/utils/productPrice' -import { getStoreClosedMessage, isStoreClosed } from '@/utils/storeHours' +import { getStoreClosedHint, shouldBlockStoreTrading } from '@/utils/storeHours' +import { useUserStore } from '@/store/userStore' import { lastPrice } from '@/utils/price' import { changeProductsTab, @@ -50,15 +51,18 @@ export const PRODUCTS_PAGE_CONTEXT_KEY: InjectionKey{{ storeClosedMessage }}
-از همراهی و اعتماد شما سپاسگزاریم.🤍
+