diff --git a/src/App.vue b/src/App.vue
index b1540fc..54a0541 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -104,6 +104,7 @@
+
@@ -129,6 +130,8 @@ import EnamadBadge from '@/components/EnamadBadge.vue'
import { usePwaInstall } from '@/composables/usePwaInstall'
import PwaInstallGuideModal from '@/components/pwa/PwaInstallGuideModal.vue'
import GoldDayCalculatorModal from '@/components/GoldDayCalculatorModal.vue'
+import GoldLoading from '@/components/GoldLoading.vue'
+import { colleagueOrderWaiting, resumeColleagueOrderIfPending } from '@/composables/useColleagueOrderWait'
import { useUserStore } from '@/store/userStore'
import { useSettingsStore } from '@/store/settingsStore'
import { connectChatIfExists, disconnectChat, isSettingFlagOn, unreadSupportCount, useChatService } from '@/utils/chat'
@@ -272,6 +275,14 @@ watch(
{ immediate: true },
)
+watch(
+ () => getToken(),
+ (token) => {
+ if (token) void resumeColleagueOrderIfPending()
+ },
+ { immediate: true },
+)
+
watch(latestIncomingNotification, (payload) => {
if (!payload) return
if (payload.at === lastSupportToastAt) return
diff --git a/src/api/order.ts b/src/api/order.ts
index ced8c0b..3c3913e 100644
--- a/src/api/order.ts
+++ b/src/api/order.ts
@@ -7,11 +7,22 @@ import {useUserStore} from "@/store/userStore";
const userStore = useUserStore()
-export const createOrder = async (obj: Order): Promise => {
- return await useAxios.post(`/customer${!userStore.isSingle ? '' : '/single'}/order`, obj)
+function customerOrderPrefix() {
+ return `/customer${!userStore.isSingle ? '' : '/single'}`
}
+export const createOrder = async (obj: Order): Promise => {
+ return await useAxios.post(`${customerOrderPrefix()}/order`, obj)
+}
+
+export const getPendingColleagueOrder = async (): Promise => {
+ return await useAxios.get(`${customerOrderPrefix()}/order/pending`)
+}
+
+export const getColleagueOrderStatus = async (id: number): Promise => {
+ return await useAxios.get(`${customerOrderPrefix()}/order/${id}/status`)
+}
export const getOrders = async (tbl: Ref>): Promise> => {
- return await useAxios.post>(`/customer${!userStore.isSingle ? '' : '/single'}/order/table`, tbl)
+ return await useAxios.post>(`${customerOrderPrefix()}/order/table`, tbl)
}
diff --git a/src/composables/useColleagueOrderWait.ts b/src/composables/useColleagueOrderWait.ts
new file mode 100644
index 0000000..6a5e715
--- /dev/null
+++ b/src/composables/useColleagueOrderWait.ts
@@ -0,0 +1,176 @@
+import { ref } from 'vue'
+import { message } from 'ant-design-vue'
+import router from '@/router'
+import { getColleagueOrderStatus, getPendingColleagueOrder } from '@/api/order'
+import { useUserStore } from '@/store/userStore'
+import { useWalletStore } from '@/store/walletStore'
+import { useFundUserStore } from '@/store/fundStore'
+import { getToken } from '@/utils'
+
+export const colleagueOrderWaiting = ref(false)
+
+const CLIENT_POLL_MS = 5000
+const STREAM_EVENT = 'colleague-order'
+
+type WaitResult = 'success' | 'failed' | 'none'
+
+let inflight: Promise | null = null
+
+export function emitColleagueOrderFromStream(payload: unknown) {
+ window.dispatchEvent(new CustomEvent(STREAM_EVENT, { detail: payload }))
+}
+
+export function isColleagueOrderPending(res: unknown): boolean {
+ if (!res || typeof res !== 'object') return false
+ const row = res as Record
+ if (row.pending === true) return true
+ if (Array.isArray(row) && row[0]?.pending === true) return true
+ const sts = Number(
+ row[0]?.sts ?? row.sts ?? row[1]?.order?.sts ?? row.order?.sts ?? NaN
+ )
+ return sts === 4
+}
+
+export function colleagueOrderIdFromResponse(res: unknown): number | null {
+ if (!res || typeof res !== 'object') return null
+ const row = res as Record
+ const id = Number(
+ row[0]?.order_id ?? row.order_id ?? row[1]?.order?.id ?? row.order?.id ?? NaN
+ )
+ return id > 0 ? id : null
+}
+
+async function finishSuccess() {
+ try {
+ await useUserStore().getMyInfo()
+ } catch {
+ /* ignore */
+ }
+ try {
+ await useWalletStore().getMyWallet()
+ } catch {
+ /* ignore */
+ }
+ try {
+ await useFundUserStore().getMyFund()
+ } catch {
+ /* ignore */
+ }
+ try {
+ const { resetTransactionsPageData } = await import(
+ '@/views/base/transactions/composables/useTransactionsPageData'
+ )
+ resetTransactionsPageData()
+ } catch {
+ /* optional */
+ }
+ message.success('سفارش شما با موفقیت انجام شد')
+ if (router.currentRoute.value.name !== 'transactions') {
+ await router.push({ name: 'transactions' })
+ }
+}
+
+function stsFromPayload(payload: Record | null | undefined): number | null {
+ if (!payload) return null
+ const sts = Number(payload.sts ?? payload.order?.sts)
+ return Number.isFinite(sts) ? sts : null
+}
+
+async function readStatus(orderId: number | null): Promise {
+ try {
+ if (orderId && orderId > 0) {
+ const row = (await getColleagueOrderStatus(orderId)) as Record
+ return stsFromPayload(row)
+ }
+ const row = (await getPendingColleagueOrder()) as Record
+ if (row?.pending === false && row?.sts == null) {
+ return null
+ }
+ return stsFromPayload(row)
+ } catch {
+ return null
+ }
+}
+
+export async function waitForColleagueOrder(orderId?: number | null): Promise {
+ if (inflight) return inflight
+
+ inflight = (async () => {
+ colleagueOrderWaiting.value = true
+ let settled: WaitResult | null = null
+
+ const finish = (result: WaitResult) => {
+ if (settled) return
+ settled = result
+ }
+
+ const onStream = (event: Event) => {
+ const detail = (event as CustomEvent).detail as Record | undefined
+ if (orderId && Number(detail?.order_id) > 0 && Number(detail.order_id) !== orderId) {
+ return
+ }
+ const sts = stsFromPayload(detail)
+ if (sts === 2) finish('success')
+ if (sts === 3) finish('failed')
+ }
+
+ window.addEventListener(STREAM_EVENT, onStream)
+
+ try {
+ while (!settled) {
+ const sts = await readStatus(orderId ?? null)
+ if (sts === 2) {
+ finish('success')
+ break
+ }
+ if (sts === 3) {
+ finish('failed')
+ break
+ }
+ await new Promise((resolve) => {
+ const timer = window.setTimeout(resolve, CLIENT_POLL_MS)
+ const once = () => {
+ window.clearTimeout(timer)
+ resolve()
+ }
+ window.addEventListener(STREAM_EVENT, once, { once: true })
+ })
+ }
+ } finally {
+ window.removeEventListener(STREAM_EVENT, onStream)
+ colleagueOrderWaiting.value = false
+ }
+
+ if (settled === 'success') {
+ await finishSuccess()
+ return 'success'
+ }
+
+ message.error('سفارش توسط همکار رد شد')
+ return 'failed'
+ })().finally(() => {
+ inflight = null
+ })
+
+ return inflight
+}
+
+export async function afterCreateOrder(res: unknown): Promise {
+ if (isColleagueOrderPending(res)) {
+ return waitForColleagueOrder(colleagueOrderIdFromResponse(res))
+ }
+ await finishSuccess()
+ return 'success'
+}
+
+export async function resumeColleagueOrderIfPending(): Promise {
+ if (!getToken()) return 'none'
+ try {
+ const row = (await getPendingColleagueOrder()) as Record
+ if (!row?.pending) return 'none'
+ const id = Number(row.order_id ?? row.order?.id ?? 0)
+ return waitForColleagueOrder(id > 0 ? id : null)
+ } catch {
+ return 'none'
+ }
+}
diff --git a/src/utils/priceSocket.ts b/src/utils/priceSocket.ts
index 5f9e5a2..24f0c22 100644
--- a/src/utils/priceSocket.ts
+++ b/src/utils/priceSocket.ts
@@ -560,6 +560,16 @@ function bindStreamEvents(source: AuthPriceStream) {
}
})
+ source.addEventListener('colleague_order', (event) => {
+ try {
+ void import('@/composables/useColleagueOrderWait').then(({ emitColleagueOrderFromStream }) => {
+ emitColleagueOrderFromStream(JSON.parse(event.data))
+ })
+ } catch (error) {
+ console.warn('Colleague order SSE parse failed', error)
+ }
+ })
+
source.addEventListener('ping', () => {
touchStreamActivity()
})
diff --git a/src/views/base/gold/index.vue b/src/views/base/gold/index.vue
index 1df9163..0cf25e1 100644
--- a/src/views/base/gold/index.vue
+++ b/src/views/base/gold/index.vue
@@ -251,6 +251,7 @@ import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import router from '@/router'
import { useWalletStore } from '@/store/walletStore'
import { createOrder } from '@/api/order'
+import { afterCreateOrder } from '@/composables/useColleagueOrderWait'
import { message } from 'ant-design-vue'
import type { Price } from '@/models/home'
import { getLastPrice } from '@/api/home'
@@ -790,7 +791,7 @@ async function ok() {
loading.value = true
await nextTick()
infoVisible.value = true
- await createOrder({
+ const res = await createOrder({
direction: isBuy.value ? 1 : 2,
price: Math.round(unitPrice.value),
amount: normalizeOrderGoldAmount(orderGoldAmount.value),
@@ -798,17 +799,16 @@ async function ok() {
target_cash: calcTradeTargetCash(form.value.goldCash, inputLock.value),
abshode_id: props.ProductItem?.id,
})
- await walletStore.getMyWallet()
- await loadWalletAssets(true)
- await router.push({ name: 'transactions' })
+ const result = await afterCreateOrder(res)
+ if (result !== 'success') {
+ return
+ }
form.value = {
goldValue: undefined,
goldCash: undefined,
percentWallet: 0,
}
inputLock.value = null
- message.success('سفارش شما با موفقیت انجام شد')
- await fundStore.getMyFund()
} catch (e) {
// console.log(e)
// await initPrice()
diff --git a/src/views/base/products/components/DealProduct.vue b/src/views/base/products/components/DealProduct.vue
index 0b37da4..0293a52 100644
--- a/src/views/base/products/components/DealProduct.vue
+++ b/src/views/base/products/components/DealProduct.vue
@@ -252,6 +252,7 @@ import BasicButton from '@/components/BasicPacks/BasicButton.vue'
import router from '@/router'
import { useWalletStore } from '@/store/walletStore'
import { createOrder } from '@/api/order'
+import { afterCreateOrder } from '@/composables/useColleagueOrderWait'
import { FormInstance, message } from 'ant-design-vue'
import type { Price } from '@/models/home'
import Icon from '@/components/BasicPacks/BasicIcon.vue'
@@ -734,9 +735,10 @@ async function ok() {
window.location.href = returnUrl
return // Stop execution here
}
- // If no gateway, continue with normal flow
- await walletStore.getMyWallet()
- await router.push({ name: 'transactions' })
+ const result = await afterCreateOrder(data)
+ if (result !== 'success') {
+ return
+ }
form.value = {
goldValue: undefined,
goldCash: undefined,
@@ -744,9 +746,6 @@ async function ok() {
method: 'cash',
gateway: false
}
- // refreshTable()
- message.success('سفارش شما با موفقیت انجام شد')
- await loadWalletAssets(true)
} catch (e) {
// console.log(e)
// await initPrice()