Files
cz-web/src/views/finance/bill-detail.vue
2026-09-30 15:55:36 +08:00

296 lines
8.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, onMounted, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useRoute, useRouter } from 'vue-router'
import { AppButton, StatusTag } from '@/components'
// 页面容器:数据只经 store,不直接 import api
import { useFinanceStore } from '@/stores/modules/finance'
import type { BillStatus } from '@/types/business/finance'
import { formatMoney } from '@/utils/format'
import { toChannelLabel } from '@/utils/payMeta'
const route = useRoute()
const router = useRouter()
const financeStore = useFinanceStore()
const { currentBill } = storeToRefs(financeStore)
const billId = computed(() => String(route.params.id))
const STATUS_VARIANTS: Record<BillStatus, 'warning' | 'success' | 'info' | 'danger'> = {
待支付: 'warning',
已支付: 'success',
未到期: 'info',
已取消: 'danger',
}
async function load(): Promise<void> {
// 支付信息(渠道 / 时间 / 流水号)已由后端回写在账单本身上,无需再查支付结果
await financeStore.fetchDetail(billId.value)
}
function onPay(): void {
// 进收银台(确认支付):选支付方式 → 微信出码 / 支付宝跳转
void router.push({ path: '/finance/checkout', query: { ids: billId.value } })
}
watch(billId, () => {
void load()
})
onMounted(() => {
void load()
})
</script>
<template>
<div class="bill-detail">
<nav class="bill-detail__breadcrumb text-secondary">
<RouterLink to="/finance" class="link">
财务中心
</RouterLink>
<span> &gt; </span>
<RouterLink to="/finance/bills" class="link">
账单明细
</RouterLink>
<span> &gt; </span>
<span>账单详情</span>
</nav>
<template v-if="currentBill">
<section class="bill-detail__card card">
<div class="bill-detail__card-head">
<h3 class="bill-detail__card-title">
订单信息
</h3>
<StatusTag :label="currentBill.status" :variant="STATUS_VARIANTS[currentBill.status]" />
</div>
<div class="bill-detail__fields">
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">账单名称</span>
<span class="bill-detail__value">{{ currentBill.planName }}</span>
</div>
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">账单号</span>
<span class="bill-detail__value">{{ currentBill.billNo }}</span>
</div>
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">项目名称</span>
<span class="bill-detail__value">{{ currentBill.projectName }}</span>
</div>
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">订单金额</span>
<!-- 设计 31:金额随状态取色——已支付红 / 待支付橙 / 未到期深灰 -->
<span
class="bill-detail__value bill-detail__value--amount"
:class="{
'is-pending': currentBill.status === '待支付',
'is-idle': currentBill.status === '未到期' || currentBill.status === '已取消',
}"
>¥{{ formatMoney(currentBill.amount) }}</span>
</div>
</div>
<!-- 待支付:立即支付 -->
<div v-if="currentBill.status === '待支付'" class="bill-detail__pay">
<AppButton type="primary" @click="onPay">
立即支付
</AppButton>
</div>
<!-- 已支付:支付信息 -->
<template v-else-if="currentBill.status === '已支付'">
<div class="bill-detail__pay-info">
<h4 class="bill-detail__sub-title">
支付信息
</h4>
<div class="bill-detail__fields">
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">付款金额</span>
<span class="bill-detail__value bill-detail__value--amount">¥{{ formatMoney(currentBill.amount) }}</span>
</div>
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">支付方式</span>
<span class="bill-detail__value">{{ toChannelLabel(currentBill.payChannel) }}</span>
</div>
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">支付时间</span>
<span class="bill-detail__value">{{ currentBill.payTime ?? '—' }}</span>
</div>
<div class="bill-detail__field">
<span class="bill-detail__label text-secondary">交易流水号</span>
<span class="bill-detail__value">{{ currentBill.tradeNo ?? '—' }}</span>
</div>
</div>
</div>
</template>
<!-- 已取消 -->
<div v-else-if="currentBill.status === '已取消'" class="bill-detail__tip text-secondary">
该账单已取消,如有疑问请联系项目负责人。
</div>
<!-- 未到期:提示 -->
<div v-else class="bill-detail__tip text-secondary">
账单尚未到期,到期后可前往账单明细完成支付。
</div>
</section>
</template>
<p v-else class="bill-detail__empty text-secondary">
账单不存在或已下线
</p>
<div class="bill-detail__back">
<AppButton @click="router.push('/finance/bills')">
返回
</AppButton>
</div>
</div>
</template>
<style lang="less" scoped>
.bill-detail {
width: 100%;
max-width: @container-width;
margin: 0 auto;
padding: @spacing-lg @spacing-base @spacing-xxl;
// 设计 31:面包屑 13 设计px → 11px,前缀灰、当前页深灰
&__breadcrumb {
margin-bottom: @spacing-base;
font-size: 11px;
color: @text-color-disabled;
> span:last-child {
color: @text-color;
}
}
// 设计 31:白卡居中(对应设计三张窄卡的中轴布局),圆角 8、柔阴影
&__card {
max-width: 440px;
margin: 0 auto;
padding: @spacing-base 20px 20px;
border-radius: @radius-base;
background: @white;
box-shadow: @shadow-base;
}
&__card-head {
.flex(row, space-between, center);
margin-bottom: @spacing-base;
}
&__card-title {
font-size: 12px;
font-weight: 700;
color: @heading-color;
}
// 状态徽标压成设计稿的深色粗体状态词
:deep(.status-tag) {
padding: 0;
background: transparent;
color: @heading-color;
font-size: 12px;
font-weight: 700;
}
// 字段行:标签左(灰 11px)、值右(深色粗体)——设计 31 左右分栏
&__fields {
.flex(column, flex-start, stretch);
gap: 12px;
}
&__field {
.flex(row, space-between, center);
gap: @spacing-base;
font-size: 11px;
}
&__label {
flex-shrink: 0;
font-size: 11px;
}
&__value {
color: @heading-color;
font-weight: 600;
text-align: right;
word-break: break-all;
// 设计 31:付款金额 已支付 #EF4444 / 待支付 #F59E0B / 未到期深灰,18 设计px → 14px 粗体
&--amount {
font-size: 14px;
font-weight: 700;
color: @danger-color;
}
&.is-pending {
color: @finance-pending;
}
&.is-idle {
color: @heading-color;
}
}
&__pay {
margin-top: @spacing-base;
}
&__pay-info {
margin-top: @spacing-base;
padding-top: @spacing-base;
border-top: 1px solid @project-divider;
}
&__sub-title {
margin-bottom: 12px;
font-size: 11px;
font-weight: 700;
color: @heading-color;
}
&__tip {
margin-top: @spacing-base;
padding: 12px;
border-radius: @radius-sm;
background: @bg-color;
font-size: 11px;
}
&__empty {
padding: @spacing-xl 0;
text-align: center;
font-size: 11px;
}
&__back {
max-width: 440px;
margin: @spacing-base auto 0;
}
// 设计 31/32:按钮蓝底 #024FFF(返回/立即支付同色)
:deep(.app-button--primary) {
background: @primary-strong;
&:hover {
background: @primary-color;
}
}
&__back :deep(.app-button--default) {
border-color: @primary-strong;
background: @primary-strong;
color: @white;
&:hover {
border-color: @primary-color;
background: @primary-color;
color: @white;
}
}
}
</style>