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