314 lines
7.8 KiB
Vue
314 lines
7.8 KiB
Vue
<template>
|
||
<section :class="rootClass">
|
||
<header class="portfolio-overview__header">
|
||
<span class="portfolio-overview__eyebrow">کل دارایی شما</span>
|
||
<p class="portfolio-overview__total">
|
||
{{ usePriceWithoutType(totalRial) }}
|
||
<span class="portfolio-overview__unit">ریال</span>
|
||
</p>
|
||
</header>
|
||
|
||
<div
|
||
v-if="hasProfitInsight"
|
||
class="portfolio-overview__profit"
|
||
:class="{
|
||
'portfolio-overview__profit--up': profitTone === 'profit',
|
||
'portfolio-overview__profit--down': profitTone === 'loss',
|
||
}"
|
||
>
|
||
<div class="portfolio-overview__profit-main">
|
||
<span class="portfolio-overview__profit-amount">{{ profitText }}</span>
|
||
<span v-if="profitPercent" class="portfolio-overview__profit-percent">{{ profitPercent }}</span>
|
||
</div>
|
||
<div class="portfolio-overview__profit-label">
|
||
<span class="portfolio-overview__profit-hint">سود/زیان تحققنیافته طلا</span>
|
||
<button
|
||
type="button"
|
||
class="portfolio-overview__profit-info"
|
||
aria-label="اطلاعات بیشتر"
|
||
@click="openProfitInfo"
|
||
>
|
||
<BasicIcon icon="vuesax-linear:info-circle" size="14" color="tertiary" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="portfolio-overview__grid">
|
||
<article class="portfolio-overview__tile">
|
||
<span class="portfolio-overview__tile-label">ارزش طلا</span>
|
||
<strong class="portfolio-overview__tile-value">{{ usePriceWithoutType(metalRial) }} ریال</strong>
|
||
<span v-if="goldWeight > 0" class="portfolio-overview__tile-sub">
|
||
{{ formatWeightAmount(goldWeight) }}{{ weightUnit }}
|
||
</span>
|
||
</article>
|
||
<article class="portfolio-overview__tile">
|
||
<span class="portfolio-overview__tile-label">موجودی نقد</span>
|
||
<strong class="portfolio-overview__tile-value">{{ usePriceWithoutType(cashRial) }} ریال</strong>
|
||
<span class="portfolio-overview__tile-sub">کیف پول ریالی</span>
|
||
</article>
|
||
</div>
|
||
|
||
</section>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, h } from 'vue'
|
||
import { Modal } from 'ant-design-vue'
|
||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||
import {
|
||
formatPortfolioProfitInfoText,
|
||
formatPortfolioProfitLabel,
|
||
formatPortfolioProfitPercent,
|
||
formatPortfolioProfitText,
|
||
resolveAssetsRialValue,
|
||
resolveBoursecuCopperUnit,
|
||
} from '@/utils/productAssets'
|
||
import { formatWeightAmount, usePriceWithoutType } from '@/utils/usePrice'
|
||
import { getTradeBuyPrice, lastPrice } from '@/utils/price'
|
||
|
||
const props = withDefaults(
|
||
defineProps<{
|
||
variant?: 'mobile' | 'desktop'
|
||
}>(),
|
||
{ variant: 'mobile' }
|
||
)
|
||
|
||
const { assetsSummary } = useWalletAssets()
|
||
|
||
const portfolio = computed(() => assetsSummary.value?.portfolio)
|
||
const weightUnit = computed(() => resolveBoursecuCopperUnit(assetsSummary.value?.meta?.weight_unit))
|
||
|
||
const totalRial = computed(() =>
|
||
Number(portfolio.value?.total_rial_value ?? assetsSummary.value?.total_rial_value ?? 0)
|
||
)
|
||
const cashRial = computed(() =>
|
||
Number(portfolio.value?.cash_rial ?? assetsSummary.value?.cash_wallet ?? 0)
|
||
)
|
||
const metalRial = computed(() => {
|
||
const fromPortfolio = Number(portfolio.value?.metal_rial_value ?? 0)
|
||
if (fromPortfolio > 0) return fromPortfolio
|
||
return resolveAssetsRialValue(assetsSummary.value, getTradeBuyPrice(lastPrice.value))
|
||
})
|
||
const goldWeight = computed(() => Number(portfolio.value?.gold_weight ?? 0))
|
||
|
||
const hasProfitInsight = computed(() => portfolio.value?.unrealized_profit_rial != null)
|
||
const profitTone = computed(() => formatPortfolioProfitLabel(portfolio.value?.unrealized_profit_rial))
|
||
const profitText = computed(() => formatPortfolioProfitText(portfolio.value?.unrealized_profit_rial))
|
||
const profitPercent = computed(() =>
|
||
formatPortfolioProfitPercent(portfolio.value?.unrealized_profit_percent)
|
||
)
|
||
|
||
function renderModalLines(text: string) {
|
||
return h(
|
||
'div',
|
||
{ style: { lineHeight: '1.9' } },
|
||
text.split('\n').map((line, index) =>
|
||
h(
|
||
'div',
|
||
{ key: index, style: index > 0 ? { marginTop: '6px' } : undefined },
|
||
line
|
||
)
|
||
)
|
||
)
|
||
}
|
||
|
||
function openProfitInfo() {
|
||
const p = portfolio.value
|
||
if (!p) return
|
||
|
||
Modal.confirm({
|
||
title: 'سود/زیان تحققنیافته طلا',
|
||
content: renderModalLines(formatPortfolioProfitInfoText(p, weightUnit.value)),
|
||
okText: 'متوجه شدم',
|
||
centered: true,
|
||
cancelButtonProps: { style: { display: 'none' } },
|
||
})
|
||
}
|
||
|
||
const rootClass = computed(() => [
|
||
'portfolio-overview',
|
||
`portfolio-overview--${props.variant}`,
|
||
])
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.portfolio-overview {
|
||
border-radius: 14px;
|
||
padding: 14px 16px;
|
||
background: linear-gradient(145deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.06));
|
||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||
color: #fff;
|
||
}
|
||
|
||
.portfolio-overview--desktop {
|
||
margin-bottom: 16px;
|
||
padding: 20px 22px;
|
||
background: #fff;
|
||
border: 1px solid rgba(15, 23, 42, 0.06);
|
||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||
color: #111827;
|
||
}
|
||
|
||
.portfolio-overview__header {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.portfolio-overview__eyebrow {
|
||
display: block;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__eyebrow {
|
||
color: #6b7280;
|
||
opacity: 1;
|
||
}
|
||
|
||
.portfolio-overview__total {
|
||
margin: 4px 0 0;
|
||
font-size: 2rem;
|
||
// font-weight: 800;
|
||
line-height: 1.2;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
|
||
.portfolio-overview__unit {
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
margin-right: 4px;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.portfolio-overview__profit {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
padding: 10px 12px;
|
||
border-radius: 12px;
|
||
margin-bottom: 12px;
|
||
background: rgba(255, 255, 255, 0.12);
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.portfolio-overview__profit-main {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.portfolio-overview__profit-label {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.portfolio-overview__profit-info {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 0;
|
||
margin: 0;
|
||
border: none;
|
||
background: transparent;
|
||
cursor: pointer;
|
||
line-height: 0;
|
||
opacity: 0.85;
|
||
|
||
&:hover {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__profit {
|
||
background: #f9fafb;
|
||
}
|
||
|
||
.portfolio-overview__profit--up {
|
||
color: #bbf7d0;
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__profit--up {
|
||
color: #027a48;
|
||
background: #ecfdf3;
|
||
}
|
||
|
||
.portfolio-overview__profit--down {
|
||
color: #fecaca;
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__profit--down {
|
||
color: #b42318;
|
||
background: #fef3f2;
|
||
}
|
||
|
||
.portfolio-overview__profit-percent {
|
||
direction: ltr;
|
||
unicode-bidi: isolate;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.portfolio-overview__profit-hint {
|
||
width: 100%;
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__profit-hint {
|
||
color: #6b7280;
|
||
opacity: 1;
|
||
}
|
||
|
||
.portfolio-overview__grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 10px;
|
||
}
|
||
|
||
.portfolio-overview__tile {
|
||
padding: 10px 12px;
|
||
border-radius: 10px;
|
||
background: rgba(0, 0, 0, 0.12);
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__tile {
|
||
background: #f6f7f9;
|
||
}
|
||
|
||
.portfolio-overview__tile-label {
|
||
display: block;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
opacity: 0.85;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__tile-label {
|
||
color: #6b7280;
|
||
opacity: 1;
|
||
}
|
||
|
||
.portfolio-overview__tile-value {
|
||
display: block;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
line-height: 1.35;
|
||
}
|
||
|
||
.portfolio-overview__tile-sub {
|
||
display: block;
|
||
margin-top: 4px;
|
||
font-size: 11px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.portfolio-overview--desktop .portfolio-overview__tile-sub {
|
||
color: #9ca3af;
|
||
opacity: 1;
|
||
}
|
||
</style>
|