新增财务仪表盘并统一金额到角

This commit is contained in:
yml
2026-06-09 00:13:03 +08:00
parent a2a0489158
commit 2dfa2611fd
40 changed files with 1324 additions and 70 deletions
@@ -0,0 +1,189 @@
<script setup lang="ts">
import { Refresh, Search } from '@element-plus/icons-vue'
import { computed, onMounted, reactive, ref } from 'vue'
import {
fetchFinanceDashboard,
type FinanceDashboard,
type FinanceDailyItem,
} from '@/features/admin/api/adminFinance'
import { formatMoneyWithSymbol } from '@/shared/utils/money'
import { formatDateTime } from '@/utils/time'
const loading = ref(false)
const dashboard = ref<FinanceDashboard | null>(null)
const filters = reactive({
start_date: defaultStartDate(),
end_date: defaultEndDate(),
})
const dailyItems = computed(() => dashboard.value?.daily_items ?? [])
onMounted(loadDashboard)
async function loadDashboard() {
loading.value = true
try {
dashboard.value = await fetchFinanceDashboard(filters)
} finally {
loading.value = false
}
}
function moneyCent(value: number) {
return formatMoneyWithSymbol(Number(value || 0) / 100)
}
function money(value: number) {
return formatMoneyWithSymbol(value)
}
function defaultStartDate() {
const date = new Date()
date.setDate(date.getDate() - 6)
return formatInputDate(date)
}
function defaultEndDate() {
return formatInputDate(new Date())
}
function formatInputDate(date: Date) {
return date.toISOString().slice(0, 10)
}
function diffType(value: number) {
return Math.abs(Number(value || 0)) >= 0.05 ? 'danger' : 'success'
}
function rowDiffClass(row: FinanceDailyItem) {
return Math.abs(Number(row.settlement_diff_amount || 0)) >= 0.05 ? 'amount-danger' : ''
}
</script>
<template>
<section class="page">
<div class="page-header-row">
<div class="page-header">
<p class="eyebrow">Finance Dashboard</p>
<h1>财务仪表盘</h1>
<p>按天查看第三方收款退款平台收入号主入账和结算差异</p>
</div>
<div class="toolbar-actions">
<el-date-picker
v-model="filters.start_date"
type="date"
value-format="YYYY-MM-DD"
placeholder="开始日期"
/>
<el-date-picker
v-model="filters.end_date"
type="date"
value-format="YYYY-MM-DD"
placeholder="结束日期"
/>
<el-button type="primary" :icon="Search" :loading="loading" @click="loadDashboard">
查询
</el-button>
<el-button :icon="Refresh" :loading="loading" @click="loadDashboard">刷新</el-button>
</div>
</div>
<div v-if="dashboard" class="metric-grid">
<div class="metric-card">
<span>总流水</span>
<strong>{{ moneyCent(dashboard.summary.total_flow_amount_cent) }}</strong>
<small>{{ dashboard.summary.successful_pay_count }} 笔成功收款</small>
</div>
<div class="metric-card">
<span>总退款</span>
<strong>{{ moneyCent(dashboard.summary.total_refund_amount_cent) }}</strong>
<small>{{ dashboard.summary.successful_refund_count }} 笔成功退款</small>
</div>
<div class="metric-card">
<span>渠道净流入</span>
<strong>{{ moneyCent(dashboard.summary.channel_net_amount_cent) }}</strong>
<small>成功收款 - 成功退款</small>
</div>
<div class="metric-card">
<span>平台收入</span>
<strong>{{ money(dashboard.summary.platform_income_amount) }}</strong>
<small>{{ dashboard.summary.settled_order_count }} 个已结算订单</small>
</div>
<div class="metric-card">
<span>号主应得</span>
<strong>{{ money(dashboard.summary.owner_should_income_amount) }}</strong>
<small>结账单口径</small>
</div>
<div class="metric-card">
<span>号主实际入账</span>
<strong>{{ money(dashboard.summary.owner_wallet_income_amount) }}</strong>
<small>钱包流水口径</small>
</div>
<div class="metric-card">
<span>退款中</span>
<strong>{{ moneyCent(dashboard.summary.pending_refund_amount_cent) }}</strong>
<small>{{ dashboard.summary.pending_refund_count }} 笔待回执</small>
</div>
<div class="metric-card">
<span>结算差异</span>
<strong>
<el-tag :type="diffType(dashboard.summary.settlement_diff_amount)">
{{ money(dashboard.summary.settlement_diff_amount) }}
</el-tag>
</strong>
<small>{{ dashboard.summary.financial_exception_count }} 个异常订单</small>
</div>
</div>
<el-table v-loading="loading" class="table-panel" :data="dailyItems">
<el-table-column prop="date" label="日期" width="130" />
<el-table-column label="总流水" width="130">
<template #default="{ row }">{{ moneyCent(row.total_flow_amount_cent) }}</template>
</el-table-column>
<el-table-column label="总退款" width="130">
<template #default="{ row }">{{ moneyCent(row.total_refund_amount_cent) }}</template>
</el-table-column>
<el-table-column label="渠道净流入" width="140">
<template #default="{ row }">{{ moneyCent(row.channel_net_amount_cent) }}</template>
</el-table-column>
<el-table-column label="平台收入" width="130">
<template #default="{ row }">{{ money(row.platform_income_amount) }}</template>
</el-table-column>
<el-table-column label="号主应得" width="130">
<template #default="{ row }">{{ money(row.owner_should_income_amount) }}</template>
</el-table-column>
<el-table-column label="号主入账" width="130">
<template #default="{ row }">{{ money(row.owner_wallet_income_amount) }}</template>
</el-table-column>
<el-table-column label="结算差异" width="130">
<template #default="{ row }">
<span :class="rowDiffClass(row)">{{ money(row.settlement_diff_amount) }}</span>
</template>
</el-table-column>
<el-table-column label="收款/退款/结算" min-width="170">
<template #default="{ row }">
{{ row.successful_pay_count }} / {{ row.successful_refund_count }} /
{{ row.settled_order_count }}
</template>
</el-table-column>
</el-table>
<p v-if="dashboard" class="generated-at">
数据生成时间{{ formatDateTime(dashboard.generated_at) }}
</p>
</section>
</template>
<style scoped>
.amount-danger {
color: #dc2626;
font-weight: 700;
}
.generated-at {
margin: 12px 0 0;
color: #64748b;
font-size: 13px;
}
</style>