Files
hfb_sys/frontend/src/features/orders/components/OrderCheckoutSummary.vue
T
2026-06-09 22:07:55 +08:00

241 lines
5.7 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 } from 'vue'
import type { Order } from '@/features/orders/api/orders'
import { amountYuan, money } from '@/features/orders/composables/useOrderSnapshot'
const props = withDefaults(
defineProps<{
variant?: 'desktop' | 'mobile'
order: Order
isOwner: boolean
isRenter: boolean
}>(),
{ variant: 'desktop' }
)
const checkout = computed(() => props.order.checkout)
</script>
<template>
<section v-if="checkout && props.variant === 'mobile'" class="card-section">
<h3 class="section-title">结账结算账单</h3>
<van-cell-group inset :border="false">
<van-cell
title="实际结算租金"
:value="`¥${money(amountYuan(checkout.display_amount_cent))}`"
/>
<van-cell
title="押金总额"
:label="
amountYuan(props.order.deposit_waived_amount_cent) > 0
? `已免押 ¥${money(amountYuan(props.order.deposit_waived_amount_cent))}`
: ''
"
:value="`¥${money(amountYuan(checkout.deposit_amount_cent))}`"
/>
<van-cell
title="额外消耗品已用"
:value="`¥${money(amountYuan(checkout.consumable_amount_cent))}`"
/>
<van-cell
title="押金赔付扣除"
:value="`¥${money(amountYuan(checkout.deposit_deduct_amount_cent))}`"
value-class="red-text"
/>
<van-cell
v-if="props.isRenter"
title="退还租客"
:value="`¥${money(amountYuan(checkout.renter_refund_amount_cent))}`"
value-class="green-text"
/>
<van-cell
v-if="props.isOwner"
title="号主最终收入"
:value="`¥${money(amountYuan(checkout.owner_income_amount_cent))}`"
value-class="green-text"
/>
<van-cell v-if="checkout.content" title="结账备注" :label="checkout.content" />
<van-cell
v-if="checkout.owner_adjustment_reason"
title="号主修正原因"
:label="checkout.owner_adjustment_reason"
/>
</van-cell-group>
</section>
<div v-else-if="checkout" class="info-section">
<div class="section-header">
<h2>结账明细</h2>
</div>
<div class="checkout-summary-card">
<div class="summary-row">
<span>实际结算租金</span>
<strong>¥{{ money(amountYuan(checkout.display_amount_cent)) }}</strong>
</div>
<div class="summary-row">
<span>预收押金</span>
<strong>
¥{{ money(amountYuan(checkout.deposit_amount_cent)) }}
<em v-if="amountYuan(props.order.deposit_waived_amount_cent) > 0">
已免押 ¥{{ money(amountYuan(props.order.deposit_waived_amount_cent)) }}
</em>
</strong>
</div>
<div class="summary-row">
<span>额外消耗品已用</span>
<strong class="warning">¥{{ money(amountYuan(checkout.consumable_amount_cent)) }}</strong>
</div>
<div class="summary-row">
<span>押金赔付扣除</span>
<strong class="warning">
¥{{ money(amountYuan(checkout.deposit_deduct_amount_cent)) }}
</strong>
</div>
<div v-if="props.isRenter" class="summary-row highlight">
<span>退还租客未使用租金 + 剩余押金</span>
<strong class="amount">¥{{ money(amountYuan(checkout.renter_refund_amount_cent)) }}</strong>
</div>
<div v-if="props.isOwner" class="summary-row highlight">
<span>号主最终收入租金 + 押金赔付</span>
<strong class="amount">¥{{ money(amountYuan(checkout.owner_income_amount_cent)) }}</strong>
</div>
<div v-if="checkout.content" class="summary-note">
<label>说明</label>
<p>{{ checkout.content }}</p>
</div>
<div v-if="checkout.owner_adjustment_reason" class="summary-note warning">
<label>修正原因</label>
<p>{{ checkout.owner_adjustment_reason }}</p>
</div>
</div>
</div>
</template>
<style scoped>
.info-section {
margin-bottom: 32px;
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.section-header h2 {
font-size: 20px;
font-weight: 700;
color: #1f2937;
margin: 0;
}
.checkout-summary-card {
display: grid;
gap: 12px;
padding: 24px;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 12px;
}
.summary-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid #f3f4f6;
}
.summary-row:last-child {
border-bottom: none;
}
.summary-row.highlight {
padding: 16px;
background: #f0fdf4;
border: 1px solid #bbf7d0;
border-radius: 8px;
}
.summary-row span {
font-size: 14px;
color: #64748b;
}
.summary-row strong {
display: flex;
flex-direction: column;
align-items: flex-end;
font-size: 18px;
font-weight: 700;
color: #1f2937;
}
.summary-row strong em {
font-style: normal;
font-size: 12px;
font-weight: 500;
color: #2563eb;
}
.summary-row strong.amount {
color: #16a34a;
}
.summary-row strong.warning {
color: #dc2626;
}
.summary-note {
padding: 16px;
background: #f8fafc;
border-radius: 8px;
}
.summary-note.warning {
background: #fff7ed;
}
.summary-note label {
display: block;
margin-bottom: 8px;
color: #64748b;
font-size: 13px;
font-weight: 700;
}
.summary-note p {
margin: 0;
color: #1f2937;
font-size: 14px;
line-height: 1.6;
white-space: pre-wrap;
}
.card-section {
margin: 12px 12px 0;
padding: 14px;
background: #ffffff;
border-radius: 8px;
}
.section-title {
font-size: 15px;
font-weight: 800;
color: #182232;
margin: 0 0 12px;
}
:deep(.red-text) {
color: #ef4444;
font-weight: 700;
}
:deep(.green-text) {
color: #16a34a;
font-weight: 700;
}
</style>