342 lines
9.6 KiB
Vue
342 lines
9.6 KiB
Vue
<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
|
||
v-if="props.isRenter"
|
||
title="实际纯币原价"
|
||
:value="`¥${money(amountYuan(checkout.pure_coin_amount_cent))}`"
|
||
/>
|
||
<van-cell
|
||
v-if="props.isRenter && Number(checkout.pure_coin_discount_cent || 0) > 0"
|
||
title="成长等级优惠"
|
||
:value="`-¥${money(amountYuan(checkout.pure_coin_discount_cent))}`"
|
||
value-class="green-text"
|
||
/>
|
||
<van-cell
|
||
v-if="props.isRenter"
|
||
title="折后纯币金额"
|
||
:value="`¥${money(amountYuan(checkout.pure_coin_payable_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 title="哈夫币实际消耗" :value="`${checkout.coin_consumed_m}M`" />
|
||
<van-cell
|
||
v-if="Number(checkout.overshoot_amount_cent || 0) > 0"
|
||
title="打超金额(从押金)"
|
||
:value="`¥${money(amountYuan(checkout.overshoot_amount_cent))}`"
|
||
value-class="red-text"
|
||
/>
|
||
<van-cell
|
||
v-if="Number(checkout.shortfall_cent || 0) > 0"
|
||
title="押金不足差额"
|
||
:value="`¥${money(amountYuan(checkout.shortfall_cent))}`"
|
||
value-class="red-text"
|
||
label="无法自动完结,请协商修改或发起争议"
|
||
/>
|
||
<van-cell
|
||
v-if="checkout.round_count"
|
||
title="协商轮次"
|
||
:value="`第 ${checkout.round_count}/${checkout.max_rounds || 6} 轮`"
|
||
/>
|
||
<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="props.isRenter && props.order.status === 'completed'"
|
||
title="本单成长积分"
|
||
:label="`积分基数 ¥${money(amountYuan(props.order.growth_points_basis_cent))}`"
|
||
:value="`+${Number(props.order.growth_points_awarded || 0)}`"
|
||
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 v-if="props.isRenter" class="summary-row">
|
||
<span>实际纯币原价</span>
|
||
<strong>¥{{ money(amountYuan(checkout.pure_coin_amount_cent)) }}</strong>
|
||
</div>
|
||
<div
|
||
v-if="props.isRenter && Number(checkout.pure_coin_discount_cent || 0) > 0"
|
||
class="summary-row"
|
||
>
|
||
<span>成长等级优惠</span>
|
||
<strong class="amount">-¥{{ money(amountYuan(checkout.pure_coin_discount_cent)) }}</strong>
|
||
</div>
|
||
<div v-if="props.isRenter" class="summary-row">
|
||
<span>折后纯币金额</span>
|
||
<strong>¥{{ money(amountYuan(checkout.pure_coin_payable_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 class="summary-row">
|
||
<span>哈夫币实际消耗</span>
|
||
<strong>{{ checkout.coin_consumed_m }}M</strong>
|
||
</div>
|
||
<div v-if="Number(checkout.overshoot_amount_cent || 0) > 0" class="summary-row">
|
||
<span>打超金额(按比例从押金扣)</span>
|
||
<strong class="warning">¥{{ money(amountYuan(checkout.overshoot_amount_cent)) }}</strong>
|
||
</div>
|
||
<div v-if="Number(checkout.shortfall_cent || 0) > 0" class="summary-row">
|
||
<span>押金不足差额(禁止自动完结)</span>
|
||
<strong class="warning">¥{{ money(amountYuan(checkout.shortfall_cent)) }}</strong>
|
||
</div>
|
||
<div v-if="checkout.round_count" class="summary-row">
|
||
<span>协商轮次</span>
|
||
<strong>第 {{ checkout.round_count }}/{{ checkout.max_rounds || 6 }} 轮</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="props.isRenter && props.order.status === 'completed'"
|
||
class="summary-row highlight"
|
||
>
|
||
<span>
|
||
本单成长积分(基数 ¥{{ money(amountYuan(props.order.growth_points_basis_cent)) }})
|
||
</span>
|
||
<strong class="amount">+{{ Number(props.order.growth_points_awarded || 0) }}</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: 16px;
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.section-header h2 {
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
color: #1f2937;
|
||
margin: 0;
|
||
}
|
||
|
||
.checkout-summary-card {
|
||
display: grid;
|
||
gap: 0;
|
||
padding: 10px 14px;
|
||
background: #ffffff;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.summary-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
padding: 6px 0;
|
||
border-bottom: 1px solid #f3f4f6;
|
||
min-height: 28px;
|
||
}
|
||
|
||
.summary-row:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.summary-row.highlight {
|
||
margin-top: 4px;
|
||
padding: 8px 10px;
|
||
background: #f0fdf4;
|
||
border: 1px solid #bbf7d0;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.summary-row span {
|
||
font-size: 12px;
|
||
color: #64748b;
|
||
line-height: 1.35;
|
||
}
|
||
|
||
.summary-row strong {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
color: #1f2937;
|
||
line-height: 1.3;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.summary-row strong em {
|
||
font-style: normal;
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
color: #2563eb;
|
||
}
|
||
|
||
.summary-row strong.amount {
|
||
color: #16a34a;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.summary-row strong.warning {
|
||
color: #dc2626;
|
||
}
|
||
|
||
.summary-note {
|
||
margin-top: 4px;
|
||
padding: 8px 10px;
|
||
background: #f8fafc;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.summary-note.warning {
|
||
background: #fff7ed;
|
||
}
|
||
|
||
.summary-note label {
|
||
display: block;
|
||
margin-bottom: 2px;
|
||
color: #64748b;
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.summary-note p {
|
||
margin: 0;
|
||
color: #1f2937;
|
||
font-size: 12px;
|
||
line-height: 1.45;
|
||
white-space: pre-wrap;
|
||
}
|
||
|
||
.card-section {
|
||
margin: 10px 12px 0;
|
||
padding: 10px 12px;
|
||
background: #ffffff;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 14px;
|
||
font-weight: 800;
|
||
color: #182232;
|
||
margin: 0 0 6px;
|
||
}
|
||
|
||
:deep(.red-text) {
|
||
color: #ef4444;
|
||
font-weight: 700;
|
||
}
|
||
|
||
:deep(.green-text) {
|
||
color: #16a34a;
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* 移动端 cell 行高也收紧一点 */
|
||
.card-section :deep(.van-cell) {
|
||
padding-top: 8px;
|
||
padding-bottom: 8px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.card-section :deep(.van-cell__title) {
|
||
font-size: 12px;
|
||
}
|
||
</style>
|