Browse Source

1.3 订单页面团员demo完成

hfll
hflllll 3 hours ago
parent
commit
bac14dc75f
10 changed files with 1654 additions and 40 deletions
  1. +237
    -0
      components/order/OrderItem.vue
  2. +16
    -0
      pages.json
  3. +167
    -35
      pages/index/order.vue
  4. +71
    -5
      pages_order/components/order/placeOrder.vue
  5. +189
    -0
      pages_order/location/pickupPoint.vue
  6. +296
    -0
      pages_order/order/afterSale.vue
  7. +554
    -0
      pages_order/order/newOrderDetail.vue
  8. BIN
      static/image/古茗店面.webp
  9. +123
    -0
      static/js/mockOrders.js
  10. +1
    -0
      uni.scss

+ 237
- 0
components/order/OrderItem.vue View File

@ -0,0 +1,237 @@
<template>
<view class="order-item" @click="clickOrder">
<!-- 订单头部 - 商家信息 -->
<view class="order-header">
<view class="shop-info">
<image class="shop-logo" :src="order.shopLogo" mode="aspectFill"></image>
<text class="shop-name">{{ order.shopName }}</text>
</view>
</view>
<!-- 订单内容 - 菜品展示 -->
<view class="order-content">
<view class="food-list">
<view class="food-scroll">
<view class="food-item" v-for="(food, index) in fourImage" :key="index">
<image class="food-image" :src="food.image" mode="aspectFill"></image>
</view>
</view>
<view class="food-count" v-if="order.foodCount > 4">{{ order.foodCount }}</view>
</view>
</view>
<!-- 订单信息 - 下单时间和价格 -->
<view class="order-info">
<view class="order-time">下单时间{{ order.orderTime }}</view>
<view class="order-price">
<text>合计:</text>
<text class="price">{{ order.totalPrice.toFixed(2) }}</text>
</view>
</view>
<!-- 订单操作 -->
<view class="order-actions">
<view
class="order-toast"
v-if="order.status === 'shipping' || order.status === 'delivered'"
:style="{ backgroundColor: order.status === 'shipping' ? '#ECFEF4' : '#FFDBDB', color: order.status === 'shipping' ? '#019245' : '#FF2A2A' }">
<uv-icon name="info-circle" size="34" :color="order.status === 'shipping' ? '#019245' : '#FF2A2A'"></uv-icon>
<text v-show="order.status === 'shipping'">全力奔跑中请耐心等待哦</text>
<text v-show="order.status === 'delivered'">您的餐点已送到取餐点请尽快取餐</text>
</view>
<view class="action-btn cancel" v-show="order.status === 'pending'" @click="cancelOrder">
取消订单
</view>
<view class="action-btn confirm" v-show="order.status === 'pending'" @click="payOrder">
立即下单
</view>
<view class="action-btn confirm" v-show="order.status === 'processing' || order.status === 'shipping'"
@click="payOrder">
查看订单
</view>
<view class="action-btn confirm" v-show="order.status === 'completed'" @click="gotoSale">
订单售后
</view>
<view class="action-btn confirm" v-show="order.status === 'delivered'" @click="payOrder">
取餐完成
</view>
</view>
</view>
</template>
<script>
export default {
name: 'OrderItem',
props: {
//
order: {
type: Object,
required: true,
default: () => ({
id: '',
shopName: '',
shopLogo: '',
foods: [],
foodCount: 0,
orderTime: '',
totalPrice: 0,
status: 'pending' // pending, processing, shipping, completed, delivered, canceled
})
}
},
computed: {
fourImage() {
return this.order.foods.slice(0, 4)
}
},
methods: {
//
cancelOrder() {
this.$emit('cancel', this.order.id);
},
//
payOrder() {
this.$emit('pay', this.order.id);
},
//
clickOrder() {
this.$emit('click', this.order);
},
gotoSale() {
this.$utils.navigateTo({
url: '/pages_order/order/afterSale?id=' + this.order.id
})
}
}
}
</script>
<style lang="scss" scoped>
.order-item {
background-color: #ffffff;
margin: 20rpx 0;
border-radius: 16rpx;
padding: 20rpx;
.order-header {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f5f5f5;
.shop-info {
display: flex;
align-items: center;
.shop-logo {
width: 70rpx;
height: 70rpx;
border-radius: 6rpx;
margin-right: 10rpx;
}
.shop-name {
font-size: 28rpx;
}
}
}
.order-content {
padding: 20rpx 0;
.food-list {
white-space: nowrap;
height: 150rpx;
width: 100%;
display: flex;
align-items: center;
}
.food-scroll {
display: inline-flex;
}
.food-item {
height: 140rpx;
width: 130rpx;
margin-right: 10rpx;
display: inline-block;
.food-image {
width: 100%;
height: 100%;
border-radius: 8rpx;
}
}
.food-count {
flex: 1;
font-size: 24rpx;
color: #666;
text-align: center;
margin-top: 10rpx;
}
}
.order-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 0;
border-top: 1rpx solid #f5f5f5;
.order-time {
font-size: 24rpx;
color: #666;
}
.order-price {
font-size: 24rpx;
.price {
color: #f00;
font-weight: 500;
margin-left: 8rpx;
}
}
}
.order-actions {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 20rpx;
gap: 20rpx;
.order-toast {
display: flex;
align-items: center;
// justify-content: flex-start;
flex: 1;
// text-align: left;
gap: 10rpx;
font-size: 24rpx;
background-color: pink;
border-radius: 10rpx;
padding: 10rpx;
}
.action-btn {
padding: 12rpx 30rpx;
border-radius: 30rpx;
font-size: 24rpx;
font-weight: 500;
&.cancel {
background-color: #fff;
color: $uni-color-third;
border: 3rpx solid $uni-color-third;
}
&.confirm {
background-color: $uni-color;
color: #fff;
}
}
}
}
</style>

+ 16
- 0
pages.json View File

@ -51,6 +51,13 @@
"enablePullDownRefresh": true
}
},
{
"path": "order/newOrderDetail",
"style": {
"navigationBarTitleText": "待支付订单",
"navigationStyle": "custom"
}
},
{
"path": "mine/purse"
},
@ -84,6 +91,9 @@
{
"path": "order/createOrder"
},
{
"path": "order/afterSale"
},
{
"path": "mine/balance"
},
@ -131,6 +141,12 @@
},
{
"path": "order/receiveGift"
},
{
"path": "location/pickupPoint",
"style": {
"navigationBarTitleText": "取餐点选择"
}
}
]
}],


+ 167
- 35
pages/index/order.vue View File

@ -1,21 +1,34 @@
<template>
<view class="page">
<!-- 导航栏 -->
<navbar title="订单中心" leftClick @leftClick="$utils.navigateBack" bgColor="#E3441A" color="#fff" />
<navbar title=" " bgColor="#019245" color="#fff" />
<!-- 搜索框 -->
<view class="search-box" style="background-color: #fff; padding: 12rpx 20rpx 0rpx; ">
<uv-search placeholder="搜索商品名" v-model="keyword" :showAction="false" actionText="" height="80rpx" animation
bgColor="#F5F5F5" inputAlign="center" color="#000" placeholderColor="#979797"
searchIconSize="50rpx"></uv-search>
</view>
<!-- 订单筛选 -->
<view class="tabs">
<uv-tabs :list="tabs"
:activeStyle="{color : '#fff', fontWeight : 600}"
lineColor="#fff"
:inactiveStyle="{color: 'rgba(255,255,255,.8)'}"
lineHeight="8rpx"
lineWidth="50rpx"
:current="current"
@click="clickTabs"></uv-tabs>
<uv-tabs :list="tabs" :activeStyle="{ color: '#019245'}" lineColor="#019245" :scrollable="false"
:inactiveStyle="{color: 'black'}" lineHeight="6rpx" lineWidth="55rpx" :current="current"
@click="clickTabs"></uv-tabs>
</view>
<!-- 订单列表 -->
<view class="order-list">
<OrderItem v-for="(order, index) in orderList" :key="order.id" :order="order" @cancel="handleCancelOrder"
@pay="handlePayOrder" @click="goToOrderDetail(order)" />
<view style="
margin-top: 200rpx;
min-width: 700rpx;">
<uv-empty mode="order" v-if="orderList.length == 0"></uv-empty>
</view>
</view>
<view class="list">
<!-- <view class="list">
<view class="item" v-for="(item, index) in list" @click="toOrderDetail(item.id)" :key="index">
<view class="content" :key="index" v-for="(good, index) in item.commonOrderSkuList">
<view class="top">
@ -79,8 +92,8 @@
min-width: 700rpx;">
<uv-empty mode="list" v-if="list.length == 0"></uv-empty>
</view>
</view>
</view> -->
<customerServicePopup ref="customerServicePopup" />
<tabber select="order" />
@ -95,37 +108,58 @@
import mixinsOrder from '@/mixins/order.js'
import tabber from '@/components/base/tabbar.vue'
import customerServicePopup from '@/components/config/customerServicePopup.vue'
import OrderItem from '@/components/order/OrderItem.vue'
import mockOrders from '@/static/js/mockOrders.js'
export default {
mixins: [mixinsList, mixinsOrder],
components: {
tabber,
customerServicePopup,
OrderItem
},
computed: {},
data() {
return {
keyword: '',
// tabs: [{
// name: ''
// },
// {
// name: ''
// },
// {
// name: ''
// },
// {
// name: ''
// },
// {
// name: ''
// },
// {
// name: ''
// }
// ],
tabs: [{
name: '全部'
},
{
name: '待付款'
},
{
name: '待发货'
},
{
name: '待收货'
},
{
name: '已完成'
},
{
name: '已取消'
}
name: '待支付'
},
{
name: '待出餐'
},
{
name: '送餐中'
},
{
name: '待取餐'
},
{
name: '已完成'
}
],
current: 0,
mixinsListApi: 'getOrderPageList',
orderList: [],
}
},
onLoad(args) {
@ -133,6 +167,10 @@
this.clickTabs({
index: this.current
})
//
this.loadMockOrders()
this.filterOrdersByStatus(this.current)
},
methods: {
//tab
@ -144,14 +182,102 @@
} else {
this.queryParams.state = index - 1
}
this.getData()
//
// this.getData()
//
this.filterOrdersByStatus(index)
},
//
goToOrderDetail(order) {
if (order.status === 'completed') {
tthis.$utils.navigateTo({
url: '/pages_order/order/newOrderDetail?id=' + order.id + '&status=' + order.status
})
} else {
this.$utils.navigateTo({
url: '/pages_order/order/newOrderDetail?id=' + order.id + '&status=' + order.status
})
}
},
//
loadMockOrders() {
this.orderList = mockOrders
},
//
toOrderDetail(id) {
uni.navigateTo({
url: '/pages_order/order/orderDetail?id=' + id
//
filterOrdersByStatus(index) {
this.loadMockOrders() //
// if (index === 0) return //
const statusMap = {
0: 'pending', //
1: 'processing', //
2: 'shipping', //
3: 'delivered', //
4: 'completed' //
}
const targetStatus = statusMap[index]
if (targetStatus) {
this.orderList = this.orderList.filter(order => order.status === targetStatus)
}
},
//
handleCancelOrder(orderId) {
uni.showModal({
title: '提示',
content: '确定要取消订单吗?',
success: (res) => {
if (res.confirm) {
// API
uni.showToast({
title: '订单已取消',
icon: 'success'
})
//
const orderIndex = this.orderList.findIndex(item => item.id === orderId)
if (orderIndex !== -1) {
this.orderList[orderIndex].status = 'canceled'
//
if (this.current !== 0 && this.current !== 5) {
this.orderList.splice(orderIndex, 1)
}
}
}
}
})
},
//
handlePayOrder(orderId) {
uni.showToast({
title: '正在跳转支付...',
icon: 'loading'
})
// API
setTimeout(() => {
uni.hideToast()
uni.showToast({
title: '支付成功',
icon: 'success'
})
//
const orderIndex = this.orderList.findIndex(item => item.id === orderId)
if (orderIndex !== -1) {
this.orderList[orderIndex].status = 'processing'
//
if (this.current !== 0 && this.current !== 2) {
this.orderList.splice(orderIndex, 1)
}
}
}, 1500)
}
}
}
</script>
@ -160,7 +286,13 @@
.page {}
.tabs {
background: $uni-color;
background: #fff;
padding-bottom: 4rpx;
}
.order-list {
padding: 0 20rpx;
// position: relative;
}
.list {


+ 71
- 5
pages_order/components/order/placeOrder.vue View File

@ -6,15 +6,25 @@
<view class="place-order-title">
<image src="@/static/image/多人下单.webp" mode="aspectFit" class="place-order-title-image"></image>
<text class="number">2563</text><text>人下单</text>
<view class="place-order-title-close" @click="close">
<uv-icon name="close" size="40rpx"></uv-icon>
</view>
</view>
<!-- 选择取餐地点 -->
<view class="place-order-address">
<view class="place-order-address" @click="gotoPickupPoint">
<uv-icon name="map-fill" color="#019245" size="55rpx">
</uv-icon>
<text style="font-size: 42rpx;">
<text style="font-size: 42rpx;" v-show="!pickupPoint">
请选择取餐地点
</text>
<view v-show="pickupPoint" class="place-order-address-content">
<view class="place-order-address-content-name">
{{ pickupPoint.name }}{{ pickupPoint.phone }}
</view>
<view class="place-order-address-content-address"> {{ pickupPoint.address }}</view>
</view>
<view class="place-order-address-arrow">
<uv-icon name="arrow-right" size="40rpx">
</uv-icon>
@ -98,7 +108,8 @@ export default {
data() {
return {
value: 1,
payMethod: 'weixin'
payMethod: 'weixin',
pickupPoint: null
}
},
methods: {
@ -106,14 +117,40 @@ export default {
open() {
this.$refs.popup.open();
},
// close
close(){
this.$refs.popup.close();
},
// change
change(e) {
console.log('弹窗状态变化:', e);
//
},
//
gotoPickupPoint() {
this.$utils.navigateTo('/pages_order/location/pickupPoint')
// uni.navigateTo({
// url: '/pages_order/location/pickupPoint'
// });
},
//
listenPickupPoint() {
const pickupPointStr = uni.getStorageSync('selectedPickupPoint');
if (pickupPointStr) {
this.pickupPoint = JSON.parse(pickupPointStr);
}
uni.$on('updatePickupPoint', (point) => {
this.pickupPoint = point;
})
}
},
mounted(){
this.open()
this.open();
this.listenPickupPoint();
},
beforeDestroy() {
uni.$off('updatePickupPoint');
}
}
</script>
@ -125,6 +162,7 @@ export default {
display: flex;
align-items: center;
justify-content: center;
position: relative;
.number{
color: $uni-color;
}
@ -135,11 +173,19 @@ export default {
width: 100rpx;
height: 50rpx;
}
.place-order-title-close{
position: absolute;
right: 20rpx;
top: 50%;
transform: translateY(-50%);
color: $uni-color-third;
}
}
.place-order-address{
display: flex;
height: 80rpx;
line-height: 80rpx;
align-items: center;
// background-color: red;
gap: 30rpx;
padding-left: 20rpx;
@ -148,11 +194,31 @@ export default {
font-size: 32rpx;
font-weight: 500;
}
.place-order-address-arrow{
&-arrow{
position: absolute;
right: 20rpx;
top: 50%;
transform: translateY(-50%);
}
&-content{
display: flex;
flex-direction: column;
justify-content: space-around;
gap: 0rpx;
height: 100%;
// width: 100%;
&-name{
height: 30rpx;
line-height: 30rpx;
}
&-address{
height: 30rpx;
line-height: 30rpx;
width: 90%;
text-overflow: ellipsis; //
overflow: hidden;
white-space: nowrap;
}
}
}
.item{


+ 189
- 0
pages_order/location/pickupPoint.vue View File

@ -0,0 +1,189 @@
<template>
<view class="page">
<!-- 导航栏 -->
<navbar title="取餐点" leftClick @leftClick="$utils.navigateBack" bgColor="#019245" color="#fff" />
<view class="container">
<view class="header">
<view class="title">附近取餐点</view>
</view>
<!-- 取餐点列表 -->
<view class="pickup-list">
<view class="pickup-item" v-for="(item, index) in pickupPoints" :key="index">
<view class="left">
<image :src="item.image" class="shop-image" mode="aspectFill"></image>
</view>
<view class="center">
<view class="shop-name">{{item.name}}</view>
<view class="shop-address">
<uv-icon name="map-fill" color="#019245" size="34rpx"></uv-icon>
<text class="address-text">{{item.address}}</text>
</view>
<view class="shop-phone">
<uv-icon name="phone-fill" color="#019245" size="34rpx"></uv-icon>
<text class="phone-text">{{item.phone}}</text>
</view>
</view>
<view class="right">
<button class="select-btn" hover-class="select-btn-active" @click="selectPoint(item)">选择</button>
</view>
</view>
</view>
<!-- 无数据提示 -->
<uv-empty v-if="pickupPoints.length === 0" text="暂无取餐点" mode="list"></uv-empty>
</view>
</view>
</template>
<script>
import navbar from '@/components/base/navbar.vue'
export default {
components: {
navbar
},
data() {
return {
pickupPoints: [
{
id: '1',
name: '轻奢时代芙蓉兴盛',
address: '长沙市雨花区时代阳光大道轻奢时代芙蓉兴盛',
phone: '15070023168',
image: '/static/image/古茗店面.webp'
},
{
id: '2',
name: '芙蓉兴盛小文轩便利店',
address: '长沙市芙蓉区牛津街7栋102',
phone: '15070023168',
image: '/static/image/古茗店面.webp'
}
]
}
},
methods: {
//
selectPoint(point) {
// store storage
uni.setStorageSync('selectedPickupPoint', JSON.stringify(point));
//
// const pages = getCurrentPages();
// const prevPage = pages[pages.length - 2];
// if (prevPage) {
// //
// prevPage.$vm.pickupPoint = point;
// }
uni.$emit('updatePickupPoint', point);
uni.showToast({
title: '已选择取餐点',
icon: 'success',
duration: 400
});
setTimeout(() => {
// uni.navigateBack();
this.$utils.navigateBack()
}, 800);
}
}
}
</script>
<style lang="scss" scoped>
.page {
background-color: #f5f5f5;
min-height: 100vh;
}
.container {
padding: 0 20rpx;
}
.header {
margin-top: 20rpx;
background-color: #f2f2f2;
border-radius: 8rpx;
.title {
font-size: 32rpx;
// font-weight: bold;
padding: 20rpx;
}
}
.pickup-list {
margin-top: 20rpx;
.pickup-item {
display: flex;
background-color: #fff;
padding: 20rpx;
margin-bottom: 20rpx;
border-radius: 8rpx;
.left {
width: 160rpx;
height: 160rpx;
margin-right: 20rpx;
.shop-image {
width: 100%;
height: 100%;
border-radius: 8rpx;
}
}
.center {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
// gap: 8rpx;
.shop-name {
font-size: 32rpx;
// font-weight: bold;
margin-bottom: 10rpx;
}
.shop-address, .shop-phone {
font-size: 24rpx;
color: #999;
display: flex;
align-items: start;
margin-bottom: 6rpx;
gap: 8rpx;
width: 90%;
}
}
.right {
width: 100rpx;
display: flex;
align-items: center;
justify-content: center;
.select-btn {
width: 90rpx;
height: 60rpx;
line-height: 60rpx;
text-align: center;
background-color: $uni-color;
color: #fff;
font-size: 24rpx;
border-radius: 12rpx;
padding: 0;
}
.select-btn-active {
background-color: #106035;
}
}
}
}
</style>

+ 296
- 0
pages_order/order/afterSale.vue View File

@ -0,0 +1,296 @@
<template>
<view class="page">
<!-- 导航栏 -->
<navbar title="订单售后" leftClick @leftClick="navigateBack" bgColor="#019245" color="#fff" />
<!-- 售后表单 -->
<view class="after-sale-form">
<!-- 问题描述区域 -->
<view class="form-section">
<view class="section-title">
<view class="title-indicator"></view>
<text>请描述具体问题</text>
</view>
<view class="text-area-container">
<textarea class="problem-textarea" v-model="problemDescription" placeholder="请在此输入详细问题或意见"
placeholder-style="color: #999; font-size: 28rpx;" maxlength="500" />
</view>
</view>
<!-- 图片上传区域 -->
<view class="form-section">
<view class="section-title">
<view class="title-indicator"></view>
<text>请提供相关问题的截图或图片</text>
</view>
<view class="upload-area">
<view class="image-grid">
<view class="image-item" v-for="(image, index) in uploadedImages" :key="'img-'+index">
<image :src="image" mode="aspectFill" class="preview-image"></image>
<view class="delete-icon" @click="deleteImage(index)">
<uv-icon name="close" color="#fff" size="24rpx"></uv-icon>
</view>
</view>
<view class="upload-button" @click="chooseImage" v-if="uploadedImages.length < 9">
<uv-icon name="plus" size="60rpx" color="#019245"></uv-icon>
<text>添加图片</text>
</view>
</view>
</view>
</view>
<!-- 联系方式 -->
<view class="form-section">
<view class="section-title">
<view class="title-indicator"></view>
<text>联系方式</text>
</view>
<view class="contact-info">
<input class="contact-tip" placeholder="留下联系方式,方便我们向您回复" />
</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-button" @click="submitAfterSale">
提交
</view>
</view>
</template>
<script>
import navbar from '@/components/base/navbar.vue'
export default {
components: {
navbar
},
data() {
return {
orderId: '',
problemDescription: '',
uploadedImages: [],
contactInfo: '15070023168', //
orderDetail: null
}
},
onLoad(options) {
if (options.id) {
this.orderId = options.id
//
this.getOrderDetail(options.id)
}
},
methods: {
//
navigateBack() {
uni.navigateBack()
},
//
getOrderDetail(id) {
//
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
if (prevPage && prevPage.route.includes('order')) {
// ID
const foundOrder = prevPage.$vm.orderList.find(order => order.id === id)
if (foundOrder) {
this.orderDetail = foundOrder
}
}
},
//
chooseImage() {
uni.chooseImage({
count: 9 - this.uploadedImages.length,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
//
this.uploadedImages = [...this.uploadedImages, ...res.tempFilePaths]
}
})
},
//
deleteImage(index) {
this.uploadedImages.splice(index, 1)
},
//
submitAfterSale() {
//
if (!this.problemDescription.trim()) {
uni.showToast({
title: '请描述您的问题',
icon: 'none'
})
return
}
//
uni.showLoading({
title: '正在提交...'
})
//
setTimeout(() => {
//
setTimeout(() => {
uni.hideLoading()
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 2000
})
//
setTimeout(() => {
this.navigateBack()
}, 1500)
}, 1000)
}, 1000)
}
}
}
</script>
<style lang="scss" scoped>
.page {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 150rpx;
}
.after-sale-form {
margin: 20rpx;
}
.form-section {
// background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
margin-bottom: 20rpx;
.section-title {
display: flex;
align-items: center;
margin-bottom: 30rpx;
.title-indicator {
width: 8rpx;
height: 30rpx;
background-color: #019245;
border-radius: 4rpx;
margin-right: 16rpx;
}
text {
font-size: 30rpx;
font-weight: 500;
}
}
}
.text-area-container {
background-color: #fff;
border-radius: 8rpx;
.problem-textarea {
width: 100%;
height: 200rpx;
font-size: 28rpx;
padding: 20rpx;
}
}
.upload-area {
background-color: #fff;
padding: 30rpx;
.image-grid {
display: flex;
flex-wrap: wrap;
gap: 30rpx;
}
.image-item {
width: 160rpx;
height: 160rpx;
position: relative;
.preview-image {
width: 100%;
height: 100%;
border-radius: 8rpx;
}
.delete-icon {
position: absolute;
top: -20rpx;
right: -20rpx;
width: 40rpx;
height: 40rpx;
background-color: rgba(0,0,0,0.6);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
}
.upload-button {
width: 160rpx;
height: 160rpx;
color: $uni-color;
border: 4rpx dashed $uni-color;
border-radius: 8rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
// margin-right: 20rpx;
// margin-bottom: 20rpx;
font-size: 24rpx;
gap: 10rpx;
}
}
.contact-info {
background-color: #fff;
border-radius: 8rpx;
padding: 30rpx;
.contact-tip {
font-size: 26rpx;
color: #999;
// margin-bottom: 10rpx;
display: block;
}
.contact-value {
font-size: 28rpx;
color: #333;
}
}
.submit-button {
position: fixed;
bottom: 30rpx;
left: 50%;
transform: translateX(-50%);
width: 90%;
height: 90rpx;
background-color: #019245;
color: #fff;
font-size: 32rpx;
border-radius: 45rpx;
display: flex;
align-items: center;
justify-content: center;
}
</style>

+ 554
- 0
pages_order/order/newOrderDetail.vue View File

@ -0,0 +1,554 @@
<template>
<view class="page">
<!-- 导航栏 -->
<navbar :title="orderStatus === 'pending' ? '待支付订单' : '订单详情' " leftClick @leftClick="navigateBack" bgColor="#019245" color="#fff" />
<!-- 店铺信息 -->
<view class="shop-info">
<view class="shop-header">
<image class="shop-logo" :src="orderDetail.shopLogo" mode="aspectFill"></image>
<view class="shop-name-container">
<text class="shop-name">{{orderDetail.shopName}}</text>
<view class="shop-address">
<view style="padding-top: 7rpx;">
<!-- 需要置顶 -->
<uv-icon name="map-fill" color="#019245" size="28rpx"></uv-icon>
</view>
<text class="address-text">{{orderDetail.shopAddress}}</text>
</view>
<view class="shop-phone">
<view style="padding-top: 7rpx;">
<!-- 需要置顶 -->
<uv-icon name="phone-fill" color="#019245" size="28rpx"></uv-icon>
</view>
<text class="phone-text">{{orderDetail.shopPhone}}</text>
</view>
</view>
</view>
</view>
<view class="order-status">
<!-- 商品列表 -->
<view class="food-list">
<view class="food-item" v-for="(food, index) in showedFoods" :key="index">
<image class="food-image" :src="food.image" mode="aspectFill" />
<view class="food-info">
<text class="food-name">{{food.name}}</text>
<view class="food-sold">
<uv-icon name="bag" size="28rpx"></uv-icon>
<text>已售出 {{food.soldCount}}</text>
</view>
<text class="food-price"> <text style="font-size: 20rpx;"></text> {{food.price.toFixed(1)}}</text>
<text class="food-count">×{{food.count}}</text>
</view>
</view>
<view class="expand-more" @click="showAllFoods = !showAllFoods" v-if="orderDetail.foods.length > 3">
<text>{{showAllFoods ? '收起' : '展开'}} ({{orderDetail.foodCount}})</text>
<uv-icon :name="showAllFoods ? 'arrow-up' : 'arrow-down'" size="28rpx"></uv-icon>
</view>
</view>
<!-- 订单信息 -->
<view class="order-info">
<view class="info-item">
<text class="info-label">合计:</text>
<text class="info-value price">{{orderDetail.totalPrice.toFixed(2)}}</text>
</view>
<view class="info-item">
<text class="info-label">创建时间:</text>
<text class="info-value">{{orderDetail.orderTime}}</text>
</view>
<view class="info-item">
<text class="info-label">订单编号:</text>
<text class="info-value">{{orderDetail.id}}</text>
</view>
</view>
</view>
<view class="discount-info-container">
<!-- 优惠信息 -->
<view class="discount-info">
<view class="discount-header">
<text>优惠</text>
</view>
<view class="discount-item">
<view class="discount-left">
<image src="@/static/image/券.webp" mode="aspectFill" class="coupon-icon" />
<view>新用户立减</view>
</view>
<text class="discount-amount">-2</text>
</view>
</view>
<!-- 备注 -->
<view class="remark-section">
<view class="remark-header">
<text>备注</text>
</view>
<view class="remark-content">
<input type="text" v-model="orderDetail.remark" placeholder="请输入您要备注的内容"
placeholder-style="font-size: 28rpx" />
<!-- <text>{{orderDetail.remark || '无备注信息'}}</text> -->
</view>
</view>
</view>
<!-- 支付方式 -->
<uv-radio-group v-model="payMethod" v-if="orderStatus === 'pending'">
<view class="payment-methods">
<view class="payment-item">
<uv-icon name="weixin-circle-fill" size="70rpx" color="#019245"></uv-icon>
<text class="payment-name">微信支付</text>
<uv-radio activeColor="#019245" size="40rpx" name="weixin"></uv-radio>
</view>
<view class="payment-item">
<uv-icon name="red-packet" size="70rpx" color="#019245"></uv-icon>
<text class="payment-name">账户余额<text class="balance-text">(余额: 0)</text></text>
<uv-radio activeColor="#019245" size="40rpx" name="account"></uv-radio>
</view>
</view>
</uv-radio-group>
<!-- 底部支付栏 -->
<view class="bottom-bar">
<view class="total-section">
<text class="total-label">{{orderDetail.foodCount}}<text style="color: black;">合计</text> </text>
<text class="total-price">{{(orderDetail.totalPrice - 2).toFixed(1)}}</text>
</view>
<view class="pay-button" @click="handlePay" v-if="orderStatus === 'pending'">立即下单</view>
<view class="pay-button" @click="handlePay" v-if="orderStatus === 'delivered'">立即取餐</view>
</view>
</view>
</template>
<script>
import navbar from '@/components/base/navbar.vue'
export default {
components: {
navbar
},
data() {
return {
id: '',
payMethod: 'weixin',
showAllFoods: false,
orderStatus: '',
orderDetail: {
id: '324563256386532',
status: 'pending',
shopName: '轻奢时代芙蓉兴盛',
shopLogo: '/static/image/古茗店面.webp',
shopAddress: '长沙市雨花区时代阳光大道轻奢时代芙蓉兴盛',
shopPhone: '15070023168',
foods: [
{
id: 1,
name: '茄子肉沫',
image: '/static/image/红烧肉.png',
price: 9.9,
count: 1,
soldCount: 100
},
{
id: 2,
name: '豆角炒鸡蛋',
image: '/static/image/红烧肉.png',
price: 9.9,
count: 1,
soldCount: 100
},
{
id: 3,
name: '酸辣土豆丝',
image: '/static/image/红烧肉.png',
price: 9.9,
count: 1,
soldCount: 100
},
{
id: 3,
name: '酸辣土豆丝',
image: '/static/image/红烧肉.png',
price: 9.9,
count: 1,
soldCount: 100
},
{
id: 3,
name: '酸辣土豆丝',
image: '/static/image/红烧肉.png',
price: 9.9,
count: 1,
soldCount: 100
}
],
foodCount: 10,
orderTime: '2025-04-09 14:32:46',
totalPrice: 88.00,
remark: ''
}
}
},
computed: {
statusText() {
const statusMap = {
'pending': '等待支付',
'processing': '正在出餐',
'shipping': '正在配送中',
'delivered': '已送达,等待取餐',
'completed': '订单已完成',
'canceled': '订单已取消'
}
return statusMap[this.orderDetail.status] || '等待支付'
},
showedFoods() {
return this.showAllFoods ? this.orderDetail.foods : this.orderDetail.foods.slice(0, 3)
}
},
onLoad(options) {
// ID
if (options.id) {
this.id = options.id
// ID
// this.getOrderDetail(this.id)
//
this.orderStatus = options.status
}
},
methods: {
//
navigateBack() {
uni.navigateBack()
},
//
getOrderDetail(id) {
// API
// 使
},
//
handlePay() {
uni.showLoading({
title: '支付处理中...'
})
//
setTimeout(() => {
uni.hideLoading()
uni.showToast({
title: '支付成功',
icon: 'success',
duration: 2000
})
//
setTimeout(() => {
this.navigateBack()
// order
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
if (prevPage && prevPage.route.includes('order')) {
//
prevPage.$vm.loadMockOrders()
prevPage.$vm.filterOrdersByStatus(1) // Tab
prevPage.$vm.current = 1 // Tab
}
}, 1000)
}, 2000)
}
}
}
</script>
<style lang="scss" scoped>
.page {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
.status-bar {
background-color: #019245;
padding: 30rpx;
color: #fff;
font-size: 32rpx;
font-weight: 500;
}
.shop-info {
background-color: #fff;
margin: 20rpx;
border-radius: 16rpx;
padding: 20rpx;
.shop-header {
display: flex;
align-items: center;
// background-color: red;
.shop-logo {
width: 150rpx;
height: 150rpx;
border-radius: 10rpx;
margin-right: 20rpx;
}
.shop-name-container {
flex: 1;
.shop-name {
font-size: 30rpx;
font-weight: 500;
margin-bottom: 10rpx;
display: block;
}
.shop-address, .shop-phone {
display: flex;
align-items: start;
font-size: 24rpx;
color: $uni-color-third;
margin-top: 8rpx;
.address-text, .phone-text {
margin-left: 8rpx;
width: 80%;
white-space: wrap;
// overflow: hidden;
// text-overflow: ellipsis;
}
}
.shop-address-top{
display: flex;
align-items: start;
background-color: red;
// gap: 10rpx;
}
}
}
}
.order-status{
background-color: #fff;
margin: 20rpx;
border-radius: 16rpx;
padding: 20rpx;
.food-list {
// gap: 20rpx;
// background-color: #019245;
.food-item {
display: flex;
margin-bottom: 20rpx;
// background-color: red;
.food-image {
width: 120rpx;
height: 120rpx;
border-radius: 10rpx;
margin-right: 20rpx;
}
.food-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
.food-name {
font-size: 28rpx;
font-weight: 500;
}
.food-sold {
display: flex;
align-items: center;
font-size: 24rpx;
color: $uni-color-third;
}
.food-price {
font-size: 28rpx;
color: #f00;
}
.food-count {
color: black;
position: absolute;
bottom: 50%;
right: 0;
}
}
}
.expand-more {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0 0;
font-size: 24rpx;
color: $uni-color-third;
}
}
.order-info {
padding-top: 20rpx;
.info-item {
display: flex;
justify-content: space-between;
margin-bottom: 15rpx;
font-size: 26rpx;
.info-label {
color: black;
}
.info-value {
color: #333;
&.price {
color: #f00;
font-weight: 500;
}
}
}
}
}
.discount-info-container {
background-color: #fff;
margin: 20rpx;
border-radius: 16rpx;
padding: 20rpx;
display: flex;
flex-direction: column;
gap: 40rpx;
}
.discount-info {
display: flex;
align-items: center;
justify-content: space-between;
.discount-header {
font-size: 28rpx;
}
.discount-item {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20rpx;
.discount-left {
display: flex;
align-items: center;
gap: 10rpx;
.coupon-icon {
width: 36rpx;
height: 36rpx;
margin-top: 6rpx;
}
}
.discount-amount {
color: #f00;
font-weight: 500;
}
}
}
.remark-section {
display: flex;
// flex-direction: column;
gap: 40rpx;
// background-color: red;
align-items: center;
.remark-header {
font-size: 28rpx;
// font-weight: 500;
}
.remark-content {
font-size: 26rpx;
color: black;
min-height: 60rpx;
display: flex;
align-items: center;
}
}
.payment-methods {
background-color: #fff;
width: 100%;
margin: 20rpx;
border-radius: 16rpx;
padding: 20rpx;
display: flex;
flex-direction: column;
gap: 20rpx;
.payment-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.payment-name {
flex: 1;
margin-left: 20rpx;
font-size: 28rpx;
.balance-text {
font-size: 24rpx;
color: $uni-color-third;
margin-left: 10rpx;
}
}
}
}
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 100rpx;
background-color: #fff;
display: flex;
align-items: center;
padding: 0 30rpx;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
.total-section {
flex: 1;
.total-label {
font-size: 26rpx;
color: $uni-color-third;
}
.total-price {
font-size: 32rpx;
color: #f00;
margin-left: 10rpx;
}
}
.pay-button {
width: 240rpx;
height: 80rpx;
background-color: #019245;
color: #fff;
font-size: 30rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 40rpx;
}
}
</style>

BIN
static/image/古茗店面.webp View File

Before After

+ 123
- 0
static/js/mockOrders.js View File

@ -0,0 +1,123 @@
export default [
{
id: '20241223184523001',
shopName: '轻奢时代芙蓉兴盛',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 1, name: '红烧肉', image: '/static/image/红烧肉.png' },
{ id: 2, name: '青椒炒肉', image: '/static/image/红烧肉.png' },
{ id: 3, name: '香菇炒肉', image: '/static/image/红烧肉.png' },
{ id: 4, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 5, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 6, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 7, name: '豆角炒肉', image: '/static/image/红烧肉.png' }
],
foodCount: 10,
orderTime: '2024-12-23 18:45:23',
totalPrice: 88.00,
status: 'pending'
},
{
id: '20241223184523001',
shopName: '轻奢时代芙蓉兴盛',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 1, name: '红烧肉', image: '/static/image/红烧肉.png' },
{ id: 2, name: '青椒炒肉', image: '/static/image/红烧肉.png' },
{ id: 3, name: '香菇炒肉', image: '/static/image/红烧肉.png' },
{ id: 4, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 5, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 6, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 7, name: '豆角炒肉', image: '/static/image/红烧肉.png' }
],
foodCount: 10,
orderTime: '2024-12-23 18:45:23',
totalPrice: 88.00,
status: 'pending'
},
{
id: '20241223184523001',
shopName: '轻奢时代芙蓉兴盛',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 1, name: '红烧肉', image: '/static/image/红烧肉.png' },
{ id: 2, name: '青椒炒肉', image: '/static/image/红烧肉.png' },
{ id: 3, name: '香菇炒肉', image: '/static/image/红烧肉.png' },
{ id: 4, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 5, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 6, name: '豆角炒肉', image: '/static/image/红烧肉.png' },
{ id: 7, name: '豆角炒肉', image: '/static/image/红烧肉.png' }
],
foodCount: 10,
orderTime: '2024-12-23 18:45:23',
totalPrice: 88.00,
status: 'pending'
},
{
id: '20241223184523002',
shopName: '爷爷不泡茶奶茶店(鲁北路)',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 1, name: '红烧肉', image: '/static/image/红烧肉.png' },
{ id: 2, name: '青椒炒肉', image: '/static/image/红烧肉.png' },
{ id: 3, name: '香菇炒肉', image: '/static/image/红烧肉.png' },
{ id: 4, name: '豆角炒肉', image: '/static/image/红烧肉.png' }
],
foodCount: 10,
orderTime: '2024-12-23 18:45:23',
totalPrice: 88.00,
status: 'pending'
},
{
id: '20241223184523003',
shopName: '芙蓉兴盛小文轩便利店',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 5, name: '回锅肉', image: '/static/image/红烧肉.png' },
{ id: 6, name: '豆角炒鸡蛋', image: '/static/image/红烧肉.png' }
],
foodCount: 4,
orderTime: '2024-12-23 17:30:15',
totalPrice: 45.50,
status: 'processing'
},
{
id: '20241223184523003',
shopName: '晨光文具店',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 5, name: '回锅肉', image: '/static/image/红烧肉.png' },
{ id: 6, name: '豆角炒鸡蛋', image: '/static/image/红烧肉.png' }
],
foodCount: 4,
orderTime: '2024-12-23 17:30:15',
totalPrice: 45.50,
status: 'shipping'
},
{
id: '20241223184523003',
shopName: 'KFC肯德基中山路店',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 5, name: '回锅肉', image: '/static/image/红烧肉.png' },
{ id: 6, name: '豆角炒鸡蛋', image: '/static/image/红烧肉.png' }
],
foodCount: 4,
orderTime: '2024-12-23 17:30:15',
totalPrice: 45.50,
status: 'delivered'
},
{
id: '20241223184523003',
shopName: '轩宇蛋炒饭',
shopLogo: '/static/image/古茗店面.webp',
foods: [
{ id: 5, name: '回锅肉', image: '/static/image/红烧肉.png' },
{ id: 6, name: '豆角炒鸡蛋', image: '/static/image/红烧肉.png' }
],
foodCount: 4,
orderTime: '2024-12-23 17:30:15',
totalPrice: 45.50,
status: 'completed'
},
];

+ 1
- 0
uni.scss View File

@ -14,6 +14,7 @@
/* 颜色变量 */
$uni-color: #019245;
$uni-color-second: #FF2A2A;
$uni-color-third: #999;
/* 行为相关颜色 */
$uni-color-primary: #007aff;


Loading…
Cancel
Save