Files
boursecu_admin/src/pages/dashboard/index.vue
T
2026-07-01 22:28:09 +03:30

892 lines
28 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" />
<DashboardTradingIncomeSummary :finance="finance" />
<!-- تراز و آمار — ۴ کارت در یک ردیف -->
<section class="dashboard-metrics-row mt-2">
<DashboardStatCard
tone="green"
icon="vuesax-linear:receipt-2"
title="تعداد سفارش"
subtitle="ثبت‌شده در بازه"
:value="String(finance?.orderCount ?? 0)"
:help="copy.kpi.orderCount"
/>
<DashboardStatCard
v-if="metalBalanceItems.length === 1"
tone="blue"
icon="vuesax-linear:empty-wallet"
:title="metalBalanceTitle(metalBalanceItems[0].metal_id, metalBalanceItems[0].label)"
subtitle="تراز وزن — سفارش موفق"
:value="formatGram(metalBalanceItems[0].goldBalance, metalBalanceItems[0].metal_id)"
:help="copy.kpi.goldBalance"
/>
<DashboardStatCard
v-else
tone="blue"
icon="vuesax-linear:empty-wallet"
:title="metalLabel.goldBalance()"
subtitle="تراز وزن — سفارش موفق"
:value="formatGram(balance?.goldBalance)"
:help="copy.kpi.goldBalance"
/>
<DashboardStatCard
tone="rose"
icon="vuesax-linear:dollar-circle"
title="تراز ریالی"
subtitle="ورود/خروج نقد"
:value="formatDashboardAmount(balance?.cashBalance)"
:unit="DASHBOARD_RIAL_UNIT"
:help="copy.kpi.cashBalance"
/>
<DashboardStatCard
tone="violet"
icon="vuesax-linear:chart-2"
title="تراز مظنه"
subtitle="میانگین موزون"
:value="formatDashboardAmount(balance?.mazanehBalance)"
:unit="DASHBOARD_RIAL_UNIT"
:help="copy.kpi.mazanehBalance"
/>
</section>
<!-- بازه گزارش -->
<section class="dashboard-panel mt-2">
<DashboardSectionHeader title="بازه گزارش" :help="copy.dateRange" />
<div class="dashboard-metrics-row mb-2">
<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) + (finance?.GiftsPrise ?? 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>
<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">
{{ usePrice(order.service_charge_price ?? 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 DashboardTradingIncomeSummary from '@/pages/dashboard/components/DashboardTradingIncomeSummary.vue'
import {
dashboardCharts,
dashboardCustomerMetrics,
dashboardCustomers,
dashboardDateMetrics,
dashboardDateRange,
dashboardGateway,
dashboardHero,
dashboardKpi,
dashboardOrders,
dashboardWallet,
dashboardWalletMetrics,
} from '@/pages/dashboard/dashboardSectionCopy'
import { DASHBOARD_RIAL_UNIT, formatDashboardAmount } from '@/pages/dashboard/dashboardFormat'
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 tradingProfitTotal = computed(() => {
const spread = Number(finance.value?.fullPriceSood ?? 0)
const commission = Number(finance.value?.fullPriceKarmozd ?? finance.value?.fullPriceKaermozd ?? 0)
return Number(finance.value?.totalTradingProfit ?? spread + commission)
})
const {
quickActionLoading,
hasProductSnapshot,
productSnapshotCount,
loadSnapshotStatus,
deactivateAll,
restoreProducts,
closeAllBuy,
closeAllSell,
syncShow,
syncPrices,
} = useDashboardQuickActions(refreshAll)
const showQuickWallet = ref(false)
void loadSnapshotStatus()
const dateRangeMetrics = computed(() => [
{
label: 'واریز بانکی',
value: `${formatDashboardAmount(balance.value?.income_money)} ${DASHBOARD_RIAL_UNIT}`,
help: dashboardDateMetrics.bankDeposit,
},
{
label: 'جمع سود معاملات',
value: `${formatDashboardAmount(tradingProfitTotal.value)} ${DASHBOARD_RIAL_UNIT}`,
help: dashboardDateMetrics.totalTradingProfit,
},
{
label: 'تراز قیمت−پرداخت (پس از هدیه)',
value: `${formatDashboardAmount(finance.value?.sumAll)} ${DASHBOARD_RIAL_UNIT}`,
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: `${formatDashboardAmount(walletSums.value?.cash)} ${DASHBOARD_RIAL_UNIT}`,
help: dashboardWalletMetrics.cash,
variant: 'sky',
},
{
label: metalLabel.goldValueInRial(),
value: `${formatDashboardAmount(walletSums.value?.goldToCash)} ${DASHBOARD_RIAL_UNIT}`,
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-metrics-row {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 0.5rem;
}
@media (max-width: 1024px) {
.dashboard-metrics-row {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 480px) {
.dashboard-metrics-row {
grid-template-columns: 1fr;
}
}
.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);
min-height: 3.75rem;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.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>