313 lines
9.7 KiB
Vue
313 lines
9.7 KiB
Vue
<template>
|
||
<div class="mt-10 p-5">
|
||
<div v-if="userStore.userInfo && !loading">
|
||
<!-- هشدار حداقل مبلغ -->
|
||
<div
|
||
v-if="limitedPrice !== undefined && userStore?.userInfo.trade_active !== 1"
|
||
class="text-red text-xs flex gap-1 items-center justify-center mb-2"
|
||
>
|
||
<Icon icon="vuesax-linear:info-circle" size="16"/>
|
||
حداقل مبلغ اولیه برای ثبت سفارش {{ usePriceWithoutType(limitedPrice.value as number ?? 0) }} ریال می باشد.
|
||
</div>
|
||
|
||
<!-- بخش اصلی -->
|
||
<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"/>
|
||
</div>
|
||
|
||
<!-- اسکلت لودینگ -->
|
||
<HomeSkeleton v-if="loading" class="w-full"/>
|
||
</div>
|
||
|
||
<!-- هدر -->
|
||
<AppHeader @logout="showLogoutConfirm = true"/>
|
||
|
||
<!-- دیالوگ خروج -->
|
||
<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"/>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="tsx" setup>
|
||
import {computed, onMounted, onUnmounted, ref} from 'vue'
|
||
import router from '@/router'
|
||
import {useWindowScroll} from '@vueuse/core'
|
||
import {loading, removeToken} from '@/utils'
|
||
import {useUserStore} from '@/store/userStore'
|
||
import {useWalletStore} from '@/store/walletStore'
|
||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||
import {useConfigStore} from '@/store/configStore'
|
||
import {useFundUserStore} from '@/store/fundStore'
|
||
import {usePrice, usePriceWithoutType} from '../../../utils/usePrice'
|
||
import {getLastPrices, lastPrice, price, setIntervalGetAllPrice, stopPriceInterval} from '@/utils/price'
|
||
import {getConstByKey} from '@/api/const'
|
||
import {message, Modal} from 'ant-design-vue'
|
||
|
||
// 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'
|
||
import {getReferralShareText, getReferralShareTitle} from '@/utils/config'
|
||
|
||
// Stores
|
||
const userStore = useUserStore()
|
||
const walletStore = useWalletStore()
|
||
const configStore = useConfigStore()
|
||
const fundStore = useFundUserStore()
|
||
|
||
// 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 = getReferralShareText({
|
||
userName: userStore.userInfo?.name,
|
||
projectName: configStore.config.name,
|
||
referralId: userStore.userInfo?.referral_id,
|
||
})
|
||
|
||
try {
|
||
await navigator.share({
|
||
title: getReferralShareTitle(configStore.config.name),
|
||
text,
|
||
})
|
||
} catch {
|
||
copyCode()
|
||
}
|
||
}
|
||
|
||
function copyCode() {
|
||
const code = userStore.userInfo?.referral_id
|
||
if (code) {
|
||
navigator.clipboard.writeText(code)
|
||
message.info('کد رونوشت شد')
|
||
}
|
||
}
|
||
|
||
async function logout() {
|
||
userStore.userInfo = undefined
|
||
walletStore.walletInfo = undefined
|
||
useWalletAssets().clearWalletAssets()
|
||
removeToken()
|
||
await router.push({name: 'login'})
|
||
window.location.reload()
|
||
}
|
||
|
||
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'}}
|
||
})
|
||
}
|
||
|
||
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'}}
|
||
})
|
||
}
|
||
|
||
function handleBannerClick(banner) {
|
||
const handlers = {
|
||
share: () => showShare.value = true,
|
||
modal: () => {
|
||
if (banner.modalText) {
|
||
TextBanner.value = banner.modalText
|
||
showTextBanner.value = true
|
||
}
|
||
},
|
||
link: () => {
|
||
if (banner.link) {
|
||
if (banner.link.startsWith('http')) {
|
||
window.open(banner.link, '_blank')
|
||
} else {
|
||
router.push(banner.link)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
handlers[banner.typeClick]?.()
|
||
}
|
||
|
||
// Lifecycle
|
||
onMounted(async () => {
|
||
try {
|
||
loading.value = true
|
||
await Promise.all([
|
||
loadFunds(),
|
||
getLastPrices(),
|
||
fetchPrices(),
|
||
setIntervalGetAllPrice(),
|
||
loadBanners()
|
||
])
|
||
|
||
// شروع آپدیت قیمت
|
||
const updateInterval = setInterval(() => {
|
||
odometerKey.value++
|
||
}, 1000)
|
||
|
||
onUnmounted(() => {
|
||
clearInterval(updateInterval)
|
||
stopPriceInterval()
|
||
})
|
||
} catch (error) {
|
||
console.error('Initialization error:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style lang="less">
|
||
.odometer {
|
||
font-size: 60px;
|
||
text-align: center;
|
||
width: 100%;
|
||
animation-duration: 3s;
|
||
}
|
||
|
||
label:focus-within {
|
||
box-shadow: none !important;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
</style> |