优化
This commit is contained in:
@@ -14,7 +14,8 @@
|
||||
"Bash(find node_modules/.pnpm -name *.mjs -path *vue-router*)",
|
||||
"Bash(grep -r \"routeMeta\\\\|definePage\\\\|<route\" node_modules/.pnpm/vue-router*/node_modules/vue-router/dist/*.mjs)",
|
||||
"Bash(grep -r \"route block\\\\|customBlock\\\\|defineCustomBlock\" node_modules/.pnpm/vue-router*/dist/*.mjs)",
|
||||
"Bash(find node_modules/.pnpm -path *vue-router* -name *.mjs)"
|
||||
"Bash(find node_modules/.pnpm -path *vue-router* -name *.mjs)",
|
||||
"Bash(pnpm add:*)"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"/Users/sion/Desktop/projects/monisuo/monisuo-admin/.git"
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"dayjs": "^1.11.20",
|
||||
"decimal.js": "^10.6.0",
|
||||
"echarts": "^6.0.0",
|
||||
"embla-carousel-autoplay": "^8.6.0",
|
||||
"embla-carousel-vue": "^8.6.0",
|
||||
|
||||
8
monisuo-admin/pnpm-lock.yaml
generated
8
monisuo-admin/pnpm-lock.yaml
generated
@@ -50,6 +50,9 @@ importers:
|
||||
dayjs:
|
||||
specifier: ^1.11.20
|
||||
version: 1.11.20
|
||||
decimal.js:
|
||||
specifier: ^10.6.0
|
||||
version: 10.6.0
|
||||
echarts:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
@@ -3431,6 +3434,9 @@ packages:
|
||||
decache@4.6.2:
|
||||
resolution: {integrity: sha512-2LPqkLeu8XWHU8qNCS3kcF6sCcb5zIzvWaAHYSvPfwhdd7mHuah29NssMzrTYyHN4F5oFy2ko9OBYxegtU0FEw==}
|
||||
|
||||
decimal.js@10.6.0:
|
||||
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
|
||||
|
||||
decode-named-character-reference@1.3.0:
|
||||
resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
|
||||
|
||||
@@ -10091,6 +10097,8 @@ snapshots:
|
||||
callsite: 1.0.0
|
||||
optional: true
|
||||
|
||||
decimal.js@10.6.0: {}
|
||||
|
||||
decode-named-character-reference@1.3.0:
|
||||
dependencies:
|
||||
character-entities: 2.0.2
|
||||
|
||||
@@ -179,24 +179,24 @@ function formatCurrency(value: number): string {
|
||||
<UiSpinner class="w-8 h-8" />
|
||||
</div>
|
||||
|
||||
<div v-else class="space-y-6">
|
||||
<div v-else class="grid gap-6">
|
||||
<!-- 模块1: 盈利分析 -->
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:dollar-sign" class="size-4" />
|
||||
盈利分析
|
||||
</h2>
|
||||
<div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<div class="grid gap-3 grid-cols-2 sm:grid-cols-4">
|
||||
<UiCard v-for="item in profitMetrics" :key="item.label" class="hover:shadow-sm transition-shadow">
|
||||
<UiCardContent class="pt-6">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<Icon :icon="item.icon" class="size-5" :class="item.color" />
|
||||
<UiCardContent class="p-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<Icon :icon="item.icon" class="size-4" :class="item.color" />
|
||||
<span class="text-xs text-muted-foreground">{{ item.rate }}</span>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
<p class="text-xs text-muted-foreground truncate">
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<p class="text-2xl font-bold font-mono mt-1" :class="item.color">
|
||||
<p class="text-lg sm:text-xl font-bold font-mono mt-1 truncate" :class="item.color">
|
||||
{{ formatCurrency(item.value) }}
|
||||
</p>
|
||||
</UiCardContent>
|
||||
@@ -205,45 +205,47 @@ function formatCurrency(value: number): string {
|
||||
</section>
|
||||
|
||||
<!-- 模块2: 交易分析 -->
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:trending-up" class="size-4" />
|
||||
交易分析
|
||||
</h2>
|
||||
<UiCard>
|
||||
<UiCardContent class="pt-6">
|
||||
<VChart :option="tradeAnalysisOption" autoresize style="height: 280px" />
|
||||
<UiCardContent class="p-4">
|
||||
<VChart :option="tradeAnalysisOption" autoresize style="height: 260px" />
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
</section>
|
||||
|
||||
<!-- 模块3: 币种分布 + 用户分析 -->
|
||||
<div class="grid gap-4 lg:grid-cols-3">
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<div class="grid gap-6 lg:grid-cols-5">
|
||||
<!-- 币种分布 -->
|
||||
<section class="space-y-3 lg:col-span-2">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:pie-chart" class="size-4" />
|
||||
币种交易分布
|
||||
</h2>
|
||||
<UiCard>
|
||||
<UiCardContent class="pt-6">
|
||||
<VChart :option="coinDistributionOption" autoresize style="height: 240px" />
|
||||
<UiCard class="h-[calc(100%-2rem)]">
|
||||
<UiCardContent class="p-4">
|
||||
<VChart :option="coinDistributionOption" autoresize style="height: 220px" />
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
</section>
|
||||
|
||||
<section class="lg:col-span-2">
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<!-- 用户分析 -->
|
||||
<section class="space-y-3 lg:col-span-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:users" class="size-4" />
|
||||
用户分析
|
||||
</h2>
|
||||
<div class="grid gap-4">
|
||||
<div class="grid gap-3 sm:grid-cols-4">
|
||||
<div class="space-y-3">
|
||||
<div class="grid gap-3 grid-cols-2 sm:grid-cols-4">
|
||||
<UiCard v-for="item in userMetrics" :key="item.label" class="hover:shadow-sm transition-shadow">
|
||||
<UiCardContent class="pt-4 pb-4">
|
||||
<p class="text-xs text-muted-foreground">
|
||||
<UiCardContent class="p-4">
|
||||
<p class="text-xs text-muted-foreground truncate">
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<p class="text-xl font-bold mt-1">
|
||||
<p class="text-lg sm:text-xl font-bold mt-1">
|
||||
{{ item.value }}
|
||||
</p>
|
||||
<p class="text-xs mt-1" :class="item.up ? 'text-green-600' : 'text-red-600'">
|
||||
@@ -253,8 +255,8 @@ function formatCurrency(value: number): string {
|
||||
</UiCard>
|
||||
</div>
|
||||
<UiCard>
|
||||
<UiCardContent class="pt-6">
|
||||
<VChart :option="userGrowthOption" autoresize style="height: 180px" />
|
||||
<UiCardContent class="p-4">
|
||||
<VChart :option="userGrowthOption" autoresize style="height: 160px" />
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
</div>
|
||||
@@ -262,26 +264,26 @@ function formatCurrency(value: number): string {
|
||||
</div>
|
||||
|
||||
<!-- 模块4: 风险指标 + 决策建议 -->
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<div class="grid gap-6 lg:grid-cols-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:shield" class="size-4" />
|
||||
风险指标
|
||||
</h2>
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
<div class="grid gap-3 grid-cols-2">
|
||||
<UiCard v-for="item in riskMetrics" :key="item.label" class="hover:shadow-sm transition-shadow">
|
||||
<UiCardContent class="pt-6">
|
||||
<UiCardContent class="p-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<p class="text-sm font-medium">
|
||||
<p class="text-xs font-medium truncate">
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<span class="text-xs text-muted-foreground">{{ item.threshold }}</span>
|
||||
<span class="text-xs text-muted-foreground shrink-0">{{ item.threshold }}</span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<p class="text-3xl font-bold" :class="item.color">
|
||||
<p class="text-2xl font-bold truncate" :class="item.color">
|
||||
{{ item.value }}
|
||||
</p>
|
||||
<UiBadge v-if="item.status === 'warning'" variant="destructive">
|
||||
<UiBadge v-if="item.status === 'warning'" variant="destructive" class="shrink-0">
|
||||
需关注
|
||||
</UiBadge>
|
||||
</div>
|
||||
@@ -290,8 +292,8 @@ function formatCurrency(value: number): string {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:lightbulb" class="size-4" />
|
||||
决策建议
|
||||
</h2>
|
||||
@@ -299,16 +301,16 @@ function formatCurrency(value: number): string {
|
||||
<div
|
||||
v-for="item in suggestions"
|
||||
:key="item.title"
|
||||
class="p-4 rounded-lg border-l-4"
|
||||
class="p-3 sm:p-4 rounded-lg border-l-4"
|
||||
:class="item.color"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<Icon :icon="item.icon" class="size-5 mt-0.5" />
|
||||
<div>
|
||||
<p class="font-medium">
|
||||
<Icon :icon="item.icon" class="size-4 sm:size-5 mt-0.5 shrink-0" />
|
||||
<div class="min-w-0">
|
||||
<p class="font-medium text-sm">
|
||||
{{ item.title }}
|
||||
</p>
|
||||
<p class="text-sm text-muted-foreground mt-1">
|
||||
<p class="text-xs sm:text-sm text-muted-foreground mt-1">
|
||||
{{ item.desc }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
<script lang="ts" setup>
|
||||
import Decimal from 'decimal.js'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import VChart from 'vue-echarts'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { BasicPage } from '@/components/global-layout'
|
||||
import { useGetFinanceOverviewQuery } from '@/services/api/monisuo-admin.api'
|
||||
import { useGetCashFlowTrendQuery, useGetFinanceOverviewQuery } from '@/services/api/monisuo-admin.api'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const { data: overviewData, isLoading } = useGetFinanceOverviewQuery()
|
||||
const { data: overviewData, isLoading: overviewLoading } = useGetFinanceOverviewQuery()
|
||||
const { data: cashFlowData, isLoading: cashFlowLoading } = useGetCashFlowTrendQuery(6)
|
||||
|
||||
const isLoading = computed(() => overviewLoading.value || cashFlowLoading.value)
|
||||
const overview = computed(() => overviewData.value?.data)
|
||||
const cashFlow = computed(() => cashFlowData.value?.data || [])
|
||||
|
||||
// ========== 模块1: 资金概览 ==========
|
||||
const fundMetrics = computed(() => [
|
||||
@@ -37,32 +42,57 @@ const fundMetrics = computed(() => [
|
||||
])
|
||||
|
||||
// ========== 模块2: 资金流动 ==========
|
||||
const flowMetrics = computed(() => [
|
||||
{
|
||||
label: '累计充值',
|
||||
value: overview.value?.totalDeposit || 0,
|
||||
icon: 'lucide:arrow-down-circle',
|
||||
color: 'text-green-600',
|
||||
bgColor: 'bg-green-50 dark:bg-green-950',
|
||||
trend: '+12.5%',
|
||||
},
|
||||
{
|
||||
label: '累计提现',
|
||||
value: overview.value?.totalWithdraw || 0,
|
||||
icon: 'lucide:arrow-up-circle',
|
||||
color: 'text-red-600',
|
||||
bgColor: 'bg-red-50 dark:bg-red-950',
|
||||
trend: '+8.3%',
|
||||
},
|
||||
{
|
||||
label: '净流入',
|
||||
value: (overview.value?.totalDeposit || 0) - (overview.value?.totalWithdraw || 0),
|
||||
icon: 'lucide:trending-up',
|
||||
color: 'text-emerald-600',
|
||||
bgColor: 'bg-emerald-50 dark:bg-emerald-950',
|
||||
trend: '+15.2%',
|
||||
},
|
||||
])
|
||||
function calcGrowthRate(current: number, previous: number): string {
|
||||
if (previous === 0)
|
||||
return current > 0 ? '+100%' : '0%'
|
||||
const rate = new Decimal(current).minus(previous).div(previous).mul(100).toDecimalPlaces(1)
|
||||
const sign = rate.gte(0) ? '+' : ''
|
||||
return `${sign}${rate}%`
|
||||
}
|
||||
|
||||
const flowMetrics = computed(() => {
|
||||
const flow = cashFlow.value
|
||||
const len = flow.length
|
||||
const thisMonth = len >= 1 ? flow[len - 1] : null
|
||||
const lastMonth = len >= 2 ? flow[len - 2] : null
|
||||
|
||||
const depositTrend = thisMonth && lastMonth
|
||||
? calcGrowthRate(thisMonth.deposit as number, lastMonth.deposit as number)
|
||||
: '+0%'
|
||||
const withdrawTrend = thisMonth && lastMonth
|
||||
? calcGrowthRate(thisMonth.withdraw as number, lastMonth.withdraw as number)
|
||||
: '+0%'
|
||||
const netInflowTrend = thisMonth && lastMonth
|
||||
? calcGrowthRate(thisMonth.netInflow as number, lastMonth.netInflow as number)
|
||||
: '+0%'
|
||||
|
||||
return [
|
||||
{
|
||||
label: '累计充值',
|
||||
value: overview.value?.totalDeposit || 0,
|
||||
icon: 'lucide:arrow-down-circle',
|
||||
color: 'text-green-600',
|
||||
bgColor: 'bg-green-50 dark:bg-green-950',
|
||||
trend: depositTrend,
|
||||
},
|
||||
{
|
||||
label: '累计提现',
|
||||
value: overview.value?.totalWithdraw || 0,
|
||||
icon: 'lucide:arrow-up-circle',
|
||||
color: 'text-red-600',
|
||||
bgColor: 'bg-red-50 dark:bg-red-950',
|
||||
trend: withdrawTrend,
|
||||
},
|
||||
{
|
||||
label: '净流入',
|
||||
value: (overview.value?.totalDeposit || 0) - (overview.value?.totalWithdraw || 0),
|
||||
icon: 'lucide:trending-up',
|
||||
color: 'text-emerald-600',
|
||||
bgColor: 'bg-emerald-50 dark:bg-emerald-950',
|
||||
trend: netInflowTrend,
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
// ========== 模块3: 资金趋势图 ==========
|
||||
const trendChartOption = computed(() => ({
|
||||
@@ -71,7 +101,7 @@ const trendChartOption = computed(() => ({
|
||||
grid: { left: '3%', right: '4%', bottom: '15%', top: '5%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月'],
|
||||
data: cashFlow.value.map((t: any) => t.month),
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
@@ -82,7 +112,7 @@ const trendChartOption = computed(() => ({
|
||||
name: '充值',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [320, 302, 301, 334, 390, 430],
|
||||
data: cashFlow.value.map((t: any) => t.deposit),
|
||||
itemStyle: { color: '#10b981' },
|
||||
areaStyle: { color: 'rgba(16, 185, 129, 0.1)' },
|
||||
},
|
||||
@@ -90,7 +120,7 @@ const trendChartOption = computed(() => ({
|
||||
name: '提现',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [120, 132, 101, 134, 90, 230],
|
||||
data: cashFlow.value.map((t: any) => t.withdraw),
|
||||
itemStyle: { color: '#ef4444' },
|
||||
areaStyle: { color: 'rgba(239, 68, 68, 0.1)' },
|
||||
},
|
||||
@@ -98,23 +128,27 @@ const trendChartOption = computed(() => ({
|
||||
}))
|
||||
|
||||
// ========== 模块4: 资金分布 ==========
|
||||
const distributionOption = computed(() => ({
|
||||
tooltip: { trigger: 'item', formatter: '{b}: {d}%' },
|
||||
legend: { orient: 'vertical', right: '5%', top: 'center' },
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['50%', '75%'],
|
||||
center: ['35%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: { borderRadius: 8, borderColor: '#fff', borderWidth: 2 },
|
||||
label: { show: true, position: 'inside', formatter: '{d}%', fontSize: 12 },
|
||||
data: [
|
||||
{ value: overview.value?.fundBalance || 50, name: '在管资金', itemStyle: { color: '#3b82f6' } },
|
||||
{ value: overview.value?.tradeValue || 30, name: '交易账户', itemStyle: { color: '#8b5cf6' } },
|
||||
{ value: 20, name: '冻结资金', itemStyle: { color: '#f59e0b' } },
|
||||
],
|
||||
}],
|
||||
}))
|
||||
const distributionOption = computed(() => {
|
||||
const fundBalance = overview.value?.fundBalance || 0
|
||||
const tradeValue = overview.value?.tradeValue || 0
|
||||
|
||||
return {
|
||||
tooltip: { trigger: 'item', formatter: '{b}: {d}%' },
|
||||
legend: { orient: 'vertical', right: '5%', top: 'center' },
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['50%', '75%'],
|
||||
center: ['35%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: { borderRadius: 8, borderColor: '#fff', borderWidth: 2 },
|
||||
label: { show: true, position: 'inside', formatter: '{d}%', fontSize: 12 },
|
||||
data: [
|
||||
{ value: fundBalance, name: '在管资金', itemStyle: { color: '#3b82f6' } },
|
||||
{ value: tradeValue, name: '交易账户', itemStyle: { color: '#8b5cf6' } },
|
||||
],
|
||||
}],
|
||||
}
|
||||
})
|
||||
|
||||
// ========== 模块5: 运营指标 ==========
|
||||
const operationMetrics = computed(() => [
|
||||
@@ -139,26 +173,26 @@ function navigateTo(path: string) {
|
||||
<UiSpinner class="w-8 h-8" />
|
||||
</div>
|
||||
|
||||
<div v-else class="space-y-6">
|
||||
<div v-else class="grid gap-6">
|
||||
<!-- 模块1: 资金概览 -->
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:wallet" class="size-4" />
|
||||
资金概览
|
||||
</h2>
|
||||
<div class="grid gap-3 sm:grid-cols-3">
|
||||
<div class="grid gap-3 grid-cols-1 sm:grid-cols-3">
|
||||
<UiCard v-for="item in fundMetrics" :key="item.label" class="hover:shadow-sm transition-shadow">
|
||||
<UiCardContent class="pt-6">
|
||||
<UiCardContent class="p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="p-2.5 rounded-lg" :class="[item.bgColor]">
|
||||
<Icon :icon="item.icon" class="size-5" :class="item.color" />
|
||||
<div class="p-2 rounded-lg" :class="[item.bgColor]">
|
||||
<Icon :icon="item.icon" class="size-4" :class="item.color" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 space-y-1">
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<p class="text-2xl font-bold font-mono" :class="item.color">
|
||||
<p class="text-lg sm:text-xl font-bold font-mono truncate" :class="item.color">
|
||||
{{ formatCurrency(item.value) }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -168,17 +202,17 @@ function navigateTo(path: string) {
|
||||
</section>
|
||||
|
||||
<!-- 模块2: 资金流动 -->
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:git-compare" class="size-4" />
|
||||
资金流动
|
||||
</h2>
|
||||
<div class="grid gap-3 sm:grid-cols-3">
|
||||
<div class="grid gap-3 grid-cols-1 sm:grid-cols-3">
|
||||
<UiCard v-for="item in flowMetrics" :key="item.label" class="hover:shadow-sm transition-shadow">
|
||||
<UiCardContent class="pt-6">
|
||||
<UiCardContent class="p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="p-2.5 rounded-lg" :class="[item.bgColor]">
|
||||
<Icon :icon="item.icon" class="size-5" :class="item.color" />
|
||||
<div class="p-2 rounded-lg" :class="[item.bgColor]">
|
||||
<Icon :icon="item.icon" class="size-4" :class="item.color" />
|
||||
</div>
|
||||
<span class="text-xs font-medium text-green-600">{{ item.trend }}</span>
|
||||
</div>
|
||||
@@ -186,7 +220,7 @@ function navigateTo(path: string) {
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<p class="text-2xl font-bold font-mono" :class="item.color">
|
||||
<p class="text-lg sm:text-xl font-bold font-mono truncate" :class="item.color">
|
||||
{{ formatCurrency(item.value) }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -196,55 +230,55 @@ function navigateTo(path: string) {
|
||||
</section>
|
||||
|
||||
<!-- 模块3+4: 图表区域 -->
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<div class="grid gap-6 lg:grid-cols-2">
|
||||
<!-- 资金趋势 -->
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:trending-up" class="size-4" />
|
||||
资金趋势
|
||||
</h2>
|
||||
<UiCard>
|
||||
<UiCardContent class="pt-6">
|
||||
<VChart :option="trendChartOption" autoresize style="height: 260px" />
|
||||
<UiCardContent class="p-4">
|
||||
<VChart :option="trendChartOption" autoresize style="height: 240px" />
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
</section>
|
||||
|
||||
<!-- 资金分布 -->
|
||||
<section>
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:pie-chart" class="size-4" />
|
||||
资金分布
|
||||
</h2>
|
||||
<UiCard>
|
||||
<UiCardContent class="pt-6">
|
||||
<VChart :option="distributionOption" autoresize style="height: 260px" />
|
||||
<UiCardContent class="p-4">
|
||||
<VChart :option="distributionOption" autoresize style="height: 240px" />
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- 模块5: 运营指标 + 快捷入口 -->
|
||||
<div class="grid gap-4 lg:grid-cols-3">
|
||||
<div class="grid gap-6 lg:grid-cols-5">
|
||||
<!-- 运营指标 -->
|
||||
<section class="lg:col-span-1">
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3 lg:col-span-2">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:activity" class="size-4" />
|
||||
运营指标
|
||||
</h2>
|
||||
<div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-1">
|
||||
<div class="grid gap-3 grid-cols-2">
|
||||
<UiCard v-for="item in operationMetrics" :key="item.label" class="hover:shadow-sm transition-shadow">
|
||||
<UiCardContent class="pt-6">
|
||||
<UiCardContent class="p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
<div class="min-w-0">
|
||||
<p class="text-xs text-muted-foreground truncate">
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<p class="text-2xl font-bold mt-1">
|
||||
<p class="text-lg sm:text-xl font-bold mt-1 truncate">
|
||||
{{ item.value }}
|
||||
</p>
|
||||
</div>
|
||||
<Icon :icon="item.icon" class="size-8 text-muted-foreground/30" />
|
||||
<Icon :icon="item.icon" class="size-6 text-muted-foreground/30 shrink-0" />
|
||||
</div>
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
@@ -252,19 +286,19 @@ function navigateTo(path: string) {
|
||||
</section>
|
||||
|
||||
<!-- 快捷入口 -->
|
||||
<section class="lg:col-span-2">
|
||||
<h2 class="text-sm font-medium text-muted-foreground mb-3 flex items-center gap-2">
|
||||
<section class="space-y-3 lg:col-span-3">
|
||||
<h2 class="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<Icon icon="lucide:zap" class="size-4" />
|
||||
快捷入口
|
||||
</h2>
|
||||
<div class="grid gap-3 sm:grid-cols-3">
|
||||
<div class="grid gap-3 grid-cols-2 sm:grid-cols-4">
|
||||
<UiCard
|
||||
class="cursor-pointer hover:shadow-md hover:border-primary/50 transition-all"
|
||||
@click="navigateTo('/monisuo/users')"
|
||||
>
|
||||
<UiCardContent class="pt-6 text-center">
|
||||
<Icon icon="lucide:users" class="size-8 mx-auto mb-2 text-blue-600" />
|
||||
<p class="font-medium">
|
||||
<UiCardContent class="p-4 text-center">
|
||||
<Icon icon="lucide:users" class="size-6 mx-auto mb-2 text-blue-600" />
|
||||
<p class="text-sm font-medium">
|
||||
用户管理
|
||||
</p>
|
||||
</UiCardContent>
|
||||
@@ -274,9 +308,9 @@ function navigateTo(path: string) {
|
||||
class="cursor-pointer hover:shadow-md hover:border-primary/50 transition-all"
|
||||
@click="navigateTo('/monisuo/coins')"
|
||||
>
|
||||
<UiCardContent class="pt-6 text-center">
|
||||
<Icon icon="lucide:coins" class="size-8 mx-auto mb-2 text-yellow-600" />
|
||||
<p class="font-medium">
|
||||
<UiCardContent class="p-4 text-center">
|
||||
<Icon icon="lucide:coins" class="size-6 mx-auto mb-2 text-yellow-600" />
|
||||
<p class="text-sm font-medium">
|
||||
币种管理
|
||||
</p>
|
||||
</UiCardContent>
|
||||
@@ -286,9 +320,9 @@ function navigateTo(path: string) {
|
||||
class="cursor-pointer hover:shadow-md hover:border-primary/50 transition-all"
|
||||
@click="navigateTo('/monisuo/orders')"
|
||||
>
|
||||
<UiCardContent class="pt-6 text-center">
|
||||
<Icon icon="lucide:clipboard-check" class="size-8 mx-auto mb-2 text-green-600" />
|
||||
<p class="font-medium">
|
||||
<UiCardContent class="p-4 text-center">
|
||||
<Icon icon="lucide:clipboard-check" class="size-6 mx-auto mb-2 text-green-600" />
|
||||
<p class="text-sm font-medium">
|
||||
订单审批
|
||||
</p>
|
||||
</UiCardContent>
|
||||
@@ -298,9 +332,9 @@ function navigateTo(path: string) {
|
||||
class="cursor-pointer hover:shadow-md hover:border-primary/50 transition-all"
|
||||
@click="navigateTo('/monisuo/analytics')"
|
||||
>
|
||||
<UiCardContent class="pt-6 text-center">
|
||||
<Icon icon="lucide:trending-up" class="size-8 mx-auto mb-2 text-purple-600" />
|
||||
<p class="font-medium">
|
||||
<UiCardContent class="p-4 text-center">
|
||||
<Icon icon="lucide:trending-up" class="size-6 mx-auto mb-2 text-purple-600" />
|
||||
<p class="text-sm font-medium">
|
||||
业务分析
|
||||
</p>
|
||||
</UiCardContent>
|
||||
|
||||
Reference in New Issue
Block a user