chore: sync price monitor updates
This commit is contained in:
+37
-19
@@ -7,6 +7,9 @@ import {
|
||||
priceSocketConnected,
|
||||
priceStreamConnectingSince,
|
||||
priceStreamLifecycle,
|
||||
priceStreamList,
|
||||
priceStreamProducts,
|
||||
priceStreamServerUnix,
|
||||
priceWssEnabled,
|
||||
} from '@/utils/priceSocketState'
|
||||
import {
|
||||
@@ -282,28 +285,21 @@ export function notifyPriceLastFetchFailed() {
|
||||
void maybeShowNetworkAlert()
|
||||
}
|
||||
|
||||
function onTvBoard() {
|
||||
if (typeof window === 'undefined') return false
|
||||
const path = window.location.pathname.replace(/\/+$/, '') || '/'
|
||||
return path === '/tv' || path.endsWith('/tv') || path === '/monitor' || path.endsWith('/monitor')
|
||||
}
|
||||
|
||||
async function runFallbackPoll() {
|
||||
if (onTvBoard() || tvStreamKey || !priceWssEnabled.value || priceSocketConnected.value) {
|
||||
if (tvStreamKey || !priceWssEnabled.value || priceSocketConnected.value) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const { getLastPrices, hasRecentPriceFromSource } = await import('@/utils/price')
|
||||
const jobs: Promise<unknown>[] = [getLastPrices()]
|
||||
if (!tvStreamKey) {
|
||||
const { refreshProductsPageData } = await import(
|
||||
'@/views/base/products/composables/useProductsPageData'
|
||||
)
|
||||
jobs.push(refreshProductsPageData())
|
||||
}
|
||||
const { refreshProductsPageData } = await import(
|
||||
'@/views/base/products/composables/useProductsPageData'
|
||||
)
|
||||
|
||||
const [priceResult] = await Promise.allSettled(jobs)
|
||||
const [priceResult] = await Promise.allSettled([
|
||||
getLastPrices(),
|
||||
refreshProductsPageData(),
|
||||
])
|
||||
|
||||
const priceOk =
|
||||
priceResult.status === 'fulfilled'
|
||||
@@ -508,6 +504,7 @@ function handleListPayload(payload: unknown) {
|
||||
}
|
||||
|
||||
touchStreamActivity()
|
||||
priceStreamList.value = products as Array<Record<string, unknown>>
|
||||
applyProductsListFromStream(products)
|
||||
}
|
||||
|
||||
@@ -572,6 +569,31 @@ function bindStreamEvents(source: AuthPriceStream) {
|
||||
}
|
||||
})
|
||||
|
||||
source.addEventListener('products', (event) => {
|
||||
try {
|
||||
const rows = JSON.parse(event.data)
|
||||
if (Array.isArray(rows) && rows.length) {
|
||||
touchStreamActivity()
|
||||
priceStreamProducts.value = rows
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Price SSE products parse failed', error)
|
||||
}
|
||||
})
|
||||
|
||||
source.addEventListener('time', (event) => {
|
||||
try {
|
||||
const payload = JSON.parse(event.data) as { unix?: number }
|
||||
const unix = Number(payload?.unix)
|
||||
if (unix > 0) {
|
||||
touchStreamActivity()
|
||||
priceStreamServerUnix.value = unix
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Price SSE time parse failed', error)
|
||||
}
|
||||
})
|
||||
|
||||
source.addEventListener('app_notification', (event) => {
|
||||
try {
|
||||
handleAppNotificationPayload(JSON.parse(event.data))
|
||||
@@ -750,10 +772,6 @@ function unbindBrowserNetworkListeners() {
|
||||
window.removeEventListener('offline', onBrowserOffline)
|
||||
}
|
||||
|
||||
export function isTvStreamActive() {
|
||||
return Boolean(tvStreamKey)
|
||||
}
|
||||
|
||||
export function startTvPriceStream(
|
||||
settingGetter: (key: string) => unknown,
|
||||
key: string,
|
||||
|
||||
@@ -9,6 +9,15 @@ export const priceStreamLifecycle = ref<PriceStreamLifecycle>('idle')
|
||||
|
||||
export const priceStreamConnectingSince = ref(0)
|
||||
|
||||
/** آخرین رویداد list استریم */
|
||||
export const priceStreamList = ref<Array<Record<string, unknown>>>([])
|
||||
|
||||
/** آخرین بدنهٔ tv/products که از SSE آمده */
|
||||
export const priceStreamProducts = ref<Array<Record<string, unknown>>>([])
|
||||
|
||||
/** unix ساعت سرور از رویداد time استریم */
|
||||
export const priceStreamServerUnix = ref(0)
|
||||
|
||||
const CONNECTING_POLL_AFTER_MS = 8000
|
||||
|
||||
export function shouldUsePricePolling(): boolean {
|
||||
|
||||
@@ -61,15 +61,6 @@ function sellCashFee(product: Product, base: number) {
|
||||
return resolveProductCashFeeSellRial(product, base, cashFeeOptions(product, 'sell'))
|
||||
}
|
||||
|
||||
/** سمت خرید/فروش همکار؛ اگر سرور نفرستاده باشد همان قیمت وسط قبلی */
|
||||
function colleagueSideUnit(product: Product, side: 'buy' | 'sell', live: number): number {
|
||||
const sided = side === 'buy' ? Number(product.price_buy ?? 0) : Number(product.price_sell ?? 0)
|
||||
if (sided > 0) {
|
||||
return sided
|
||||
}
|
||||
return getColleagueSourcedUnitPrice(product, live)
|
||||
}
|
||||
|
||||
/** قیمت منبع همکار؛ اگر خالی بود آبشده همان مظنهٔ صفحه اصلی را میگیرد */
|
||||
function getColleagueSourcedUnitPrice(product: Product, live: number, apiPrice = Number(product.price ?? 0)): number {
|
||||
if (apiPrice > 0) {
|
||||
@@ -143,7 +134,7 @@ export function getProductBaseBuyPrice(product?: Product | null): number {
|
||||
}
|
||||
|
||||
if (isColleaguePriceProduct(product)) {
|
||||
return colleagueSideUnit(product, 'buy', getTradeBuyPrice(lastPrice.value))
|
||||
return getColleagueSourcedUnitPrice(product, getTradeBuyPrice(lastPrice.value))
|
||||
}
|
||||
|
||||
if (isMeltedProductUsingAppPrice(product) || isAppPriceProduct(product)) {
|
||||
@@ -220,7 +211,11 @@ export function getProductBaseSellPrice(product?: Product | null): number {
|
||||
}
|
||||
|
||||
if (isColleaguePriceProduct(product)) {
|
||||
return colleagueSideUnit(product, 'sell', getTradeSellPrice(lastPrice.value))
|
||||
return getColleagueSourcedUnitPrice(
|
||||
product,
|
||||
getTradeSellPrice(lastPrice.value),
|
||||
Number(product.sellPrice ?? product.price ?? 0),
|
||||
)
|
||||
}
|
||||
|
||||
if (isMeltedProductUsingAppPrice(product) || isAppPriceProduct(product)) {
|
||||
|
||||
Reference in New Issue
Block a user