453 lines
10 KiB
Vue
453 lines
10 KiB
Vue
<template>
|
||
<view class="order-detail" v-if="order">
|
||
<!-- 自定义导航栏 -->
|
||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="custom-navbar__content" :style="{ height: navBarHeight + 'px' }">
|
||
<image class="custom-navbar__back" src="/static/ic_back.png" mode="aspectFit" @click="goBack" />
|
||
<text class="custom-navbar__title">订单详情</text>
|
||
<view class="custom-navbar__placeholder" />
|
||
</view>
|
||
</view>
|
||
<view :style="{ height: (statusBarHeight + navBarHeight) + 'px' }" />
|
||
|
||
<!-- 商品列表 -->
|
||
<view class="section product-section">
|
||
<view class="order-item" v-for="item in orderItems" :key="item.id">
|
||
<image class="order-item__img" :src="getItemImage(item)" mode="aspectFill" />
|
||
<view class="order-item__info">
|
||
<text class="order-item__name">{{ item.product.name }}</text>
|
||
<view class="order-item__specs">
|
||
<view class="spec-row">
|
||
<text v-if="item.specData.modelName">款号:{{ item.specData.modelName }}</text>
|
||
<text v-if="item.specData.fineness">商品型号:{{ item.specData.fineness }}</text>
|
||
</view>
|
||
<view class="spec-row">
|
||
<text v-if="item.specData.mainStone">成色:{{ item.specData.mainStone }}</text>
|
||
<text v-if="item.specData.subStone">副石:{{ item.specData.subStone }}</text>
|
||
</view>
|
||
<view class="spec-row">
|
||
<text v-if="item.specData.ringSize">主石:{{ item.specData.ringSize }}</text>
|
||
<text v-if="item.specData.goldTotalWeight">手寸:{{ item.specData.goldTotalWeight }}</text>
|
||
</view>
|
||
<view class="spec-row">
|
||
<text v-if="item.specData.goldNetWeight">金料总重:{{ item.specData.goldNetWeight }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="order-item__bottom">
|
||
<text class="order-item__price">¥{{ item.unitPrice }}元</text>
|
||
<text class="order-item__qty">×{{ item.quantity }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单信息 -->
|
||
<view class="section">
|
||
<view class="info-row">
|
||
<text class="info-label">订单号</text>
|
||
<text class="info-value">{{ order.orderNo }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">商品价格总计:</text>
|
||
<text class="info-value">¥{{ order.totalPrice }}</text>
|
||
</view>
|
||
<view v-if="order.shippingCompany" class="info-row">
|
||
<text class="info-label">物流公司</text>
|
||
<text class="info-value">{{ order.shippingCompany }}</text>
|
||
</view>
|
||
<view v-if="order.shippingNo" class="info-row">
|
||
<text class="info-label">物流单号</text>
|
||
<view style="display:flex;align-items:center;gap:16rpx;">
|
||
<text class="info-value">{{ order.shippingNo }}</text>
|
||
<text class="copy-btn" @click="copyShippingNo(order.shippingNo)">复制</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 提示信息 -->
|
||
<view class="section tip-section">
|
||
<text class="tip-section__title">您已成功下单!</text>
|
||
<view class="tip-section__body">
|
||
<text>客服电话(微信): 15920028399</text>
|
||
<text>交易方式: 门店交易、微信、支付宝、银行卡转账</text>
|
||
<text>公司地址: 水贝二路贝丽花园21栋1楼叶生珠宝请</text>
|
||
</view>
|
||
<text class="tip-section__footer">请点击下面联系客服出货吧</text>
|
||
</view>
|
||
|
||
<!-- 取消订单 -->
|
||
<view class="section cancel-section" v-if="order.status === 'pending'">
|
||
<text class="cancel-btn" @click="handleCancel">取消订单</text>
|
||
</view>
|
||
|
||
<!-- 收货信息 -->
|
||
<view class="receiver-section">
|
||
<view class="receiver-row">
|
||
<image class="receiver-icon" src="/static/ic_address2.png" mode="aspectFit" />
|
||
<text>{{ order.receiverAddress || '我的地址' }}</text>
|
||
</view>
|
||
<view class="receiver-row">
|
||
<image class="receiver-icon" src="/static/ic_phone.png" mode="aspectFit" />
|
||
<text>{{ order.receiverPhone || '我的手机号' }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部栏 -->
|
||
<view class="bottom-bar">
|
||
<view class="bottom-bar__left">
|
||
<text class="bottom-bar__label">合计:</text>
|
||
<text class="bottom-bar__price">¥{{ order.totalPrice }}</text>
|
||
</view>
|
||
<view class="bottom-bar__btn" @click="contactService">联系客服</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue'
|
||
// @ts-ignore
|
||
import { onShow } from '@dcloudio/uni-app'
|
||
import type { Order, OrderItem } from '../../types'
|
||
import { getOrderDetail, cancelOrder } from '../../api/order'
|
||
import { useOrderStore } from '../../store/order'
|
||
import { BASE_URL } from '../../utils/request'
|
||
|
||
const orderStore = useOrderStore()
|
||
const order = ref<Order | null>(null)
|
||
const orderItems = ref<OrderItem[]>([])
|
||
const orderId = ref(0)
|
||
|
||
const statusBarHeight = ref(20)
|
||
const navBarHeight = ref(44)
|
||
try {
|
||
const sysInfo = uni.getSystemInfoSync()
|
||
statusBarHeight.value = sysInfo.statusBarHeight || 20
|
||
// #ifdef MP-WEIXIN
|
||
const menuBtn = uni.getMenuButtonBoundingClientRect()
|
||
navBarHeight.value = (menuBtn.top - (sysInfo.statusBarHeight || 20)) * 2 + menuBtn.height
|
||
// #endif
|
||
} catch { /* fallback */ }
|
||
|
||
function goBack() {
|
||
uni.navigateBack({ delta: 1 })
|
||
}
|
||
|
||
function fullUrl(path : string) : string {
|
||
if (!path) return ''
|
||
if (path.startsWith('http')) return path
|
||
return BASE_URL + path
|
||
}
|
||
|
||
function getItemImage(item : OrderItem) : string {
|
||
const imgs = item.product?.bannerImages
|
||
if (imgs && imgs.length > 0) return fullUrl(imgs[0])
|
||
const thumb = (item.product as any)?.thumb
|
||
if (thumb) return fullUrl(thumb)
|
||
return ''
|
||
}
|
||
|
||
onMounted(() => {
|
||
const pages = getCurrentPages()
|
||
const currentPage = pages[pages.length - 1] as { options ?: { id ?: string } }
|
||
orderId.value = Number(currentPage.options?.id)
|
||
if (orderId.value) loadOrder(orderId.value)
|
||
})
|
||
|
||
onShow(() => {
|
||
if (orderId.value) loadOrder(orderId.value)
|
||
})
|
||
|
||
async function loadOrder(id : number) {
|
||
try {
|
||
const data = await getOrderDetail(id)
|
||
order.value = data
|
||
orderItems.value = data.items || []
|
||
orderStore.setCurrentOrder(data)
|
||
} catch {
|
||
uni.showToast({ title: '加载订单失败', icon: 'none' })
|
||
}
|
||
}
|
||
|
||
async function handleCancel() {
|
||
if (!order.value) return
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定要取消该订单吗?',
|
||
success: async (res) => {
|
||
if (res.confirm && order.value) {
|
||
try {
|
||
await cancelOrder(order.value.id)
|
||
order.value.status = 'cancelled'
|
||
orderStore.updateOrderStatus(order.value.id, 'cancelled')
|
||
uni.showToast({ title: '订单已取消', icon: 'success' })
|
||
} catch {
|
||
uni.showToast({ title: '取消订单失败', icon: 'none' })
|
||
}
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
function contactService() {
|
||
uni.makePhoneCall({ phoneNumber: '15920028399' })
|
||
}
|
||
|
||
function copyShippingNo(no: string) {
|
||
uni.setClipboardData({
|
||
data: no,
|
||
success() {
|
||
uni.showToast({ title: '物流单号已复制', icon: 'success' })
|
||
}
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.order-detail {
|
||
min-height: 100vh;
|
||
background: #f5f5f5;
|
||
padding-bottom: 130rpx;
|
||
}
|
||
|
||
/* 自定义导航栏 */
|
||
.custom-navbar {
|
||
background: linear-gradient(to right, #FFCFDE, #FFA6C4);
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 100;
|
||
}
|
||
.custom-navbar__content {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 24rpx;
|
||
}
|
||
.custom-navbar__back {
|
||
width: 44rpx;
|
||
height: 44rpx;
|
||
}
|
||
.custom-navbar__title {
|
||
flex: 1;
|
||
text-align: center;
|
||
font-size: 34rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
.custom-navbar__placeholder {
|
||
width: 44rpx;
|
||
}
|
||
|
||
.section {
|
||
background: #fff;
|
||
margin: 20rpx 24rpx;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
}
|
||
|
||
/* 商品卡片 */
|
||
.order-item {
|
||
display: flex;
|
||
padding: 16rpx 0;
|
||
}
|
||
|
||
.order-item+.order-item {
|
||
border-top: 1rpx solid #f0f0f0;
|
||
}
|
||
|
||
.order-item__img {
|
||
width: 180rpx;
|
||
height: 180rpx;
|
||
border-radius: 12rpx;
|
||
flex-shrink: 0;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.order-item__info {
|
||
flex: 1;
|
||
margin-left: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.order-item__name {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.order-item__specs {
|
||
margin-top: 12rpx;
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.spec-row {
|
||
display: flex;
|
||
gap: 40rpx;
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.spec-row text {
|
||
min-width: 200rpx;
|
||
}
|
||
|
||
.order-item__bottom {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: 12rpx;
|
||
}
|
||
|
||
.order-item__price {
|
||
font-size: 32rpx;
|
||
color: #e4393c;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.order-item__qty {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
}
|
||
|
||
/* 订单信息 */
|
||
.info-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 16rpx 0;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
}
|
||
|
||
.info-row:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.info-label {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.info-value {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.copy-btn {
|
||
color: #FF6D9B;
|
||
font-size: 22rpx;
|
||
padding: 4rpx 16rpx;
|
||
border: 1rpx solid #FF6D9B;
|
||
border-radius: 16rpx;
|
||
}
|
||
|
||
/* 提示信息 */
|
||
.tip-section {
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.tip-section__title {
|
||
font-size: 30rpx;
|
||
color: #FF6D9B;
|
||
font-weight: bold;
|
||
display: block;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.tip-section__body {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12rpx;
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.tip-section__footer {
|
||
display: block;
|
||
margin-top: 20rpx;
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
/* 取消订单 */
|
||
.cancel-section {
|
||
margin-top: 20rpx;
|
||
text-align: center;
|
||
padding: 0;
|
||
}
|
||
|
||
.cancel-btn {
|
||
display: block;
|
||
padding: 28rpx 0;
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
}
|
||
|
||
/* 收货信息 */
|
||
.receiver-section {
|
||
background: #fff;
|
||
margin: 20rpx 24rpx;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
}
|
||
|
||
.receiver-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
padding: 12rpx 0;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.receiver-icon {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* 底部栏 */
|
||
.bottom-bar {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background: #fff;
|
||
padding: 20rpx 32rpx;
|
||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
gap: 30rpx;
|
||
}
|
||
|
||
.bottom-bar__left {
|
||
display: flex;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.bottom-bar__label {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.bottom-bar__price {
|
||
font-size: 44rpx;
|
||
color: #FF6D9B;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.bottom-bar__btn {
|
||
background: #FF6D9B;
|
||
color: #fff;
|
||
font-size: 30rpx;
|
||
font-weight: 500;
|
||
padding: 22rpx 56rpx;
|
||
border-radius: 44rpx;
|
||
border: none;
|
||
line-height: 1.4;
|
||
}
|
||
</style> |