优化财务管理整个ui
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { Document, Search } from '@element-plus/icons-vue'
|
||||
import {
|
||||
CreditCard,
|
||||
DocumentChecked,
|
||||
Money,
|
||||
Refresh,
|
||||
Search,
|
||||
TopRight,
|
||||
View,
|
||||
Wallet,
|
||||
} from '@element-plus/icons-vue'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
|
||||
import { fetchAdminPayments, type AdminPayment } from '@/features/admin/api/adminPayments'
|
||||
@@ -15,6 +24,7 @@ const currentPageSize = ref(20)
|
||||
const total = ref(0)
|
||||
const detailVisible = ref(false)
|
||||
const activePayment = ref<AdminPayment | null>(null)
|
||||
|
||||
const filters = reactive({
|
||||
user_id: '',
|
||||
order_id: '',
|
||||
@@ -70,11 +80,11 @@ async function handlePageChange() {
|
||||
await loadPayments()
|
||||
}
|
||||
|
||||
function moneyCent(value: number) {
|
||||
return formatCentWithSymbol(value)
|
||||
function moneyCent(value: number | undefined | null) {
|
||||
return formatCentWithSymbol(value || 0)
|
||||
}
|
||||
|
||||
function paymentStatusType(status: string) {
|
||||
function paymentStatusType(status: string): 'success' | 'danger' | 'warning' | 'info' {
|
||||
if (['paid', 'refunded'].includes(status)) return 'success'
|
||||
if (status === 'failed') return 'danger'
|
||||
if (['paying', 'refunding'].includes(status)) return 'warning'
|
||||
@@ -126,199 +136,643 @@ function jsonText(value: unknown) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="page">
|
||||
<div class="page-header-row">
|
||||
<div class="page-header">
|
||||
<p class="eyebrow">Payment Ledger</p>
|
||||
<h1>支付流水</h1>
|
||||
<p>查看第三方支付、退款请求、渠道单号、状态和失败原因。</p>
|
||||
</div>
|
||||
<div class="toolbar-actions">
|
||||
<el-button @click="resetFilters">重置</el-button>
|
||||
<el-button type="primary" :icon="Search" :loading="loading" @click="loadPayments"
|
||||
>查询</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric-grid">
|
||||
<div class="metric-card">
|
||||
<span>总条数</span>
|
||||
<strong>{{ total }} 笔</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>本页支付额</span>
|
||||
<strong>{{ moneyCent(payAmount) }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>本页退款额</span>
|
||||
<strong>{{ moneyCent(refundAmount) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-form class="filter-panel" label-position="top">
|
||||
<el-form-item label="用户 ID">
|
||||
<el-input v-model="filters.user_id" clearable placeholder="按用户筛选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单 ID">
|
||||
<el-input v-model="filters.order_id" clearable placeholder="按订单筛选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单号">
|
||||
<el-input v-model="filters.order_no" clearable placeholder="按订单号筛选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="业务类型">
|
||||
<el-select v-model="filters.biz_type" clearable placeholder="全部业务" class="full-control">
|
||||
<el-option label="订单支付" value="order_pay" />
|
||||
<el-option label="撞车支付" value="mohong_pay" />
|
||||
<el-option label="结账退款" value="checkout_refund" />
|
||||
<el-option label="仲裁退款" value="arbitration_refund" />
|
||||
<el-option label="人工退款" value="admin_refund" />
|
||||
<el-option label="取消退款" value="cancel_refund" />
|
||||
<el-option label="撞车退款" value="mohong_refund" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="filters.status" clearable placeholder="全部状态" class="full-control">
|
||||
<el-option label="已支付" value="paid" />
|
||||
<el-option label="支付中" value="paying" />
|
||||
<el-option label="退款中" value="refunding" />
|
||||
<el-option label="已退款" value="refunded" />
|
||||
<el-option label="失败" value="failed" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="渠道">
|
||||
<el-select v-model="filters.provider" clearable placeholder="全部渠道" class="full-control">
|
||||
<el-option label="拉卡拉" value="lakala" />
|
||||
<el-option label="乐刷" value="leshua" />
|
||||
<el-option label="顺成" value="shuncheng" />
|
||||
<el-option label="Mock" value="mock" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="loading" class="table-panel" :data="payments">
|
||||
<el-table-column prop="payment_no" label="支付单号" min-width="220" />
|
||||
<el-table-column label="订单" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<RouterLink v-if="row.order_id" :to="adminPath(`orders/${row.order_id}`)">{{
|
||||
row.order_no || row.order_id
|
||||
}}</RouterLink>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户" min-width="130">
|
||||
<template #default="{ row }">{{ row.user_phone || `用户 ${row.user_id}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="业务" width="120">
|
||||
<template #default="{ row }">{{ bizTypeLabel(row.biz_type) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="渠道" width="90">
|
||||
<template #default="{ row }">{{ row.provider || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="金额" width="110">
|
||||
<template #default="{ row }">{{ moneyCent(row.amount_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="110">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="paymentStatusType(row.status)">{{
|
||||
paymentStatusLabel(row.status)
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="失败原因" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.status === 'failed' && row.error_message"
|
||||
>{{ row.error_code }} {{ row.error_message }}</span
|
||||
>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="third_order_id" label="平台单号" min-width="230" />
|
||||
<el-table-column prop="provider_order_id" label="渠道单号" min-width="220" />
|
||||
<el-table-column label="创建时间" min-width="180">
|
||||
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button size="small" :icon="Document" @click="openDetail(row)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<AdminTablePagination
|
||||
v-if="total > 0"
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="currentPageSize"
|
||||
:total="total"
|
||||
:loading="loading"
|
||||
@page-change="handlePageChange"
|
||||
/>
|
||||
|
||||
<el-dialog v-model="detailVisible" title="支付流水详情" width="820px">
|
||||
<div v-if="activePayment" class="payment-detail">
|
||||
<div class="detail-grid">
|
||||
<p>
|
||||
<span>业务类型</span><strong>{{ bizTypeLabel(activePayment.biz_type) }}</strong>
|
||||
</p>
|
||||
<p>
|
||||
<span>状态</span><strong>{{ paymentStatusLabel(activePayment.status) }}</strong>
|
||||
</p>
|
||||
<p>
|
||||
<span>金额</span><strong>{{ moneyCent(activePayment.amount_cent) }}</strong>
|
||||
</p>
|
||||
<p>
|
||||
<span>渠道</span><strong>{{ activePayment.provider || '-' }}</strong>
|
||||
<div class="finance-page-container">
|
||||
<!-- 头部卡片 -->
|
||||
<header class="page-header-card">
|
||||
<div class="header-main">
|
||||
<div class="title-group">
|
||||
<div class="eyebrow-tag">
|
||||
<el-icon><CreditCard /></el-icon>
|
||||
<span>PAYMENT LEDGER</span>
|
||||
</div>
|
||||
<h1 class="page-title">支付流水</h1>
|
||||
<p class="page-subtitle">
|
||||
聚合监控第三方通道支付与退款交互、渠道交易号、状态及失败异常报文。
|
||||
</p>
|
||||
</div>
|
||||
<h3>请求参数</h3>
|
||||
<pre>{{ jsonText(activePayment.raw_request) }}</pre>
|
||||
<h3>响应结果</h3>
|
||||
<pre>{{ jsonText(activePayment.raw_response) }}</pre>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
<el-button :icon="Refresh" @click="resetFilters">重置</el-button>
|
||||
<el-button type="primary" :icon="Search" :loading="loading" @click="loadPayments">
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- 汇总指标卡片 -->
|
||||
<section class="summary-metric-grid">
|
||||
<div class="metric-card metric-card--pay">
|
||||
<div class="metric-icon-wrap emerald">
|
||||
<el-icon><Money /></el-icon>
|
||||
</div>
|
||||
<div class="metric-info">
|
||||
<span class="metric-label">本页支付成功额</span>
|
||||
<strong class="metric-val emerald-val">{{ moneyCent(payAmount) }}</strong>
|
||||
<span class="metric-sub-pill success">支付流水</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric-card metric-card--refund">
|
||||
<div class="metric-icon-wrap rose">
|
||||
<el-icon><TopRight /></el-icon>
|
||||
</div>
|
||||
<div class="metric-info">
|
||||
<span class="metric-label">本页退款发生额</span>
|
||||
<strong class="metric-val rose-val">{{ moneyCent(refundAmount) }}</strong>
|
||||
<span class="metric-sub-pill danger">退款流水</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric-card metric-card--total">
|
||||
<div class="metric-icon-wrap indigo">
|
||||
<el-icon><Wallet /></el-icon>
|
||||
</div>
|
||||
<div class="metric-info">
|
||||
<span class="metric-label">渠道流水记录</span>
|
||||
<strong class="metric-val">{{ total }} 笔</strong>
|
||||
<span class="metric-sub-text">第三方通道总记录数</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 筛选卡片 -->
|
||||
<section class="section-card filter-card">
|
||||
<el-form class="filter-grid" label-position="top" @keyup.enter="loadPayments">
|
||||
<el-form-item label="用户 ID">
|
||||
<el-input v-model="filters.user_id" clearable placeholder="按用户 ID 检索" />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单 ID">
|
||||
<el-input v-model="filters.order_id" clearable placeholder="按订单 ID 检索" />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单号">
|
||||
<el-input v-model="filters.order_no" clearable placeholder="按订单号检索" />
|
||||
</el-form-item>
|
||||
<el-form-item label="业务类型">
|
||||
<el-select
|
||||
v-model="filters.biz_type"
|
||||
clearable
|
||||
placeholder="全部业务类型"
|
||||
class="full-control"
|
||||
>
|
||||
<el-option label="订单支付" value="order_pay" />
|
||||
<el-option label="撞车支付" value="mohong_pay" />
|
||||
<el-option label="结账退款" value="checkout_refund" />
|
||||
<el-option label="仲裁退款" value="arbitration_refund" />
|
||||
<el-option label="人工退款" value="admin_refund" />
|
||||
<el-option label="取消退款" value="cancel_refund" />
|
||||
<el-option label="撞车退款" value="mohong_refund" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="流水状态">
|
||||
<el-select v-model="filters.status" clearable placeholder="全部状态" class="full-control">
|
||||
<el-option label="已支付" value="paid" />
|
||||
<el-option label="支付中" value="paying" />
|
||||
<el-option label="退款中" value="refunding" />
|
||||
<el-option label="已退款" value="refunded" />
|
||||
<el-option label="失败" value="failed" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="支付渠道">
|
||||
<el-select
|
||||
v-model="filters.provider"
|
||||
clearable
|
||||
placeholder="全部渠道"
|
||||
class="full-control"
|
||||
>
|
||||
<el-option label="拉卡拉" value="lakala" />
|
||||
<el-option label="乐刷" value="leshua" />
|
||||
<el-option label="顺成" value="shuncheng" />
|
||||
<el-option label="Mock" value="mock" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</section>
|
||||
|
||||
<!-- 支付流水表格 -->
|
||||
<section class="section-card table-section-card">
|
||||
<div class="table-card-header">
|
||||
<div class="table-header-title">
|
||||
<el-icon class="header-icon"><DocumentChecked /></el-icon>
|
||||
<span>支付与退款渠道明细</span>
|
||||
</div>
|
||||
<span class="count-badge">共 {{ total }} 条记录</span>
|
||||
</div>
|
||||
|
||||
<div class="table-container">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
class="custom-enterprise-table"
|
||||
:data="payments"
|
||||
stripe
|
||||
empty-text="暂无支付流水记录"
|
||||
>
|
||||
<el-table-column label="支付流水号" min-width="210" fixed="left">
|
||||
<template #default="{ row }">
|
||||
<span class="mono-code">{{ row.payment_no }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="渠道 / 方式" width="150">
|
||||
<template #default="{ row }">
|
||||
<div class="provider-cell">
|
||||
<el-tag size="small" effect="plain" class="provider-tag">{{ row.provider }}</el-tag>
|
||||
<small class="pay-way">{{ row.pay_way || '-' }}</small>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="业务类型" width="130">
|
||||
<template #default="{ row }">
|
||||
<span class="biz-type-text">{{ bizTypeLabel(row.biz_type) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="交易金额" min-width="130" align="right">
|
||||
<template #default="{ row }">
|
||||
<strong
|
||||
class="amount-val"
|
||||
:class="row.biz_type.includes('refund') ? 'refund-val' : 'pay-val'"
|
||||
>
|
||||
{{ moneyCent(row.amount_cent) }}
|
||||
</strong>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="状态" width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="paymentStatusType(row.status)" class="status-pill">
|
||||
{{ paymentStatusLabel(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="关联订单 / 用户" min-width="170">
|
||||
<template #default="{ row }">
|
||||
<div class="order-user-cell">
|
||||
<RouterLink
|
||||
v-if="row.order_id"
|
||||
class="order-link"
|
||||
:to="adminPath(`orders/${row.order_id}`)"
|
||||
>
|
||||
{{ row.order_no || `订单 #${row.order_id}` }}
|
||||
</RouterLink>
|
||||
<small class="user-id">用户 ID: {{ row.user_id }}</small>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="渠道交易单号" min-width="190">
|
||||
<template #default="{ row }">
|
||||
<span class="channel-no">{{ row.channel_trade_no || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="异常与失败信息" min-width="170" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.error_message" class="error-msg">{{ row.error_message }}</span>
|
||||
<span v-else class="muted-text">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="创建时间" min-width="165">
|
||||
<template #default="{ row }">
|
||||
<span class="time-cell">{{ formatDateTime(row.created_at) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="90" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" :icon="View" @click="openDetail(row)">
|
||||
报文
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<AdminTablePagination
|
||||
v-if="total > 0"
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="currentPageSize"
|
||||
:total="total"
|
||||
@change="handlePageChange"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<!-- 报文详情弹窗 -->
|
||||
<el-dialog v-model="detailVisible" title="支付流水报文详情" width="680px" destroy-on-close>
|
||||
<div v-if="activePayment" class="payload-details">
|
||||
<div class="payload-block">
|
||||
<div class="payload-title">请求报文 Payload</div>
|
||||
<pre class="json-box"><code>{{ jsonText(activePayment.raw_request) }}</code></pre>
|
||||
</div>
|
||||
<div class="payload-block">
|
||||
<div class="payload-title">响应报文 Payload</div>
|
||||
<pre class="json-box"><code>{{ jsonText(activePayment.raw_response) }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.payment-detail h3 {
|
||||
margin: 18px 0 8px;
|
||||
font-size: 15px;
|
||||
.finance-page-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
padding: 0 4px 32px;
|
||||
}
|
||||
|
||||
.detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
/* ================= 头部卡片 ================= */
|
||||
.page-header-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
padding: 24px 28px;
|
||||
box-shadow:
|
||||
0 1px 3px rgba(15, 23, 42, 0.04),
|
||||
0 4px 12px rgba(15, 23, 42, 0.02);
|
||||
border: 1px solid rgba(226, 232, 240, 0.8);
|
||||
}
|
||||
|
||||
.header-main {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.title-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.eyebrow-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.8px;
|
||||
color: #059669;
|
||||
background: #ecfdf5;
|
||||
padding: 3px 10px;
|
||||
border-radius: 20px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 26px;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
margin: 0;
|
||||
font-size: 13.5px;
|
||||
color: #64748b;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.toolbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.detail-grid p {
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
/* ================= 核心指标卡片 ================= */
|
||||
.summary-metric-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.detail-grid span {
|
||||
display: block;
|
||||
.metric-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
padding: 18px 20px;
|
||||
border: 1px solid rgba(226, 232, 240, 0.8);
|
||||
box-shadow:
|
||||
0 1px 3px rgba(15, 23, 42, 0.04),
|
||||
0 4px 12px rgba(15, 23, 42, 0.02);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
transform 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.metric-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.metric-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
.metric-card--pay::before {
|
||||
background: linear-gradient(90deg, #10b981, #34d399);
|
||||
}
|
||||
|
||||
.metric-card--refund::before {
|
||||
background: linear-gradient(90deg, #f43f5e, #fb7185);
|
||||
}
|
||||
|
||||
.metric-card--total::before {
|
||||
background: linear-gradient(90deg, #6366f1, #818cf8);
|
||||
}
|
||||
|
||||
.metric-icon-wrap {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.metric-icon-wrap.emerald {
|
||||
background: #ecfdf5;
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.metric-icon-wrap.rose {
|
||||
background: #fff1f2;
|
||||
color: #f43f5e;
|
||||
}
|
||||
|
||||
.metric-icon-wrap.indigo {
|
||||
background: #eef2ff;
|
||||
color: #6366f1;
|
||||
}
|
||||
|
||||
.metric-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
font-size: 12.5px;
|
||||
font-weight: 500;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.metric-val {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
letter-spacing: -0.3px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.emerald-val {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.rose-val {
|
||||
color: #e11d48;
|
||||
}
|
||||
|
||||
.metric-sub-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.metric-sub-pill.success {
|
||||
background: #f0fdf4;
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.metric-sub-pill.danger {
|
||||
background: #fff1f2;
|
||||
color: #e11d48;
|
||||
}
|
||||
|
||||
.metric-sub-text {
|
||||
font-size: 11.5px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
/* ================= 筛选面板 ================= */
|
||||
.section-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
padding: 22px 24px;
|
||||
border: 1px solid rgba(226, 232, 240, 0.8);
|
||||
box-shadow:
|
||||
0 1px 3px rgba(15, 23, 42, 0.04),
|
||||
0 4px 12px rgba(15, 23, 42, 0.02);
|
||||
}
|
||||
|
||||
.filter-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 14px 16px;
|
||||
}
|
||||
|
||||
.filter-grid :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.filter-grid :deep(.el-form-item__label) {
|
||||
padding-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.detail-grid strong {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
.full-control {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
pre {
|
||||
max-height: 260px;
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
padding: 12px;
|
||||
/* ================= 表格卡片 ================= */
|
||||
.table-section-card {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
color: #059669;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.count-badge {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #059669;
|
||||
background: #ecfdf5;
|
||||
padding: 3px 10px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.custom-enterprise-table :deep(.el-table__header-wrapper th) {
|
||||
background-color: #f8fafc !important;
|
||||
color: #475569;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.custom-enterprise-table :deep(.el-table__body-wrapper td) {
|
||||
padding: 12px 0;
|
||||
font-size: 13px;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.mono-code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.provider-cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.provider-tag {
|
||||
width: fit-content;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pay-way {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.biz-type-text {
|
||||
font-size: 12.5px;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.amount-val {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 13.5px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.pay-val {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.refund-val {
|
||||
color: #e11d48;
|
||||
}
|
||||
|
||||
.status-pill {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-user-cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.order-link {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #3b82f6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.order-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.user-id {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.channel-no {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 11.5px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
font-size: 12px;
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.time-cell {
|
||||
font-size: 12px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.muted-text {
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
/* ================= 报文弹窗 ================= */
|
||||
.payload-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.payload-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #475569;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.json-box {
|
||||
background: #0f172a;
|
||||
color: #e2e8f0;
|
||||
border-radius: 8px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
padding: 12px 14px;
|
||||
font-size: 12px;
|
||||
max-height: 240px;
|
||||
overflow: auto;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user