Files
boursecu_admin/src/pages/dashboard/index.vue
T
2026-06-23 22:31:07 +03:30

861 lines
26 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="dashboard-v2 box-border min-h-full w-full max-w-full overflow-x-hidden p-2 md:p-3">
<a-spin :spinning="loading">
<!-- Hero -->
<section
class="dashboard-hero rounded-xl bg-gradient-to-l from-[#0f766e] via-[#1e3a5f] to-[#0f172a] px-3 py-2.5 text-white shadow-md"
>
<div class="flex flex-col gap-2.5 md:flex-row md:items-center md:justify-between md:gap-3">
<div class="order-2 min-w-0 md:order-1">
<div class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5">
<DashboardLabelWithHelp
label="مظنه"
:help="copy.hero"
size="xs"
text-class="text-[11px]"
label-class="text-white/80"
/>
<span class="text-[11px] text-white/80">/گرم</span>
<span class="text-lg font-bold leading-none">{{ usePrice(master?.price ?? 0, true, '') }}</span>
<span class="text-white/35">·</span>
<span class="text-[11px] text-white/80">مثقال</span>
<span class="text-sm font-semibold leading-none">{{ usePrice(master?.pricem ?? 0, true, '') }}</span>
</div>
<p v-if="master?.update_date" class="mt-1 text-[10px] leading-none text-white/55">
{{ toJalali(master.update_date) }}
</p>
</div>
<div class="order-1 w-full shrink-0 md:order-2 md:w-auto">
<DashboardQuickActionsBar
:quick-action-loading="quickActionLoading"
:has-product-snapshot="hasProductSnapshot"
:product-snapshot-count="productSnapshotCount"
@wallet="showQuickWallet = true"
@deactivate-all="deactivateAll"
@restore-products="restoreProducts"
@close-all-buy="closeAllBuy"
@close-all-sell="closeAllSell"
@sync-prices="syncPrices"
@sync-show="syncShow"
/>
</div>
</div>
</section>
<DashboardQuickWalletModal v-model:visible="showQuickWallet" />
<!-- KPI -->
<section class="mt-2 grid grid-cols-2 items-stretch gap-2 md:grid-cols-3 xl:grid-cols-6">
<DashboardStatCard
tone="gold"
icon="vuesax-linear:money-receive"
title="سود معاملات"
:value="usePrice(finance?.fullPriceSood ?? 0, true, '')"
:help="copy.kpi.profit"
/>
<DashboardStatCard
tone="amber"
icon="vuesax-linear:coin"
:title="metalLabel.goldCommission()"
:value="usePrice(finance?.fullPriceKarmozd ?? finance?.fullPriceKaermozd ?? 0, true, '')"
:help="copy.kpi.commission"
/>
<DashboardStatCard
tone="green"
icon="vuesax-linear:receipt-2"
title="تعداد سفارش"
:value="String(finance?.orderCount ?? 0)"
:help="copy.kpi.orderCount"
/>
<template v-if="metalBalanceItems.length">
<DashboardStatCard
v-for="item in metalBalanceItems"
:key="item.metal_id"
tone="blue"
icon="vuesax-linear:empty-wallet"
:title="metalBalanceTitle(item.metal_id, item.label)"
:value="formatGram(item.goldBalance, item.metal_id)"
:help="copy.kpi.goldBalance"
/>
</template>
<DashboardStatCard
v-else
tone="blue"
icon="vuesax-linear:empty-wallet"
:title="metalLabel.goldBalance()"
:value="formatGram(balance?.goldBalance)"
:help="copy.kpi.goldBalance"
/>
<DashboardStatCard
tone="rose"
icon="vuesax-linear:dollar-circle"
title="تراز ریالی"
:value="usePrice(balance?.cashBalance ?? 0, true, '')"
:help="copy.kpi.cashBalance"
/>
<DashboardStatCard
tone="violet"
icon="vuesax-linear:chart-2"
title="تراز مظنه"
:value="usePrice(balance?.mazanehBalance ?? 0, true, '')"
:help="copy.kpi.mazanehBalance"
/>
</section>
<!-- Date filter -->
<section class="dashboard-panel mt-2">
<DashboardSectionHeader title="بازه گزارش" :help="copy.dateRange" />
<div class="mb-2 grid grid-cols-1 gap-2 sm:grid-cols-3">
<div
v-for="metric in dateRangeMetrics"
:key="metric.label"
class="dashboard-inline-metric rounded-lg px-2.5 py-2"
>
<DashboardLabelWithHelp
:label="metric.label"
:help="metric.help"
size="xs"
text-class="text-[10px]"
label-class="dashboard-text-muted"
/>
<p class="dashboard-text text-sm font-bold">{{ metric.value }}</p>
</div>
</div>
<div class="flex flex-wrap items-center gap-2">
<BaseDatePicker
v-model:value="startDate"
format="YYYY-MM-DD HH:mm:ss"
class="!w-44"
size="small"
/>
<span class="dashboard-text-muted text-xs">تا</span>
<BaseDatePicker
v-model:value="endDate"
format="YYYY-MM-DD HH:mm:ss"
class="!w-44"
size="small"
/>
<div class="flex items-center gap-2">
<a-button type="primary" size="small" @click="applyDateRange">اعمال</a-button>
<a-button size="small" @click="refreshAll">بروزرسانی</a-button>
</div>
</div>
</section>
<!-- Charts row 1 -->
<section class="mt-2 grid grid-cols-1 gap-2 xl:grid-cols-2">
<div class="dashboard-panel">
<DashboardSectionHeader title="ترکیب درآمد" :help="copy.charts.incomeMix" />
<div class="dashboard-chart-wrap">
<apexchart
v-if="(finance?.fullPriceSood ?? 0) + (finance?.fullPriceKarmozd ?? 0) > 0"
type="donut"
height="220"
:options="financeChartOptions"
:series="financeChartOptions.series"
/>
<div
v-else
class="dashboard-empty flex h-44 items-center justify-center text-xs"
>
در این بازه داده مالی ثبت نشده
</div>
</div>
</div>
<div class="dashboard-panel">
<div class="flex items-start justify-between gap-2">
<DashboardSectionHeader
class="!mb-0 min-w-0 flex-1"
title="حجم خرید و فروش"
:help="copy.charts.buySellVolume"
/>
<a-radio-group
v-model:value="flowRange"
button-style="solid"
size="small"
class="shrink-0"
>
<a-radio-button value="week">۷ روز</a-radio-button>
<a-radio-button value="month">۳۰ روز</a-radio-button>
</a-radio-group>
</div>
<a-spin :spinning="flowLoading">
<apexchart
v-if="flowData.length"
type="bar"
:height="flowChartHeight"
:options="flowChartOptions"
:series="flowChartOptions.series"
/>
<div
v-else
class="dashboard-empty flex h-44 items-center justify-center text-xs"
>
داده‌ای برای نمودار نیست
</div>
</a-spin>
</div>
</section>
<!-- Price chart -->
<section class="dashboard-panel mt-2">
<div class="mb-3 flex flex-wrap items-start justify-between gap-2">
<DashboardSectionHeader
class="!mb-0 min-w-0 flex-1"
title="نمودار مظنه"
:help="copy.charts.priceChart"
/>
<a-radio-group
v-model:value="priceRange"
button-style="solid"
size="small"
class="dashboard-price-range shrink-0"
>
<a-radio-button value="DAILY">24 ساعت اخیر</a-radio-button>
<a-radio-button value="WEEKLY">هفته گذشته</a-radio-button>
<a-radio-button value="MONTHLY">ماه گذشته</a-radio-button>
</a-radio-group>
</div>
<apexchart
v-if="priceSeries.length"
:key="priceRange"
type="area"
height="200"
:options="priceChartOptions"
:series="priceChartOptions.series"
/>
<div
v-else
class="flex h-40 items-center justify-center text-xs dashboard-empty"
>
داده نمودار قیمت در دسترس نیست
</div>
</section>
<!-- Orders + side charts -->
<section class="mt-2 grid grid-cols-1 gap-2 xl:grid-cols-3">
<div class="flex flex-col gap-2 xl:col-span-1">
<div class="dashboard-panel">
<div class="mb-2 flex items-start justify-between gap-2">
<DashboardSectionHeader
class="!mb-0 min-w-0 flex-1"
title="ساعات شلوغ سفارش"
:help="copy.orders.peakHours"
/>
<a-radio-group
v-model:value="peakHoursRange"
button-style="solid"
size="small"
class="shrink-0"
>
<a-radio-button :value="7">۷ روز</a-radio-button>
<a-radio-button :value="30">۳۰ روز</a-radio-button>
</a-radio-group>
</div>
<div
v-if="peakHoursData?.peak_hour != null && peakHoursData.peak_count > 0"
class="mb-3 flex flex-wrap items-center gap-1.5"
>
<span class="dashboard-peak-badge dashboard-peak-badge--primary inline-flex items-center rounded-full px-2.5 py-1 text-[11px] font-semibold">
شلوغ‌ترین: {{ formatPeakHourLabel(peakHoursData.peak_hour) }}
<span class="mr-1 font-normal opacity-75">({{ peakHoursData.peak_count }} سفارش)</span>
</span>
<span
v-for="slot in topPeakHours.slice(1)"
:key="slot.hour"
class="dashboard-peak-badge dashboard-peak-badge--muted inline-flex items-center rounded-full px-2 py-0.5 text-[10px]"
>
{{ formatPeakHourLabel(slot.hour) }} · {{ slot.total }}
</span>
</div>
<a-spin :spinning="peakHoursLoading">
<apexchart
v-if="peakHoursData?.total_orders"
type="bar"
:height="peakHoursChartHeight"
:options="peakHoursChartOptions"
:series="peakHoursChartOptions.series"
/>
<div
v-else
class="dashboard-empty flex h-44 items-center justify-center text-xs"
>
در این بازه سفارشی ثبت نشده
</div>
</a-spin>
</div>
<div class="dashboard-panel">
<div class="mb-3 flex flex-wrap items-start justify-between gap-2">
<DashboardSectionHeader
class="!mb-0 min-w-0 flex-1"
title="فعالیت محصولات"
:help="copy.charts.productActivity"
/>
<a-radio-group
v-model:value="productActivityRange"
button-style="solid"
size="small"
class="dashboard-product-range shrink-0"
>
<a-radio-button value="day">روزانه</a-radio-button>
<a-radio-button value="week">هفتگی</a-radio-button>
<a-radio-button value="month">ماهانه</a-radio-button>
<a-radio-button value="year">سالانه</a-radio-button>
</a-radio-group>
</div>
<a-spin :spinning="productActivityLoading">
<div v-if="productReportItems.length" class="dashboard-product-chart min-w-0">
<apexchart
:key="`${productActivityRange}-${productChartHeight}-${productChartLabelWidth}`"
type="bar"
:height="productChartHeight"
:options="productChartOptions"
:series="productChartOptions.series"
/>
</div>
<div
v-else
class="dashboard-empty flex h-44 items-center justify-center text-xs"
>
در این بازه معامله‌ای برای محصولات ثبت نشده
</div>
</a-spin>
</div>
</div>
<div class="dashboard-panel xl:col-span-2">
<div class="mb-2 flex items-start justify-between gap-2">
<DashboardSectionHeader
class="!mb-0 min-w-0 flex-1"
title="آخرین سفارشات"
:help="copy.orders.recent"
/>
<router-link :to="{ name: 'ordersMain' }">
<a-button type="link" class="!px-0">همه سفارشات</a-button>
</router-link>
</div>
<div class="overflow-x-auto">
<table class="dashboard-table w-full min-w-[52rem] text-sm">
<thead>
<tr class="border-b text-xs">
<th class="px-2 py-2 text-right">کد</th>
<th class="px-2 py-2 text-right">نوع</th>
<th class="px-2 py-2 text-right">مشتری</th>
<th class="px-2 py-2 text-right">مقدار</th>
<th class="px-2 py-2 text-right">مظنه/گرم</th>
<th class="px-2 py-2 text-right">قیمت مشتری</th>
<th class="px-2 py-2 text-right">سود/گرم</th>
<th class="px-2 py-2 text-right">سود کل</th>
<th class="px-2 py-2 text-right">وضعیت</th>
<th class="px-2 py-2 text-right">تاریخ</th>
</tr>
</thead>
<tbody>
<tr
v-for="order in recentOrders"
:key="order.id"
class="border-b hover:bg-[var(--admin-bg-hover)]"
>
<td class="px-2 py-2.5 font-medium">#{{ order.id }}</td>
<td class="px-2 py-2.5">
<span class="rounded-md px-2 py-0.5 text-xs" :class="directionClass(order.direction)">
{{ directionLabel(order.direction) }}
</span>
</td>
<td class="max-w-[8rem] truncate px-2 py-2.5">{{ order.customer?.name ?? '—' }}</td>
<td class="px-2 py-2.5">{{ formatGram(order.amount) }}</td>
<td class="px-2 py-2.5">{{ usePrice(order.price_original ?? 0, true, '') }}</td>
<td class="px-2 py-2.5">{{ usePrice(order.price ?? 0, true, '') }}</td>
<td class="dashboard-profit px-2 py-2.5">
{{ usePrice(order.fee ?? 0, true, '') }}
</td>
<td class="dashboard-profit px-2 py-2.5 font-semibold">
{{ usePrice(order.total_fee ?? 0, true, '') }}
</td>
<td class="px-2 py-2.5">
<span class="rounded-md px-2 py-0.5 text-xs" :class="stsClass(order.sts)">
{{ stsLabel(order) }}
</span>
</td>
<td class="dashboard-text-muted whitespace-nowrap px-2 py-2.5 text-xs">
{{ order.created_at ? toJalali(order.created_at) : '—' }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- Bottom row -->
<section class="mt-2 grid grid-cols-1 gap-2 xl:grid-cols-2">
<div class="dashboard-panel">
<DashboardSectionHeader title="مشتریان" :help="copy.customers" />
<div class="grid grid-cols-2 gap-2.5 md:grid-cols-4">
<div
v-for="item in customerMetricItems"
:key="item.label"
class="dashboard-metric-cell"
:class="`dashboard-metric-cell--${item.variant}`"
>
<DashboardLabelWithHelp
:label="item.label"
:help="item.help"
size="xs"
text-class="text-[11px]"
label-class="dashboard-text-muted"
root-class="dashboard-metric-label"
/>
<p class="dashboard-metric-value">{{ item.value }}</p>
</div>
</div>
</div>
<div class="dashboard-panel">
<DashboardSectionHeader title="موجودی کیف پول‌ها" :help="copy.wallet" />
<div class="grid grid-cols-1 gap-2.5 sm:grid-cols-3">
<div
v-for="item in walletMetricItems"
:key="item.label"
class="dashboard-metric-cell"
:class="`dashboard-metric-cell--${item.variant}`"
>
<DashboardLabelWithHelp
:label="item.label"
:help="item.help"
size="xs"
text-class="text-[11px]"
label-class="dashboard-text-muted"
root-class="dashboard-metric-label"
/>
<p class="dashboard-metric-value">{{ item.value }}</p>
</div>
</div>
</div>
</section>
</a-spin>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import DashboardLabelWithHelp from '@/pages/dashboard/components/DashboardLabelWithHelp.vue'
import DashboardQuickActionsBar from '@/pages/dashboard/components/DashboardQuickActionsBar.vue'
import DashboardQuickWalletModal from '@/pages/dashboard/components/DashboardQuickWalletModal.vue'
import DashboardSectionHeader from '@/pages/dashboard/components/DashboardSectionHeader.vue'
import DashboardStatCard from '@/pages/dashboard/components/DashboardStatCard.vue'
import {
dashboardCharts,
dashboardCustomerMetrics,
dashboardCustomers,
dashboardDateMetrics,
dashboardDateRange,
dashboardGateway,
dashboardHero,
dashboardKpi,
dashboardOrders,
dashboardWallet,
dashboardWalletMetrics,
} from '@/pages/dashboard/dashboardSectionCopy'
import { useDashboardPage } from '@/pages/dashboard/composables/useDashboardPage'
import { useDashboardQuickActions } from '@/pages/dashboard/composables/useDashboardQuickActions'
import { metalBalanceTitle, metalLabel } from '@/utils/adminMetalLabels'
const copy = {
hero: dashboardHero,
gateway: dashboardGateway,
kpi: dashboardKpi,
dateRange: dashboardDateRange,
charts: dashboardCharts,
orders: dashboardOrders,
customers: dashboardCustomers,
wallet: dashboardWallet,
}
const {
loading,
flowLoading,
startDate,
endDate,
master,
finance,
balance,
metalBalanceItems,
walletSums,
recentOrders,
peakHoursRange,
peakHoursData,
peakHoursLoading,
topPeakHours,
priceRange,
flowRange,
flowData,
priceSeries,
productActivityRange,
productActivityLoading,
productReportItems,
productChartHeight,
productChartLabelWidth,
refreshAll,
applyDateRange,
loadFlow,
loadProductActivity,
formatGram,
directionLabel,
directionClass,
stsClass,
stsLabel,
financeChartOptions,
flowChartOptions,
flowChartHeight,
peakHoursChartOptions,
peakHoursChartHeight,
formatPeakHourLabel,
priceChartOptions,
productChartOptions,
usePrice,
toJalali,
customerStats,
} = useDashboardPage()
const {
quickActionLoading,
hasProductSnapshot,
productSnapshotCount,
loadSnapshotStatus,
deactivateAll,
restoreProducts,
closeAllBuy,
closeAllSell,
syncShow,
syncPrices,
} = useDashboardQuickActions(refreshAll)
const showQuickWallet = ref(false)
void loadSnapshotStatus()
const dateRangeMetrics = computed(() => [
{
label: 'واریز بانکی',
value: usePrice(balance.value?.income_money ?? 0),
help: dashboardDateMetrics.bankDeposit,
},
{
label: 'درآمد خالص',
value: usePrice(finance.value?.sumAll ?? 0),
help: dashboardDateMetrics.netIncome,
},
{
label: 'هدایا',
value: `${finance.value?.Gifts ?? '0'} گرم`,
help: dashboardDateMetrics.gifts,
},
])
const customerMetricItems = computed(() => [
{
label: 'کل مشتریان',
value: customerStats.value.total,
help: dashboardCustomerMetrics.total,
variant: 'default',
},
{
label: 'جدید (۳ ماه)',
value: customerStats.value.newCount,
help: dashboardCustomerMetrics.new,
variant: 'default',
},
{
label: 'فعال',
value: customerStats.value.active,
help: dashboardCustomerMetrics.active,
variant: 'success',
},
{
label: 'بدون احراز',
value: customerStats.value.notVerified,
help: dashboardCustomerMetrics.notVerified,
variant: 'danger',
},
])
const walletMetricItems = computed(() => [
{
label: metalLabel.customersGold(),
value: formatGram(walletSums.value?.gold),
help: dashboardWalletMetrics.gold,
variant: 'amber',
},
{
label: 'ریال مشتریان',
value: usePrice(walletSums.value?.cash ?? 0, true, ''),
help: dashboardWalletMetrics.cash,
variant: 'sky',
},
{
label: metalLabel.goldValueInRial(),
value: usePrice(walletSums.value?.goldToCash ?? 0, true, ''),
help: dashboardWalletMetrics.goldToCash,
variant: 'violet',
},
])
</script>
<style scoped>
.dashboard-panel {
border-radius: 0.75rem;
border: 1px solid var(--admin-border);
background: var(--admin-bg-elevated);
color: var(--admin-text);
padding: 1rem;
}
.dashboard-text {
color: var(--admin-text);
}
.dashboard-text-muted {
color: var(--admin-text-secondary);
}
.dashboard-empty {
color: var(--admin-text-secondary);
}
.dashboard-inline-metric {
background: var(--admin-bg-muted);
}
.dashboard-profit {
color: #059669;
}
.dashboard-metric-cell {
display: flex;
min-height: 4.75rem;
flex-direction: column;
justify-content: space-between;
border-radius: 0.5rem;
padding: 0.75rem;
background: var(--admin-bg-muted);
color: var(--admin-text);
}
.dashboard-metric-cell--success {
background: rgba(16, 185, 129, 0.12);
border: 1px solid rgba(16, 185, 129, 0.18);
color: #047857;
}
.dashboard-metric-cell--danger {
background: rgba(244, 63, 94, 0.1);
border: 1px solid rgba(244, 63, 94, 0.18);
color: #be123c;
}
.dashboard-metric-cell--amber {
background: rgba(245, 158, 11, 0.12);
border: 1px solid rgba(245, 158, 11, 0.18);
}
.dashboard-metric-cell--sky {
background: rgba(14, 165, 233, 0.12);
border: 1px solid rgba(14, 165, 233, 0.18);
}
.dashboard-metric-cell--violet {
background: rgba(139, 92, 246, 0.12);
border: 1px solid rgba(139, 92, 246, 0.18);
}
.dashboard-peak-badge--primary {
background: rgba(245, 158, 11, 0.14);
color: #b45309;
}
.dashboard-peak-badge--muted {
background: var(--admin-bg-muted);
color: var(--admin-text-muted);
}
.dashboard-table thead tr,
.dashboard-table tbody tr {
border-color: var(--admin-border);
}
.dashboard-table thead tr {
color: var(--admin-text-secondary);
}
.dashboard-table tbody tr {
color: var(--admin-text);
}
.dashboard-badge--buy {
background: rgba(16, 185, 129, 0.14);
color: #047857;
}
.dashboard-badge--sell {
background: rgba(244, 63, 94, 0.14);
color: #be123c;
}
.dashboard-badge--ok {
background: rgba(16, 185, 129, 0.14);
color: #047857;
}
.dashboard-badge--open {
background: rgba(245, 158, 11, 0.14);
color: #b45309;
}
.dashboard-badge--fail {
background: rgba(244, 63, 94, 0.14);
color: #be123c;
}
.dashboard-metric-value {
@apply mt-2 text-base font-bold leading-snug break-words;
}
.dashboard-v2 :deep(.dashboard-metric-label) {
align-items: flex-start;
line-height: 1.4;
}
.dashboard-v2 :deep(.dashboard-metric-label > span:first-child) {
overflow: visible;
text-overflow: unset;
white-space: normal;
line-height: 1.4;
}
.dashboard-chart-wrap {
@apply px-1 pb-1;
}
.dashboard-v2 :deep(.apexcharts-legend) {
padding-inline: 12px !important;
}
.dashboard-v2 :deep(.apexcharts-legend-series) {
margin-inline: 8px !important;
}
.dashboard-v2 :deep(.apexcharts-tooltip) {
direction: rtl;
}
.dashboard-v2 :deep(.dashboard-section-header) {
overflow: visible;
padding-bottom: 2px;
}
.dashboard-v2 :deep(.dashboard-section-title) {
line-height: 1.6;
}
.dashboard-v2 :deep(.dashboard-section-title > span:first-child) {
line-height: 1.6;
overflow: visible;
padding-bottom: 2px;
}
.dashboard-v2 :deep(.dashboard-label-with-help .ant-tooltip-disabled-compatible-wrapper),
.dashboard-v2 :deep(.dashboard-label-with-help .dashboard-help-trigger) {
display: inline-flex !important;
align-items: center !important;
line-height: 1 !important;
vertical-align: baseline !important;
}
.dashboard-product-chart {
@apply min-w-0 px-0.5 md:px-1;
}
.dashboard-product-chart :deep(.apexcharts-yaxis-texts-g text) {
text-anchor: start !important;
direction: rtl;
unicode-bidi: plaintext;
}
.dashboard-product-chart :deep(.apexcharts-yaxis) {
transform: translateX(-2px);
}
</style>
<style lang="less">
html.is-dark {
.dashboard-v2 {
.dashboard-profit {
color: #6ee7b7;
}
.dashboard-metric-cell--success {
background: rgba(16, 185, 129, 0.16);
border-color: rgba(16, 185, 129, 0.28);
color: #6ee7b7;
}
.dashboard-metric-cell--danger {
background: rgba(244, 63, 94, 0.16);
border-color: rgba(244, 63, 94, 0.28);
color: #fda4af;
}
.dashboard-metric-cell--amber {
background: rgba(245, 158, 11, 0.16);
border-color: rgba(245, 158, 11, 0.28);
}
.dashboard-metric-cell--sky {
background: rgba(14, 165, 233, 0.16);
border-color: rgba(14, 165, 233, 0.28);
}
.dashboard-metric-cell--violet {
background: rgba(139, 92, 246, 0.16);
border-color: rgba(139, 92, 246, 0.28);
}
.dashboard-peak-badge--primary {
background: rgba(245, 158, 11, 0.18);
color: #fcd34d;
}
.dashboard-badge--buy {
background: rgba(16, 185, 129, 0.2);
color: #6ee7b7;
}
.dashboard-badge--sell {
background: rgba(244, 63, 94, 0.2);
color: #fda4af;
}
.dashboard-badge--open {
background: rgba(245, 158, 11, 0.2);
color: #fcd34d;
}
.dashboard-badge--fail {
background: rgba(244, 63, 94, 0.2);
color: #fda4af;
}
.dashboard-badge--ok {
background: rgba(16, 185, 129, 0.2);
color: #6ee7b7;
}
}
}
</style>