Files
yshop-drink/yshop-drink-uniapp-vue3/pages/order/order.vue
T

396 lines
7.8 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.
<template>
<view class="order-page">
<uv-navbar
:fixed="false"
title="我的订单"
bgColor="transparent"
leftIcon=""
/>
<view class="order-tabs">
<uv-tabs
:list="tabList"
:current="current"
@change="change"
keyName="name"
:scrollable="false"
lineWidth="28"
lineHeight="6"
lineColor="#F28C38"
:activeStyle="{ color: '#2b2b2b', fontWeight: '700', fontSize: '28rpx' }"
:inactiveStyle="{ color: '#9a9590', fontSize: '28rpx' }"
/>
</view>
<view class="order-list">
<uv-empty v-if="!orders.length" mode="order" text="暂无相关订单" />
<view
v-for="(item, index) in orders"
:key="index"
class="order-card"
@tap="detail(item.orderId)"
>
<view class="order-card__head">
<view class="order-card__shop">
<text class="order-card__shop-name">{{ item.shop.name }}</text>
<view class="order-card__tag" v-if="item.orderType">
{{ item.orderType === 'takeout' ? '外卖' : '自取' }}
</view>
</view>
<text class="order-card__status">{{ item.statusDto.title }}</text>
</view>
<view class="order-card__meta">
<text>取餐号:{{ item.numberId || '--' }}</text>
<text>订单号:{{ item.orderId }}</text>
</view>
<view class="order-card__goods">
<view
v-for="(good, gIndex) in item.cartInfo"
:key="gIndex"
class="order-good"
>
<image
v-if="good.image"
:src="good.image"
mode="aspectFill"
class="order-good__img"
/>
<view v-else class="order-good__img order-good__img--placeholder" />
<view class="order-good__body">
<text class="order-good__name">{{ good.title }}</text>
<text v-if="good.spec" class="order-good__spec">{{ good.spec }}</text>
<view class="order-good__row">
<text>×{{ good.number }}</text>
<text class="order-good__price">¥{{ good.price }}</text>
</view>
</view>
</view>
</view>
<view class="order-card__footer">
<text class="order-card__time">{{ formatDateTime(item.createTime) }}</text>
<view class="order-card__pay">
<text>共{{ goodsNum(item.cartInfo) }}件,实付</text>
<text class="order-card__amount">¥{{ item.payPrice }}</text>
</view>
</view>
<view class="order-card__actions" @tap.stop>
<button
v-if="item.paid > 0 && item.status < 2 && item.refundStatus == 0"
class="order-card__btn order-card__btn--plain"
size="mini"
@tap="receive(item)"
>确认收到餐</button>
<button
class="order-card__btn order-card__btn--primary"
size="mini"
@tap="detail(item.orderId)"
>订单详情</button>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
import { formatDateTime } from '@/utils/util'
import { orderGetOrders, orderReceive } from '@/api/order'
const main = useMainStore()
const { isLogin } = storeToRefs(main)
const page = ref(1)
const pageSize = ref(10)
const orders = ref([])
const tabList = ref([
{ type: -1, name: '全部' },
{ type: 0, name: '待支付' },
{ type: 1, name: '进行中' },
{ type: 4, name: '已完成' },
{ type: -3, name: '退款单' }
])
const current = ref(0)
const type = ref(-1)
const goodsNum = computed(() => {
return (goods) => {
let num = 0
;(goods || []).forEach((good) => (num += parseInt(good.number)))
return num
}
})
onLoad(() => {
if (!isLogin.value) {
uni.navigateTo({ url: '/pages/components/pages/login/login' })
}
getOrders(false)
})
onPullDownRefresh(() => {
getOrders(true)
})
onReachBottom(() => {
getOrders(false)
})
const change = (e) => {
type.value = e.type
current.value = e.index
getOrders(true)
}
const getOrders = async (isRefresh = false) => {
uni.showLoading({ title: '加载中' })
if (isRefresh) {
orders.value = []
page.value = 1
}
const ordersData = await orderGetOrders({
page: page.value,
limit: pageSize.value,
type: type.value
})
if (ordersData) {
orders.value = orders.value.concat(ordersData)
page.value += 1
}
uni.stopPullDownRefresh()
uni.hideLoading()
}
const detail = (id) => {
uni.navigateTo({
url: '/pages/components/pages/orders/detail?id=' + id
})
}
const receive = async (order) => {
const data = await orderReceive({ uni: order.orderId })
if (data) {
await getOrders(true)
}
}
</script>
<style lang="scss" scoped>
$bg-top: #fff3e6;
$bg-mid: #fff8f0;
$bg-bottom: #ffffff;
$accent: #f28c38;
$accent-deep: #ff6817;
$text-main: #2b2b2b;
$text-sub: #9a9590;
$card-radius: 24rpx;
.order-page {
min-height: 100vh;
padding: 0 24rpx 40rpx;
box-sizing: border-box;
background: linear-gradient(180deg, $bg-top 0%, $bg-mid 42%, $bg-bottom 100%);
}
.order-tabs {
margin-bottom: 20rpx;
padding: 8rpx 8rpx 4rpx;
border-radius: $card-radius;
background: #fff;
box-shadow: 0 8rpx 24rpx rgba(180, 120, 60, 0.08);
}
.order-list {
padding-bottom: 20rpx;
}
.order-card {
margin-bottom: 20rpx;
padding: 28rpx 24rpx 20rpx;
border-radius: $card-radius;
background: #fff;
box-shadow: 0 8rpx 24rpx rgba(180, 120, 60, 0.08);
&__head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
}
&__shop {
display: flex;
align-items: center;
gap: 12rpx;
min-width: 0;
flex: 1;
}
&__shop-name {
font-size: 30rpx;
font-weight: 700;
color: $text-main;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__tag {
flex-shrink: 0;
padding: 4rpx 12rpx;
border-radius: 999rpx;
font-size: 20rpx;
color: #fff;
background: linear-gradient(90deg, #ff9b20, #ff6817);
}
&__status {
flex-shrink: 0;
font-size: 26rpx;
font-weight: 600;
color: $accent;
}
&__meta {
display: flex;
flex-direction: column;
gap: 6rpx;
margin-top: 12rpx;
font-size: 22rpx;
color: $text-sub;
}
&__goods {
margin-top: 20rpx;
padding-top: 8rpx;
border-top: 1rpx solid #f3ebe3;
}
&__footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
margin-top: 16rpx;
}
&__time {
font-size: 22rpx;
color: $text-sub;
}
&__pay {
display: flex;
align-items: baseline;
gap: 8rpx;
font-size: 22rpx;
color: $text-main;
}
&__amount {
font-size: 32rpx;
font-weight: 700;
color: $accent-deep;
}
&__actions {
display: flex;
justify-content: flex-end;
gap: 16rpx;
margin-top: 20rpx;
padding-top: 16rpx;
border-top: 1rpx solid #f3ebe3;
}
&__btn {
margin: 0;
padding: 0 28rpx;
height: 56rpx;
line-height: 52rpx;
border-radius: 999rpx;
font-size: 24rpx;
&::after {
border: none;
}
&--plain {
color: $accent;
background: #fff;
border: 2rpx solid $accent !important;
}
&--primary {
color: #fff;
background: linear-gradient(90deg, #ff9b20, #ff6817);
border: none;
}
}
}
.order-good {
display: flex;
padding: 16rpx 0;
&__img {
width: 128rpx;
height: 128rpx;
margin-right: 20rpx;
border-radius: 18rpx;
flex-shrink: 0;
background: #fff3e6;
&--placeholder {
background: linear-gradient(135deg, #fff3e6, #f5e6d4);
}
}
&__body {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
&__name {
font-size: 28rpx;
font-weight: 700;
color: $text-main;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__spec {
margin-top: 8rpx;
font-size: 22rpx;
color: $text-sub;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: auto;
padding-top: 10rpx;
font-size: 24rpx;
color: $text-sub;
}
&__price {
font-size: 28rpx;
font-weight: 700;
color: $text-main;
}
}
</style>