shop-web/src/pages/order/index.vue

232 lines
5.2 KiB
Vue
Raw Normal View History

2025-03-31 09:42:26 +08:00
<script setup lang="ts">
import { onMounted } from 'vue'
import { OrderGoods, useOrderStore } from '@/pinia/stores/order'
import { useRoute, useRouter } from 'vue-router'
import { openCabinetApi } from '@/common/apis/shop'
import { showSuccessToast, showFailToast } from 'vant'
import { ref } from 'vue'
2025-03-31 09:42:26 +08:00
const orderStore = useOrderStore()
const route = useRoute()
const router = useRouter()
2025-03-31 09:42:26 +08:00
const statusMap: Record<number, string> = {
1: '待付款',
2: '已付款',
3: '已发货',
4: '已完成',
5: '已取消'
}
const getStatusText = (status: number) => {
return statusMap[status] || '未知状态'
}
const orderId = ref(parseInt(String(route.params.id)))
// 监听路由参数变化
watch(() => route.params.id, (newId) => {
orderId.value = parseInt(String(newId))
})
const order = computed(() => {
return orderStore.orders.find(o => o.orderId === orderId.value)
})
const orderGoodsStatusMap: Record<number, string> = {
5: '审核中',
2: '已退货',
6: '退货未通过'
}
const getOrderGoodsStatusText = (status: number) => {
return orderGoodsStatusMap[status] || ''
}
const handleRefund = (item: any) => {
router.push({
path: '/approval/submit',
query: {
orderGoodsId: item.orderGoods.orderGoodsId,
orderId: orderId.value,
}
})
}
2025-03-31 09:42:26 +08:00
onMounted(() => {
if (!order.value) {
// 订单不存在处理
2025-03-31 09:42:26 +08:00
}
})
const isButtonDisabled = ref<Record<number, boolean>>({})
async function handleOpenCabinet(item: OrderGoods) {
const orderGoodsId = item.orderGoods.orderGoodsId
isButtonDisabled.value[orderGoodsId] = true
try {
const result = await openCabinetApi(orderId.value, orderGoodsId)
if (result.code !== 0) {
showFailToast(result.msg || '开启失败,请稍后重试')
return
}
showSuccessToast('柜口已成功开启')
} catch (error) {
showFailToast('开启失败,请稍后重试')
} finally {
setTimeout((currentId) => {
delete isButtonDisabled.value[currentId]
}, 5000, orderGoodsId)
}
}
2025-03-31 09:42:26 +08:00
</script>
<template>
<div class="order-detail" v-if="order">
<h2>订单详情</h2>
<div class="order-info">
<p>订单号: {{ order.orderId }}</p>
<p>状态: {{ getStatusText(order.status) }}</p>
<p>总价: ¥{{ order.totalAmount }}</p>
<p>支付时间: {{ order.payTime }}</p>
</div>
<van-cell-group class="goods-list">
<van-cell
v-for="(item, index) in order.goodsList"
:key="index"
class="goods-item"
>
<template #icon>
<van-image
:src="item.goodsInfo.coverImg"
width="80"
height="80"
class="product-image"
/>
</template>
<div class="product-info">
<div class="product-name-price">
<div class="product-name van-ellipsis">
{{ item.goodsInfo.goodsName }}
</div>
<div class="product-price">
¥{{ item.orderGoods.price.toFixed(2) }}
</div>
2025-03-31 09:42:26 +08:00
</div>
<div class="action-row">
<p>数量: {{ item.orderGoods.quantity }}</p>
<p>小计: ¥{{ (item.orderGoods.price * item.orderGoods.quantity).toFixed(2) }}</p>
<div class="button-group">
<van-button
v-if="[1,5].includes(item.orderGoods.status)"
type="primary"
size="small"
@click="handleOpenCabinet(item)"
:disabled="isButtonDisabled[item.orderGoods.orderGoodsId]"
>
打开柜子
</van-button>
<van-button
v-if="item.orderGoods.status === 1"
type="primary"
size="small"
@click="handleRefund(item)"
>
退还商品
</van-button>
</div>
</div>
<span
v-if="[2,5,6].includes(item.orderGoods.status)"
class="status-text"
:class="`status-${item.orderGoods.status}`"
>
{{ getOrderGoodsStatusText(item.orderGoods.status) }}
</span>
2025-03-31 09:42:26 +08:00
</div>
</van-cell>
</van-cell-group>
</div>
<div v-else class="not-found">
订单不存在或已失效
</div>
</template>
<style scoped>
.order-detail {
padding: 20px;
}
.order-info {
padding: 15px;
margin-bottom: 20px;
background: #f5f5f5;
border-radius: 8px;
}
.goods-list {
padding: 15px;
background: #fff;
border-radius: 8px;
}
.goods-item {
display: flex;
padding: 15px 0;
border-bottom: 1px solid #f5f5f5;
}
goods-item:last-child {
border-bottom: none;
}
goods-item img {
width: 100px;
height: 100px;
object-fit: cover;
margin-right: 15px;
}
goods-info {
flex: 1;
}
.product-name-price {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.product-name {
flex: 1;
margin-right: 10px;
}
.product-price {
color: #ee0a24;
font-weight: 500;
}
2025-03-31 09:42:26 +08:00
.not-found {
padding: 40px;
text-align: center;
color: #999;
}
.button-group {
display: flex;
justify-content: flex-end;
gap: 8px;
width: 100%;
}
.action-row {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
}
2025-03-31 09:42:26 +08:00
</style>