第 5 阶段:纠纷、通知与后台-3
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { apiClient } from './client'
|
||||
|
||||
export interface DashboardMetrics {
|
||||
total_users: number
|
||||
verified_users: number
|
||||
total_listings: number
|
||||
published_listings: number
|
||||
total_orders: number
|
||||
renting_orders: number
|
||||
today_orders: number
|
||||
today_ledger_amount: number
|
||||
}
|
||||
|
||||
export interface DashboardPending {
|
||||
listing_reviews: number
|
||||
disputes: number
|
||||
pending_handoffs: number
|
||||
pending_return_confirms: number
|
||||
}
|
||||
|
||||
export interface DashboardRecentOrder {
|
||||
id: number
|
||||
order_no: string
|
||||
title: string
|
||||
renter_id: number
|
||||
owner_id: number
|
||||
status: string
|
||||
rent_amount: number
|
||||
deposit_amount: number
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface DashboardRecentDispute {
|
||||
id: number
|
||||
order_id: number
|
||||
order_no: string
|
||||
title: string
|
||||
type: string
|
||||
status: string
|
||||
initiator_id: number
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface AdminDashboard {
|
||||
metrics: DashboardMetrics
|
||||
pending: DashboardPending
|
||||
recent_orders: DashboardRecentOrder[]
|
||||
recent_disputes: DashboardRecentDispute[]
|
||||
generated_at: string
|
||||
}
|
||||
|
||||
interface ApiResponse<T> {
|
||||
code: string
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
export async function fetchAdminDashboard() {
|
||||
const { data } = await apiClient.get<ApiResponse<AdminDashboard>>('/admin/dashboard')
|
||||
return data.data
|
||||
}
|
||||
@@ -135,6 +135,38 @@ h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.dashboard-metrics {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.dashboard-panels {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.dashboard-panel {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.pending-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
min-height: 40px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
color: #52616f;
|
||||
}
|
||||
|
||||
.pending-row:first-of-type {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.pending-row strong {
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
max-width: 420px;
|
||||
margin-top: 28px;
|
||||
@@ -399,6 +431,8 @@ h1 {
|
||||
|
||||
.listing-grid,
|
||||
.detail-grid,
|
||||
.dashboard-metrics,
|
||||
.dashboard-panels,
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
import { fetchAdminDashboard, type AdminDashboard } from '@/api/adminDashboard'
|
||||
|
||||
const loading = ref(false)
|
||||
const dashboard = ref<AdminDashboard | null>(null)
|
||||
|
||||
onMounted(loadDashboard)
|
||||
|
||||
async function loadDashboard() {
|
||||
loading.value = true
|
||||
try {
|
||||
dashboard.value = await fetchAdminDashboard()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function money(value?: number) {
|
||||
return `¥${Number(value || 0).toFixed(2)}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="page">
|
||||
<div class="page-header">
|
||||
<p class="eyebrow">Admin</p>
|
||||
<h1>后台仪表盘</h1>
|
||||
<p>待审核、待仲裁、订单和流水概览。</p>
|
||||
<section class="page" v-loading="loading">
|
||||
<div class="page-header-row">
|
||||
<div class="page-header">
|
||||
<p class="eyebrow">Admin</p>
|
||||
<h1>后台仪表盘</h1>
|
||||
<p>待审核、待仲裁、订单和流水概览。</p>
|
||||
</div>
|
||||
<el-button @click="loadDashboard">刷新</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="dashboard" class="metric-grid dashboard-metrics">
|
||||
<div class="metric-card">
|
||||
<span>用户总数</span>
|
||||
<strong>{{ dashboard.metrics.total_users }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>实名用户</span>
|
||||
<strong>{{ dashboard.metrics.verified_users }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>发布商品</span>
|
||||
<strong>{{ dashboard.metrics.total_listings }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>已上架</span>
|
||||
<strong>{{ dashboard.metrics.published_listings }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>订单总数</span>
|
||||
<strong>{{ dashboard.metrics.total_orders }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>租赁中</span>
|
||||
<strong>{{ dashboard.metrics.renting_orders }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>今日订单</span>
|
||||
<strong>{{ dashboard.metrics.today_orders }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>今日流水</span>
|
||||
<strong>{{ money(dashboard.metrics.today_ledger_amount) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="dashboard" class="dashboard-panels">
|
||||
<div class="order-panel dashboard-panel">
|
||||
<h2>待处理</h2>
|
||||
<RouterLink class="pending-row" to="/admin/disputes">
|
||||
<span>待仲裁申诉</span>
|
||||
<strong>{{ dashboard.pending.disputes }}</strong>
|
||||
</RouterLink>
|
||||
<div class="pending-row">
|
||||
<span>待审核商品</span>
|
||||
<strong>{{ dashboard.pending.listing_reviews }}</strong>
|
||||
</div>
|
||||
<div class="pending-row">
|
||||
<span>待交接订单</span>
|
||||
<strong>{{ dashboard.pending.pending_handoffs }}</strong>
|
||||
</div>
|
||||
<div class="pending-row">
|
||||
<span>待归还确认</span>
|
||||
<strong>{{ dashboard.pending.pending_return_confirms }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-panel dashboard-panel">
|
||||
<h2>后台入口</h2>
|
||||
<RouterLink class="pending-row" to="/admin/disputes">
|
||||
<span>仲裁中心</span>
|
||||
<strong>进入</strong>
|
||||
</RouterLink>
|
||||
<RouterLink class="pending-row" to="/admin/system-configs">
|
||||
<span>系统配置</span>
|
||||
<strong>进入</strong>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table v-if="dashboard" class="table-panel" :data="dashboard.recent_orders">
|
||||
<el-table-column prop="order_no" label="最近订单" min-width="210" />
|
||||
<el-table-column prop="title" label="账号" min-width="170" />
|
||||
<el-table-column prop="status" label="状态" width="140" />
|
||||
<el-table-column prop="rent_amount" label="租金" width="100" />
|
||||
<el-table-column prop="deposit_amount" label="押金" width="100" />
|
||||
<el-table-column prop="created_at" label="创建时间" min-width="180" />
|
||||
</el-table>
|
||||
|
||||
<el-table v-if="dashboard" class="table-panel" :data="dashboard.recent_disputes">
|
||||
<el-table-column prop="order_no" label="最近申诉" min-width="210" />
|
||||
<el-table-column prop="title" label="账号" min-width="170" />
|
||||
<el-table-column prop="type" label="类型" width="160" />
|
||||
<el-table-column prop="status" label="状态" width="120" />
|
||||
<el-table-column prop="created_at" label="创建时间" min-width="180" />
|
||||
<el-table-column label="操作" width="100">
|
||||
<template #default>
|
||||
<RouterLink to="/admin/disputes">
|
||||
<el-button size="small">处理</el-button>
|
||||
</RouterLink>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user