233 lines
6.7 KiB
Vue
233 lines
6.7 KiB
Vue
<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> > </span>
|
||
<RouterLink to="/finance/bills" class="link">
|
||
账单明细
|
||
</RouterLink>
|
||
<span> > </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>
|
||
<span class="bill-detail__value bill-detail__value--amount">¥{{ 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 {
|
||
padding-top: @spacing-lg;
|
||
padding-bottom: @spacing-xxl;
|
||
|
||
&__breadcrumb {
|
||
margin-bottom: @spacing-base;
|
||
font-size: @font-size-base;
|
||
}
|
||
|
||
&__card {
|
||
padding: @spacing-lg;
|
||
border-radius: @radius-lg;
|
||
background: @white;
|
||
box-shadow: @shadow-base;
|
||
}
|
||
|
||
&__card-head {
|
||
.flex(row, space-between, center);
|
||
margin-bottom: @spacing-base;
|
||
}
|
||
|
||
&__card-title {
|
||
font-size: @font-size-lg;
|
||
font-weight: 600;
|
||
color: @heading-color;
|
||
}
|
||
|
||
&__fields {
|
||
.flex(column, flex-start);
|
||
gap: @spacing-sm;
|
||
}
|
||
|
||
&__field {
|
||
.flex(row, flex-start, center);
|
||
gap: @spacing-base;
|
||
font-size: @font-size-base;
|
||
}
|
||
|
||
&__label {
|
||
width: 80px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
&__value {
|
||
color: @heading-color;
|
||
|
||
&--amount {
|
||
font-weight: 600;
|
||
color: @danger-color;
|
||
}
|
||
}
|
||
|
||
&__pay {
|
||
margin-top: @spacing-lg;
|
||
}
|
||
|
||
&__pay-info {
|
||
margin-top: @spacing-lg;
|
||
padding-top: @spacing-base;
|
||
border-top: 1px solid @border-color;
|
||
}
|
||
|
||
&__sub-title {
|
||
margin-bottom: @spacing-sm;
|
||
font-size: @font-size-base;
|
||
font-weight: 600;
|
||
color: @heading-color;
|
||
}
|
||
|
||
&__tip {
|
||
margin-top: @spacing-lg;
|
||
padding: @spacing-base;
|
||
border-radius: @radius-base;
|
||
background: @bg-color;
|
||
font-size: @font-size-base;
|
||
}
|
||
|
||
&__empty {
|
||
padding: @spacing-xl 0;
|
||
text-align: center;
|
||
font-size: @font-size-base;
|
||
}
|
||
|
||
&__back {
|
||
margin-top: @spacing-lg;
|
||
}
|
||
}
|
||
</style>
|