This commit is contained in:
2026-08-15 09:47:24 +08:00
parent b62b16cca7
commit 709dacad98
+11 -28
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { CircleDollarSign, Eye, RefreshCcw, Search, WalletCards } from '@lucide/vue'
import { CircleDollarSign, Eye, RefreshCcw, Search } from '@lucide/vue'
import { ApiError } from '@/api/http'
import { getMerchantFinanceBill, getMerchantFinanceBills, getMerchantFinanceReceipts } from '../api/finance'
import type { FinanceBillDetail, FinanceBillQuery, FinanceBillStatus, FinanceBillSummary } from '../contracts'
@@ -109,19 +109,10 @@ onMounted(() => { void loadBills(1) })
<template>
<div class="finance-bills-page">
<header class="page-heading">
<div>
<p class="eyebrow">财务结算</p>
<h1>客户账单</h1>
<p>查看本企业账单、收款记录和未收余额。币种固定为 RMB。</p>
</div>
<WalletCards :size="34" stroke-width="1.5" aria-hidden="true" />
</header>
<section class="summary-grid" aria-label="账单汇总">
<article class="summary-card"><span>账单总额</span><strong>¥ {{ formatAmount(totals.billed) }}</strong><small>CNY</small></article>
<article class="summary-card"><span>已收金额</span><strong>¥ {{ formatAmount(totals.received) }}</strong><small>CNY</small></article>
<article class="summary-card summary-card--warning"><span>未收余额</span><strong>¥ {{ formatAmount(totals.outstanding) }}</strong><small>请按账单核对</small></article>
<section class="finance-summary" aria-label="账单汇总">
<span>账单总额 <strong>¥ {{ formatAmount(totals.billed) }}</strong></span>
<span>已收 <strong>¥ {{ formatAmount(totals.received) }}</strong></span>
<span class="amount-warning">未收 <strong>¥ {{ formatAmount(totals.outstanding) }}</strong></span>
</section>
<section class="content-card">
@@ -161,9 +152,8 @@ onMounted(() => { void loadBills(1) })
<div v-loading="detailLoading" class="detail-content">
<div v-if="detailError" class="state-panel state-panel--error" role="alert"><p>{{ detailError }}</p><el-button @click="loadDetail(selectedBillId)">重试</el-button></div>
<template v-else-if="detail">
<div class="detail-heading"><div><p class="eyebrow">{{ detail.billNo }}</p><h2>账单明细</h2></div><el-tag :type="statusType(detail.status)">{{ statusLabel(detail.status) }}</el-tag></div>
<dl class="detail-meta"><div><dt>出账日期</dt><dd>{{ formatDate(detail.issueDate) }}</dd></div><div><dt>到期日</dt><dd>{{ formatDate(detail.dueDate) }}</dd></div><div><dt>币种</dt><dd>RMB/CNY</dd></div><div><dt>未收余额</dt><dd class="amount-warning">¥ {{ formatAmount(detail.outstandingAmount) }}</dd></div></dl>
<section class="detail-section"><h3>费用明细</h3><el-table :data="detail.lines" size="small"><el-table-column prop="orderId" label="订单ID" min-width="120" /><el-table-column prop="feeNo" label="费用来源编号" min-width="140" /><el-table-column prop="feeName" label="费用项目" min-width="130" /><el-table-column label="金额" width="130" align="right"><template #default="{ row }">¥ {{ formatAmount(row.amount) }}</template></el-table-column></el-table></section>
<div class="detail-heading"><div><h2>{{ detail.billNo }}</h2><p>出账 {{ formatDate(detail.issueDate) }} · 到期 {{ formatDate(detail.dueDate) }} · 未收 <strong class="amount-warning">¥ {{ formatAmount(detail.outstandingAmount) }}</strong></p></div><el-tag :type="statusType(detail.status)">{{ statusLabel(detail.status) }}</el-tag></div>
<section class="detail-section"><h3>费用明细</h3><el-table :data="detail.lines" size="small"><el-table-column prop="feeName" label="费用项目" min-width="180" /><el-table-column label="金额" width="130" align="right"><template #default="{ row }">¥ {{ formatAmount(row.amount) }}</template></el-table-column></el-table></section>
<section class="detail-section"><h3>收款记录</h3><el-table v-if="detail.receipts.length" :data="detail.receipts" size="small"><el-table-column prop="receivedAt" label="收款日期" width="110"><template #default="{ row }">{{ formatDate(row.receivedAt) }}</template></el-table-column><el-table-column prop="receiptNo" label="收款编号" min-width="130" /><el-table-column label="本次金额" width="130" align="right"><template #default="{ row }">¥ {{ formatAmount(row.allocatedAmount) }}</template></el-table-column><el-table-column prop="method" label="方式" min-width="100" /></el-table><div v-else class="sub-empty">暂无收款记录</div></section>
<p class="readonly-notice">账单金额和收款记录仅供查看。如有疑问,请线下联系平台财务。</p>
</template>
@@ -173,21 +163,14 @@ onMounted(() => { void loadBills(1) })
</template>
<style scoped>
.finance-bills-page { display: flex; flex-direction: column; gap: 16px; }
.page-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; color: var(--navy); }
.page-heading h1, .detail-heading h2 { margin: 2px 0 5px; font-size: 24px; }
.page-heading p:not(.eyebrow) { margin: 0; color: var(--muted); font-size: 13px; }
.eyebrow { margin: 0; color: var(--primary); font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.summary-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.summary-card { display: flex; min-height: 106px; flex-direction: column; justify-content: center; gap: 7px; padding: 18px 20px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface, #fff); }
.summary-card span, .summary-card small { color: var(--muted); font-size: 12px; }.summary-card strong { color: var(--navy); font-size: 23px; }.summary-card--warning strong, .amount-warning { color: #b45309; }
.finance-bills-page { display: flex; flex-direction: column; gap: 12px; }
.finance-summary { display: flex; flex-wrap: wrap; gap: 8px 26px; color: var(--muted); font-size: 13px; }.finance-summary strong { margin-left: 6px; color: var(--navy); font-size: 18px; }.amount-warning, .amount-warning strong { color: #b45309; }
.content-card { min-width: 0; padding: 16px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface, #fff); }
.filter-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }.keyword-input { width: 260px; }.status-select { width: 140px; }
.finance-table { width: 100%; }.finance-table :deep(.el-button) { display: inline-flex; align-items: center; gap: 4px; }
.state-panel { display: flex; min-height: 180px; align-items: center; justify-content: center; gap: 12px; flex-direction: column; color: var(--muted); text-align: center; }.state-panel p { margin: 0; }.state-panel--error { color: #b42318; background: #fff8f7; border: 1px solid #f5c2bd; border-radius: 6px; }
.table-empty { display: flex; align-items: center; flex-direction: column; gap: 8px; padding: 42px 12px; color: var(--muted); }.table-empty strong { color: var(--navy); }.table-empty span { font-size: 12px; }
.pagination-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 14px; color: var(--muted); font-size: 12px; }
.detail-content { min-height: 300px; }.detail-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }.detail-meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 20px 0; }.detail-meta div { padding: 12px; border-radius: 6px; background: #f7fafb; }.detail-meta dt { color: var(--muted); font-size: 11px; }.detail-meta dd { margin: 5px 0 0; color: var(--navy); font-size: 14px; font-weight: 600; }.detail-section { margin-top: 22px; }.detail-section h3 { margin: 0 0 10px; color: var(--navy); font-size: 14px; }.sub-empty { padding: 22px; color: var(--muted); font-size: 12px; text-align: center; background: #f7fafb; }.readonly-notice { margin: 22px 0 0; padding: 11px 12px; color: #45615d; background: #edf6f4; font-size: 12px; }
@media (max-width: 720px) { .summary-grid { grid-template-columns: 1fr; }.keyword-input, .status-select { width: 100%; }.filter-bar > .el-button { flex: 1; }.content-card { padding: 12px; }.pagination-row { align-items: flex-start; flex-direction: column; }.page-heading h1 { font-size: 21px; } }
@media (max-width: 420px) { .detail-meta { grid-template-columns: 1fr; }.page-heading > svg { display: none; } }
.detail-content { min-height: 300px; }.detail-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }.detail-heading h2 { margin: 0 0 5px; color: var(--navy); font-size: 18px; }.detail-heading p { margin: 0; color: var(--muted); font-size: 13px; }.detail-section { margin-top: 22px; }.detail-section h3 { margin: 0 0 10px; color: var(--navy); font-size: 14px; }.sub-empty { padding: 22px; color: var(--muted); font-size: 12px; text-align: center; background: #f7fafb; }.readonly-notice { margin: 22px 0 0; padding: 11px 12px; color: #45615d; background: #edf6f4; font-size: 12px; }
@media (max-width: 720px) { .keyword-input, .status-select { width: 100%; }.filter-bar > .el-button { flex: 1; }.content-card { padding: 12px; }.pagination-row { align-items: flex-start; flex-direction: column; }.finance-summary { align-items: flex-start; flex-direction: column; gap: 6px; } }
</style>