fix bug of main-page for guest
This commit is contained in:
@@ -35,3 +35,5 @@
|
|||||||
- 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 هر دو باز
|
- 2026-10-17 | باز/بسته خرید فروش محصول | `utils/productTradeOpen.ts` + `gold/index.vue` | `open_buy`/`open_sell`؛ بدون ProductItem هر دو باز
|
||||||
|
- 2026-10-17 | نمودار مهمان ۴۰۱ | `usePriceChart.ts` + `api/home.ts` + سرور `routes/api.php` `POST /api/price/all` | مهمان product/list نمیزند؛ تاریخچه نمودار از `/api/price/all` (همان priceData)
|
||||||
|
- 2026-10-17 | قیمت زنده مهمان | `bootstrap.ts` + `priceSocket.ts` + سرور `/api/price/stream` بدون auth | SSE بدون توکن؛ polling پشتیبان product/list فقط با توکن
|
||||||
|
|||||||
+4
-1
@@ -8,4 +8,7 @@ export const getPrice = async () => await useAxios.get<Price>(`/api/price/up`)
|
|||||||
|
|
||||||
export const getLastPrice = async () => await useAxios.get<Price>(`/api/price/last`)
|
export const getLastPrice = async () => await useAxios.get<Price>(`/api/price/last`)
|
||||||
|
|
||||||
export const getAllPrices = async () => await useAxios.post('/customer/prices/all')
|
export const getAllPrices = async () => await useAxios.post('/customer/prices/all')
|
||||||
|
|
||||||
|
/** نمودار مهمان — همان بدنهٔ prices/all، بدون توکن مشتری */
|
||||||
|
export const getPublicChartPrices = async () => await useAxios.post('/api/price/all')
|
||||||
@@ -117,9 +117,7 @@ export async function bootstrapApp() {
|
|||||||
|
|
||||||
await withTimeout(settingsStore.fetchSettings(), 45000, 'Settings loading timeout')
|
await withTimeout(settingsStore.fetchSettings(), 45000, 'Settings loading timeout')
|
||||||
|
|
||||||
if (getToken()) {
|
initPriceRealtimeChannel((key) => settingsStore.getSettingByKey(key))
|
||||||
initPriceRealtimeChannel((key) => settingsStore.getSettingByKey(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getToken()) {
|
if (getToken()) {
|
||||||
await withTimeout(userStore.getMyInfo(), 45000, 'User session loading timeout')
|
await withTimeout(userStore.getMyInfo(), 45000, 'User session loading timeout')
|
||||||
|
|||||||
+20
-21
@@ -38,7 +38,7 @@ const STREAM_CONNECTING = 0
|
|||||||
const STREAM_OPEN = 1
|
const STREAM_OPEN = 1
|
||||||
const STREAM_CLOSED = 2
|
const STREAM_CLOSED = 2
|
||||||
|
|
||||||
/** EventSource نمیتواند Authorization بفرستد؛ استریم همچنان auth:customer میخواهد. */
|
/** fetch + ReadableStream — با توکن اختلاف قیمت ویژه؛ بدون توکن همان مظنهٔ عمومی (مهمان). */
|
||||||
class AuthPriceStream extends EventTarget {
|
class AuthPriceStream extends EventTarget {
|
||||||
readyState = STREAM_CONNECTING
|
readyState = STREAM_CONNECTING
|
||||||
onopen: (() => void) | null = null
|
onopen: (() => void) | null = null
|
||||||
@@ -46,7 +46,7 @@ class AuthPriceStream extends EventTarget {
|
|||||||
onmessage: (() => void) | null = null
|
onmessage: (() => void) | null = null
|
||||||
private abort = new AbortController()
|
private abort = new AbortController()
|
||||||
|
|
||||||
constructor(url: string, token: string) {
|
constructor(url: string, token?: string) {
|
||||||
super()
|
super()
|
||||||
void this.start(url, token)
|
void this.start(url, token)
|
||||||
}
|
}
|
||||||
@@ -56,13 +56,18 @@ class AuthPriceStream extends EventTarget {
|
|||||||
this.abort.abort()
|
this.abort.abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async start(url: string, token: string) {
|
private async start(url: string, token?: string) {
|
||||||
try {
|
try {
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
Accept: 'text/event-stream',
|
||||||
|
}
|
||||||
|
const bearer = String(token ?? '').trim()
|
||||||
|
if (bearer) {
|
||||||
|
headers.Authorization = `Bearer ${bearer}`
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
headers: {
|
headers,
|
||||||
Accept: 'text/event-stream',
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
signal: this.abort.signal,
|
signal: this.abort.signal,
|
||||||
})
|
})
|
||||||
@@ -191,10 +196,6 @@ function resolveStreamUrl(): string | null {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!findStoredAuthToken()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const base = String(getConfigApp('node_server') || window.location.origin).replace(/\/$/, '')
|
const base = String(getConfigApp('node_server') || window.location.origin).replace(/\/$/, '')
|
||||||
return `${base}${resolveStreamPath()}`
|
return `${base}${resolveStreamPath()}`
|
||||||
}
|
}
|
||||||
@@ -301,10 +302,12 @@ async function runFallbackPoll() {
|
|||||||
'@/views/base/products/composables/useProductsPageData'
|
'@/views/base/products/composables/useProductsPageData'
|
||||||
)
|
)
|
||||||
|
|
||||||
const [priceResult] = await Promise.allSettled([
|
const pollTasks: Promise<unknown>[] = [getLastPrices()]
|
||||||
getLastPrices(),
|
if (findStoredAuthToken()) {
|
||||||
refreshProductsPageData(),
|
pollTasks.push(refreshProductsPageData())
|
||||||
])
|
}
|
||||||
|
|
||||||
|
const [priceResult] = await Promise.allSettled(pollTasks)
|
||||||
|
|
||||||
const priceOk =
|
const priceOk =
|
||||||
priceResult.status === 'fulfilled'
|
priceResult.status === 'fulfilled'
|
||||||
@@ -643,7 +646,7 @@ function connect() {
|
|||||||
|
|
||||||
const url = resolveStreamUrl()
|
const url = resolveStreamUrl()
|
||||||
const token = findStoredAuthToken()
|
const token = findStoredAuthToken()
|
||||||
if (!url || !token) {
|
if (!url) {
|
||||||
priceSocketConnected.value = false
|
priceSocketConnected.value = false
|
||||||
priceStreamLifecycle.value = 'closed'
|
priceStreamLifecycle.value = 'closed'
|
||||||
clearConnectingLifecycle()
|
clearConnectingLifecycle()
|
||||||
@@ -661,7 +664,7 @@ function connect() {
|
|||||||
markConnectingLifecycle()
|
markConnectingLifecycle()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eventSource = new AuthPriceStream(url, token)
|
eventSource = new AuthPriceStream(url, token ?? undefined)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Price SSE connect failed', error)
|
console.warn('Price SSE connect failed', error)
|
||||||
handleStreamLost()
|
handleStreamLost()
|
||||||
@@ -824,10 +827,6 @@ export function isPriceWebSocketEnabled(settingGetter: (key: string) => unknown)
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!findStoredAuthToken()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolveStreamUrl() !== null
|
return resolveStreamUrl() !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import { getAllPrices } from '@/api/home'
|
import { getAllPrices, getPublicChartPrices } from '@/api/home'
|
||||||
import { getProductsCatalog, getProductsCatalogRef } from '@/composables/useProductsCatalog'
|
import { getProductsCatalog, getProductsCatalogRef } from '@/composables/useProductsCatalog'
|
||||||
|
import { getToken } from '@/utils'
|
||||||
import { getTradeBuyPrice, getTradeSellPrice } from '@/utils/price'
|
import { getTradeBuyPrice, getTradeSellPrice } from '@/utils/price'
|
||||||
|
|
||||||
export type ChartMetalType = 'katod' | 'maftol' | 'shamsh'
|
export type ChartMetalType = 'katod' | 'maftol' | 'shamsh'
|
||||||
@@ -132,7 +133,7 @@ async function fetchPrices(force = false) {
|
|||||||
chartFetchPromise = (async () => {
|
chartFetchPromise = (async () => {
|
||||||
try {
|
try {
|
||||||
chartLoading.value = true
|
chartLoading.value = true
|
||||||
const response = await getAllPrices()
|
const response = await (getToken() ? getAllPrices() : getPublicChartPrices())
|
||||||
const data = resolvePricesMap(response)
|
const data = resolvePricesMap(response)
|
||||||
cachedPrices.value = data
|
cachedPrices.value = data
|
||||||
applyTimelineFromCache()
|
applyTimelineFromCache()
|
||||||
@@ -149,6 +150,14 @@ async function fetchPrices(force = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadMetalChartOffsets(force = false) {
|
async function loadMetalChartOffsets(force = false) {
|
||||||
|
if (!getToken()) {
|
||||||
|
if (!metalOffsetLoaded) {
|
||||||
|
syncChartSeries()
|
||||||
|
metalOffsetLoaded = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!force && metalOffsetLoaded && catalogProducts.value.length > 0) {
|
if (!force && metalOffsetLoaded && catalogProducts.value.length > 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,7 +221,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="variant === 'desktop' && !isRegister"
|
v-if="isRegister && variant === 'desktop'"
|
||||||
class="dauth-switch"
|
class="dauth-switch"
|
||||||
>
|
>
|
||||||
<span>حساب کاربری ندارید؟</span>
|
<span>حساب کاربری ندارید؟</span>
|
||||||
|
|||||||
@@ -8,9 +8,7 @@
|
|||||||
<p class="dauth-card__subtitle">برای ادامه، رمز ورود خود را انتخاب کنید.</p>
|
<p class="dauth-card__subtitle">برای ادامه، رمز ورود خود را انتخاب کنید.</p>
|
||||||
</header>
|
</header>
|
||||||
<header v-else class="dauth-card__header">
|
<header v-else class="dauth-card__header">
|
||||||
<p class="dauth-card__eyebrow">حساب جدید</p>
|
|
||||||
<h2 class="dauth-card__title">ثبت نام</h2>
|
<h2 class="dauth-card__title">ثبت نام</h2>
|
||||||
<p class="dauth-card__subtitle">اطلاعات خود را برای ایجاد حساب وارد کنید</p>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<Login
|
<Login
|
||||||
|
|||||||
Reference in New Issue
Block a user