2026-01-18 13:01:46 +03:30
|
|
|
|
<template>
|
2026-05-14 13:44:43 +03:30
|
|
|
|
<div class="mt-10 p-5">
|
|
|
|
|
|
<div v-if="userStore.userInfo && !loading">
|
|
|
|
|
|
<!-- هشدار حداقل مبلغ -->
|
2026-01-18 13:01:46 +03:30
|
|
|
|
<div
|
2026-05-14 13:44:43 +03:30
|
|
|
|
v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
|
|
|
|
|
|
class="text-red text-xs flex gap-1 items-center justify-center mb-2"
|
2026-01-18 13:01:46 +03:30
|
|
|
|
>
|
2026-05-14 13:44:43 +03:30
|
|
|
|
<Icon icon="vuesax-linear:info-circle" size="16"/>
|
|
|
|
|
|
حداقل مبلغ اولیه برای ثبت سفارش {{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
|
2026-01-18 13:01:46 +03:30
|
|
|
|
</div>
|
2026-05-14 13:44:43 +03:30
|
|
|
|
|
|
|
|
|
|
<!-- بخش اصلی -->
|
|
|
|
|
|
<div class="p-1 from-primary rounded-lg p-px to-transparent" :class="isGaroosi ? 'mt-0' : 'mt-5'">
|
|
|
|
|
|
<!-- داراییها (فقط گاروسی) -->
|
|
|
|
|
|
<div v-if="isGaroosi" class="flex justify-between px-2 mb-2">
|
|
|
|
|
|
<AssetItem label="دارایی طلایی:" :value="`${(userStore?.userInfo?.wallet?.count_gold ?? 0).toFixed(3)} گرم`"/>
|
|
|
|
|
|
<AssetItem label="دارایی ریالی:"
|
|
|
|
|
|
:value="`${usePriceWithoutType(userStore?.userInfo?.wallet?.count_cash ?? 0)} ریال`"/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- دکمههای اصلی -->
|
|
|
|
|
|
<div class="p-2 py-3 rounded-lg bg-tertiary">
|
|
|
|
|
|
<div class="flex justify-between">
|
|
|
|
|
|
<ActionButton
|
|
|
|
|
|
v-for="action in mainActions"
|
|
|
|
|
|
:key="action.name"
|
|
|
|
|
|
:action="action"
|
|
|
|
|
|
@click="action.handler"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- بخش کد معرف (گاروسی) -->
|
|
|
|
|
|
<ReferralSection v-if="isGaroosi"/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- بخش داراییها (سایر پروژهها) -->
|
|
|
|
|
|
<AssetsSection v-else @openGoldModal="openGoldModal" @openRialModal="openRialModal"/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- پیام بسته بودن بازار -->
|
|
|
|
|
|
<MarketClosedMessage v-if="showClosedMessage" :message="closedMessage"/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- قیمت فعلی -->
|
|
|
|
|
|
<CurrentPrice/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- بنرها -->
|
|
|
|
|
|
<BannerSlider v-if="isGaroosi && banners?.length" :banners="banners" @bannerClick="handleBannerClick"/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- نمودار قیمت -->
|
|
|
|
|
|
<PriceChart @updateData="updateChartData" :price-chart-series="priceChartSeries"/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- آمار بالا و پایین -->
|
|
|
|
|
|
<PriceStats :price="price"/>
|
2026-01-18 13:01:46 +03:30
|
|
|
|
</div>
|
2026-05-14 13:44:43 +03:30
|
|
|
|
|
|
|
|
|
|
<!-- اسکلت لودینگ -->
|
|
|
|
|
|
<HomeSkeleton v-if="loading" class="w-full"/>
|
2026-01-18 13:01:46 +03:30
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
<!-- هدر -->
|
|
|
|
|
|
<AppHeader @logout="showLogoutConfirm = true"/>
|
2026-01-18 13:01:46 +03:30
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
<!-- دیالوگ خروج -->
|
|
|
|
|
|
<LogoutConfirmDialog v-model:show="showLogoutConfirm" @confirm="logout"/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- شیت موجودی -->
|
|
|
|
|
|
<BalanceSheet v-model:show="wholeBalanceVisible" :walletInfo="walletStore.walletInfo" :goldVal="goldVal"/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- مودالها -->
|
|
|
|
|
|
<BasicModal v-model:visible="showTextBanner" :custom-footer="true" destroyOnClose>
|
|
|
|
|
|
<div class="max-h-[54vh] ql-editor" v-html="TextBanner"></div>
|
|
|
|
|
|
</BasicModal>
|
|
|
|
|
|
|
|
|
|
|
|
<ShareModal v-model:visible="showShare" :referralId="userStore.userInfo?.referral_id"/>
|
2026-01-18 13:01:46 +03:30
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script lang="tsx" setup>
|
2026-05-14 13:44:43 +03:30
|
|
|
|
import {computed, onMounted, onUnmounted, ref} from 'vue'
|
2026-01-18 13:01:46 +03:30
|
|
|
|
import router from '@/router'
|
2026-05-14 13:44:43 +03:30
|
|
|
|
import {useWindowScroll} from '@vueuse/core'
|
2026-05-09 16:52:43 +03:30
|
|
|
|
import {loading, removeToken} from '@/utils'
|
|
|
|
|
|
import {useUserStore} from '@/store/userStore'
|
|
|
|
|
|
import {useWalletStore} from '@/store/walletStore'
|
2026-05-14 13:44:43 +03:30
|
|
|
|
import {useConfigStore} from '@/store/configStore'
|
2026-05-09 16:52:43 +03:30
|
|
|
|
import {useFundUserStore} from '@/store/fundStore'
|
2026-05-14 13:44:43 +03:30
|
|
|
|
import {usePrice, usePriceWithoutType} from '../../../utils/usePrice'
|
|
|
|
|
|
import {getLastPrices, getUpPrice, lastPrice, price, setIntervalGetAllPrice, stopPriceInterval} from '@/utils/price'
|
2026-05-09 16:52:43 +03:30
|
|
|
|
import {getConstByKey} from '@/api/const'
|
2026-05-14 13:44:43 +03:30
|
|
|
|
import {message, Modal} from 'ant-design-vue'
|
2026-02-21 20:10:59 +03:30
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
// Components
|
|
|
|
|
|
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
|
|
|
|
|
import HomeSkeleton from '@/views/base/home/components/HomeSkeleton.vue'
|
|
|
|
|
|
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
|
|
|
|
|
import AssetItem from './components/AssetItem.vue'
|
|
|
|
|
|
import ActionButton from './components/ActionButton.vue'
|
|
|
|
|
|
import ReferralSection from './components/ReferralSection.vue'
|
|
|
|
|
|
import AssetsSection from './components/AssetsSection.vue'
|
|
|
|
|
|
import MarketClosedMessage from './components/MarketClosedMessage.vue'
|
|
|
|
|
|
import CurrentPrice from './components/CurrentPrice.vue'
|
|
|
|
|
|
import BannerSlider from './components/BannerSlider.vue'
|
|
|
|
|
|
import PriceChart from './components/PriceChart.vue'
|
|
|
|
|
|
import PriceStats from './components/PriceStats.vue'
|
|
|
|
|
|
import AppHeader from './components/AppHeader.vue'
|
|
|
|
|
|
import LogoutConfirmDialog from './components/LogoutConfirmDialog.vue'
|
|
|
|
|
|
import BalanceSheet from './components/BalanceSheet.vue'
|
|
|
|
|
|
import ShareModal from './components/ShareModal.vue'
|
|
|
|
|
|
|
|
|
|
|
|
// Composables
|
|
|
|
|
|
import {useBanners} from './composables/useBanners'
|
|
|
|
|
|
import {usePriceChart} from './composables/usePriceChart'
|
|
|
|
|
|
import {useUserFunds} from './composables/useUserFunds'
|
|
|
|
|
|
|
|
|
|
|
|
// Stores
|
2026-01-18 13:01:46 +03:30
|
|
|
|
const userStore = useUserStore()
|
|
|
|
|
|
const walletStore = useWalletStore()
|
2026-05-14 13:44:43 +03:30
|
|
|
|
const configStore = useConfigStore()
|
2026-01-18 13:01:46 +03:30
|
|
|
|
const fundStore = useFundUserStore()
|
2026-05-09 16:52:43 +03:30
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
// Config
|
|
|
|
|
|
const isGaroosi = computed(() => configStore.config.name === 'garoosi')
|
|
|
|
|
|
const closedMessage = computed(() => userStore.getValueByKey('closed_message'))
|
|
|
|
|
|
const showClosedMessage = computed(() =>
|
|
|
|
|
|
closedMessage.value &&
|
|
|
|
|
|
lastPrice?.value?.price_last === 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// State
|
|
|
|
|
|
const showLogoutConfirm = ref(false)
|
|
|
|
|
|
const wholeBalanceVisible = ref(false)
|
|
|
|
|
|
const showTextBanner = ref(false)
|
|
|
|
|
|
const showShare = ref(false)
|
|
|
|
|
|
const TextBanner = ref('')
|
|
|
|
|
|
const odometerKey = ref(0)
|
|
|
|
|
|
const {x, y} = useWindowScroll()
|
|
|
|
|
|
|
|
|
|
|
|
// Composables
|
|
|
|
|
|
const {banners, loadBanners} = useBanners()
|
|
|
|
|
|
const {updateChartData, priceChartSeries, fetchPrices} = usePriceChart()
|
|
|
|
|
|
const {funds, loadFunds} = useUserFunds()
|
|
|
|
|
|
|
|
|
|
|
|
// Computed
|
|
|
|
|
|
const limitedPrice = computed(() => walletStore.limitedPrice?.[0])
|
|
|
|
|
|
const goldVal = computed(() => {
|
|
|
|
|
|
return lastPrice.value?.price_last ?? 1
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Actions
|
|
|
|
|
|
const mainActions = computed(() => [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'buySell',
|
|
|
|
|
|
icon: 'vuesax-linear:money-receive',
|
|
|
|
|
|
label: 'خرید و فروش',
|
|
|
|
|
|
handler: () => router.push({name: 'buyProduct'})
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'deposit',
|
|
|
|
|
|
icon: 'vuesax-linear:card-add',
|
|
|
|
|
|
label: isGaroosi.value ? 'واریز و برداشت' : 'واریز نقدی',
|
|
|
|
|
|
handler: () => router.push({name: 'wallet', query: {state: 'deposit'}})
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'balance',
|
|
|
|
|
|
icon: 'vuesax-linear:receipt-item',
|
|
|
|
|
|
label: 'موجودی',
|
|
|
|
|
|
handler: () => wholeBalanceVisible.value = true
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'assets',
|
|
|
|
|
|
icon: 'vuesax-linear:cup',
|
|
|
|
|
|
label: isGaroosi.value ? 'دعوت از دوستان' : 'دارایی ها',
|
|
|
|
|
|
handler: () => isGaroosi.value ? shareCode() : router.push({name: 'fund'})
|
|
|
|
|
|
}
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
// Methods
|
|
|
|
|
|
async function shareCode() {
|
|
|
|
|
|
const text = `⭐️الان طلا بخر؛ آخر ماه سودشو ببر!
|
2026-05-09 16:52:43 +03:30
|
|
|
|
با خرید طلای آبشده در مقدارهای کم ولی مستمر، سود بیشتری ببر!
|
|
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
این دعوت نامه از طرف "${userStore.userInfo?.name}" عزیز برای شما ارسال شده تا شما هم از بازار طلای ${configStore.config.name} جا نمونید.
|
2026-05-09 16:52:43 +03:30
|
|
|
|
روی لینک زیر کلیک کنید و ثبت نام خود را تکمیل کنید.
|
|
|
|
|
|
|
|
|
|
|
|
${window.location.hostname}/login?id=${userStore.userInfo?.referral_id}`
|
2026-05-14 13:44:43 +03:30
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
await navigator.share({title: configStore.config.name, text})
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
copyCode()
|
|
|
|
|
|
}
|
2026-05-09 16:52:43 +03:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function copyCode() {
|
2026-05-14 13:44:43 +03:30
|
|
|
|
const code = userStore.userInfo?.referral_id
|
|
|
|
|
|
if (code) {
|
|
|
|
|
|
navigator.clipboard.writeText(code)
|
|
|
|
|
|
message.info('کد رونوشت شد')
|
2026-01-18 13:01:46 +03:30
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
async function logout() {
|
|
|
|
|
|
userStore.userInfo = undefined
|
|
|
|
|
|
walletStore.walletInfo = undefined
|
|
|
|
|
|
removeToken()
|
|
|
|
|
|
await router.push({name: 'login'})
|
|
|
|
|
|
window.location.reload()
|
|
|
|
|
|
}
|
2026-05-09 16:52:43 +03:30
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
function openGoldModal() {
|
|
|
|
|
|
const goldAmount = (walletStore.walletInfo?.gold ?? 0).toFixed(3)
|
|
|
|
|
|
const walletsAmount = (walletStore.walletInfo?.count_gold_wallets ?? 0).toFixed(3)
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: `مجموع کل وزن طلای آبشده (${goldAmount}) + ارزش دارایی ها (${walletsAmount}) گرم`,
|
|
|
|
|
|
okText: 'متوجه شدم',
|
|
|
|
|
|
centered: true,
|
|
|
|
|
|
cancelButtonProps: {style: {display: 'none'}}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-05-09 16:52:43 +03:30
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
function openRialModal() {
|
|
|
|
|
|
const cashWallet = usePrice(walletStore?.walletInfo?.count_cash_wallet ?? 0)
|
|
|
|
|
|
const cashWallets = usePrice(walletStore?.walletInfo?.count_cash_wallets ?? 0)
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: `مجموع کیف پول ریالی (${cashWallet}) + معادل ریالی محصولات (${cashWallets}) ریال`,
|
|
|
|
|
|
okText: 'متوجه شدم',
|
|
|
|
|
|
centered: true,
|
|
|
|
|
|
cancelButtonProps: {style: {display: 'none'}}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-05-09 16:52:43 +03:30
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
function handleBannerClick(banner) {
|
|
|
|
|
|
const handlers = {
|
|
|
|
|
|
share: () => showShare.value = true,
|
|
|
|
|
|
modal: () => {
|
|
|
|
|
|
if (banner.modalText) {
|
|
|
|
|
|
TextBanner.value = banner.modalText
|
|
|
|
|
|
showTextBanner.value = true
|
2026-05-09 16:52:43 +03:30
|
|
|
|
}
|
2026-05-14 13:44:43 +03:30
|
|
|
|
},
|
|
|
|
|
|
link: () => {
|
|
|
|
|
|
if (banner.link) {
|
|
|
|
|
|
if (banner.link.startsWith('http')) {
|
|
|
|
|
|
window.open(banner.link, '_blank')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
router.push(banner.link)
|
2026-01-18 13:01:46 +03:30
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-14 13:44:43 +03:30
|
|
|
|
handlers[banner.typeClick]?.()
|
2026-01-18 13:01:46 +03:30
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-14 13:44:43 +03:30
|
|
|
|
// Lifecycle
|
2026-01-18 13:01:46 +03:30
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
loading.value = true
|
2026-05-14 13:44:43 +03:30
|
|
|
|
await Promise.all([
|
|
|
|
|
|
loadFunds(),
|
|
|
|
|
|
getLastPrices(),
|
|
|
|
|
|
getUpPrice(),
|
|
|
|
|
|
fetchPrices(),
|
|
|
|
|
|
setIntervalGetAllPrice(),
|
|
|
|
|
|
loadBanners()
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
// شروع آپدیت قیمت
|
|
|
|
|
|
const updateInterval = setInterval(() => {
|
|
|
|
|
|
odometerKey.value++
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
clearInterval(updateInterval)
|
|
|
|
|
|
stopPriceInterval()
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Initialization error:', error)
|
2026-01-18 13:01:46 +03:30
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="less">
|
|
|
|
|
|
.odometer {
|
|
|
|
|
|
font-size: 60px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
animation-duration: 3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
label:focus-within {
|
2026-05-14 13:44:43 +03:30
|
|
|
|
box-shadow: none !important;
|
2026-01-18 13:01:46 +03:30
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-09 16:52:43 +03:30
|
|
|
|
.banner-swiper {
|
|
|
|
|
|
--swiper-pagination-bottom: 0.75rem;
|
|
|
|
|
|
|
|
|
|
|
|
.swiper-pagination-bullet {
|
|
|
|
|
|
width: 0.5rem;
|
|
|
|
|
|
height: 0.5rem;
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.35);
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.swiper-pagination-bullet-active {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-14 13:44:43 +03:30
|
|
|
|
</style>
|