Files
boursecu_user/src/views/base/home/index.vue
T

310 lines
9.9 KiB
Vue
Raw Normal View History

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>