拆分订单详情结账逻辑

This commit is contained in:
yml
2026-06-09 22:07:55 +08:00
parent d68020db4e
commit 3bbe356c3f
9 changed files with 1445 additions and 1402 deletions
@@ -0,0 +1,240 @@
<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>