Files
boursecu_user/src/views/base/home/components/CurrentPrice.vue
T

221 lines
5.6 KiB
Vue
Raw Normal View History

2026-05-14 13:44:43 +03:30
<template>
2026-06-23 16:02:41 +03:30
<div
class="w-full relative mt-2 rounded-lg py-3 flex flex-col justify-center home_appear_fade_in transition-colors duration-300"
:class="containerClass"
>
<div
v-if="quotePending"
class="flex flex-col items-center gap-2 px-4 py-2"
aria-busy="true"
aria-label="در حال بارگذاری قیمت"
>
<div class="h-3 w-32 rounded boursecu-price-skeleton animate-pulse" />
<div class="h-6 w-48 rounded boursecu-price-skeleton animate-pulse" />
<div class="h-8 w-24 rounded-lg boursecu-price-skeleton animate-pulse" />
</div>
<template v-else-if="displayState !== 'open'">
<div class="status-box status-box--boursecu">
2026-06-28 21:48:48 +03:30
<div class="status-box__icon-wrap">
<Icon
:icon="displayState === 'closed' ? 'vuesax-linear:lock' : 'vuesax-linear:info-circle'"
size="22"
color="#ffffff"
2026-06-28 21:48:48 +03:30
/>
2026-05-14 13:44:43 +03:30
</div>
2026-06-28 21:48:48 +03:30
<div class="status-box__title">{{ statusTitle }}</div>
<div v-if="statusHint" class="status-box__hint">{{ statusHint }}</div>
2026-05-14 13:44:43 +03:30
</div>
2026-06-23 16:02:41 +03:30
</template>
<template v-else>
<div class="price-label price-label--boursecu">
قیمت لحظه‌ای کاتد مس
2026-06-23 16:02:41 +03:30
</div>
<div class="w-full items-center flex justify-center">
<div v-if="price" class="flex gap-1 text-xs items-center">
<div
v-if="percentChange !== 0"
class="price-change-badge"
:class="percentChange > 0 ? 'price-change-badge--up' : 'price-change-badge--down'"
>
<Icon
:key="displayGoldVal"
:size="15"
:icon="percentChange > 0 ? 'vuesax-linear:send' : 'vuesax-linear:received'"
:color="percentChange > 0 ? 'green-600' : 'red-600'"
/>
<span class="price-change-badge__value">{{ formatSignedPercentChange(percentChange) }}</span>
</div>
<span
class="o-text !text-xl font-bold price-odometer--boursecu"
2026-06-29 11:20:02 +02:00
style="direction: ltr"
>{{ usePriceWithoutType(displayGoldVal) }}</span>
<span class="price-unit--boursecu">ریال</span>
2026-06-23 16:02:41 +03:30
</div>
</div>
</template>
2026-05-14 13:44:43 +03:30
</div>
</template>
<script setup lang="ts">
2026-06-16 19:47:59 +03:30
import { computed } from 'vue'
2026-05-14 13:44:43 +03:30
import Icon from '@/components/BasicPacks/BasicIcon.vue'
2026-06-23 16:02:41 +03:30
import { useUserStore } from '@/store/userStore'
2026-06-06 15:48:27 +03:30
import { getTradeBuyPrice, lastPrice, percentPriceChanged, price } from '@/utils/price'
2026-06-28 21:48:48 +03:30
import {
NO_QUOTE_MESSAGE,
STORE_CLOSED_TITLE,
2026-06-28 21:48:48 +03:30
getPriceDisplayState,
getStoreClosedHint,
isHomeQuotePending,
2026-06-28 21:48:48 +03:30
} from '@/utils/storeHours'
import { formatSignedPercentChange, usePriceWithoutType } from '@/utils/usePrice'
2026-05-14 13:44:43 +03:30
2026-06-23 16:02:41 +03:30
const userStore = useUserStore()
2026-06-28 21:48:48 +03:30
const displayState = computed(() => getPriceDisplayState())
const quotePending = computed(() => isHomeQuotePending())
2026-06-23 16:02:41 +03:30
2026-06-28 21:48:48 +03:30
const statusTitle = computed(() =>
displayState.value === 'closed' ? STORE_CLOSED_TITLE : NO_QUOTE_MESSAGE
2026-06-28 21:48:48 +03:30
)
const statusHint = computed(() => {
if (displayState.value === 'closed') {
return getStoreClosedHint(userStore.getValueByKey('closed_message'))
2026-06-23 16:02:41 +03:30
}
2026-06-28 21:48:48 +03:30
return 'در حال حاضر مظنه‌ای برای نمایش وجود ندارد.'
2026-06-23 16:02:41 +03:30
})
const containerClass = computed(() => {
if (quotePending.value) {
return 'boursecu-price-box boursecu-price-box--open'
}
2026-06-28 21:48:48 +03:30
if (displayState.value !== 'open') {
2026-06-23 16:02:41 +03:30
return 'boursecu-price-box boursecu-price-box--closed'
}
return 'boursecu-price-box boursecu-price-box--open'
})
2026-05-14 13:44:43 +03:30
const percentChange = computed(() => {
2026-06-06 15:48:27 +03:30
if (!getTradeBuyPrice(lastPrice.value)) return 0
2026-05-14 13:44:43 +03:30
return percentPriceChanged()
})
const displayGoldVal = computed(() => {
2026-06-28 21:48:48 +03:30
if (displayState.value !== 'open') return 0
2026-06-06 15:48:27 +03:30
return getTradeBuyPrice(lastPrice.value)
2026-05-14 13:44:43 +03:30
})
2026-06-23 16:02:41 +03:30
void price
2026-06-16 19:47:59 +03:30
</script>
2026-05-14 13:44:43 +03:30
2026-06-16 19:47:59 +03:30
<style scoped>
2026-06-23 16:02:41 +03:30
.boursecu-price-box {
border: none;
overflow: hidden;
}
.boursecu-price-box--open {
background: linear-gradient(135deg, #c98a4a 0%, #a86528 100%);
box-shadow: 0 4px 14px rgba(168, 101, 40, 0.28);
}
.boursecu-price-box--closed {
background: linear-gradient(135deg, #4a5568 0%, #2d3748 100%);
box-shadow: 0 4px 14px rgba(45, 55, 72, 0.22);
min-height: 88px;
}
.price-label--boursecu {
color: rgba(255, 255, 255, 0.92);
font-size: 12px;
font-weight: 600;
width: 100%;
text-align: center;
}
.price-odometer--boursecu {
color: #ffffff !important;
}
.price-unit--boursecu {
color: rgba(255, 255, 255, 0.85);
font-weight: 500;
}
.boursecu-price-skeleton {
background: rgba(255, 255, 255, 0.25);
}
2026-06-28 21:48:48 +03:30
.status-box {
2026-06-23 16:02:41 +03:30
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
padding: 8px 12px;
text-align: center;
}
2026-06-28 21:48:48 +03:30
.status-box__icon-wrap {
2026-06-23 16:02:41 +03:30
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
margin-bottom: 2px;
}
2026-06-28 21:48:48 +03:30
.status-box__title {
2026-06-23 16:02:41 +03:30
font-size: 15px;
font-weight: 700;
}
2026-06-28 21:48:48 +03:30
.status-box__hint {
2026-06-23 16:02:41 +03:30
font-size: 11px;
line-height: 1.6;
max-width: 280px;
}
2026-06-28 21:48:48 +03:30
.status-box--boursecu .status-box__icon-wrap {
background: rgba(255, 255, 255, 0.12);
}
.status-box--boursecu .status-box__title {
color: #ffffff;
}
.status-box--boursecu .status-box__hint {
color: rgba(255, 255, 255, 0.78);
}
2026-06-16 19:47:59 +03:30
.price-change-badge {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.2rem 0.65rem;
border-radius: 0.5rem;
font-weight: 600;
}
.price-change-badge--up {
background: #dcfce7;
color: #16a34a;
}
.price-change-badge--down {
background: #fee2e2;
color: #dc2626;
}
.price-change-badge__value {
direction: ltr;
unicode-bidi: isolate;
font-variant-numeric: tabular-nums;
letter-spacing: 0.01em;
}
</style>