From e56792f78e4df0df2f12552d1a61dd8ca1db5c67 Mon Sep 17 00:00:00 2001
From: MrShi <1878285526@qq.com>
Date: 星期一, 27 四月 2026 22:26:28 +0800
Subject: [PATCH] app

---
 app/pages/order/order.vue |  493 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 457 insertions(+), 36 deletions(-)

diff --git a/app/pages/order/order.vue b/app/pages/order/order.vue
index ab8b487..faa455c 100644
--- a/app/pages/order/order.vue
+++ b/app/pages/order/order.vue
@@ -19,7 +19,7 @@
 					<view class="order-card__head">
 					<view class="order-card__head-left">
 						<image class="order-card__badge-icon" :src="getBadgeIcon(item)" mode="widthFix"></image>
-						<text class="order-card__time-text">{{ item.code }}</text>
+						<text class="order-card__time-text">涓嬪崟鏃堕棿锛歿{ item.createTime }}</text>
 					</view>
 						<text class="order-card__status" :class="{ 'order-card__status--highlight': item.status === 3 || item.status === 4 }">{{ getStatusText(item.status) }}</text>
 					</view>
@@ -51,15 +51,20 @@
 					</view>
 
 					<view v-if="getActions(item).length" class="order-card__actions">
-						<button
-							v-for="action in getActions(item)"
-							:key="action.text"
-							class="order-card__action-btn"
-							:class="['order-card__action-btn--' + action.type, { 'order-card__action-btn--primary-fill': action.fill }]"
-							hover-class="order-card__action-btn--hover"
-						>
-							{{ action.text }}
-						</button>
+						<view></view>
+						<view style="display: flex;flex-wrap: wrap;gap: 20rpx;">
+							<button
+								v-for="action in getActions(item)"
+								:key="action.text"
+								class="order-card__action-btn"
+								:class="['order-card__action-btn--' + action.type, { 'order-card__action-btn--primary-fill': action.fill }]"
+								hover-class="order-card__action-btn--hover"
+								@click.stop="handleAction(item, action)"
+							>
+								{{ action.text }}
+							</button>
+						</view>
+						
 					</view>
 				</view>
 
@@ -72,6 +77,70 @@
 				</view>
 			</view>
 		</scroll-view>
+
+		<u-modal
+			:show="showCancelModal"
+			showCancelButton
+			@cancel="showCancelModal = false"
+			cancelColor="#666666"
+			confirmColor="#0055FF"
+			title="鍙栨秷璁㈠崟纭"
+			@confirm="confirmCancelOrder">
+			<view style="text-align: center;color: #333333;font-size: 28rpx;font-weight: 400;">
+				鎮ㄤ粖鏃ヨ繕鍙彇娑� {{ cancelRemain }} 娆¤鍗曪紝娆℃暟鐢ㄥ敖鍚庝粖鏃ュ皢鏃犳硶鎺ュ崟锛屾槸鍚︾‘璁ゅ彇娑堬紵
+			</view>
+		</u-modal>
+
+		<u-popup :show="showQRPopup" round="20" mode="bottom">
+			<view class="qrcode">
+				<view class="qrcode-title">
+					<image src="/static/image/ic_close@2x.png" mode="widthFix" style="opacity: 0;"></image>
+					<text>{{ selectedOrder && selectedOrder.status === 4 ? '瀛樹欢鐮�' : '鍙栬揣鐮�' }}</text>
+					<image src="/static/image/ic_close@2x.png" mode="widthFix" @click="showQRPopup = false"></image>
+				</view>
+				<view class="qrcode-image">
+					<image v-if="selectedOrder && selectedOrder.driverVerifyCode" :src="'https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=' + selectedOrder.driverVerifyCode" mode="widthFix"></image>
+				</view>
+				<view class="qrcode-btn" hover-class="qrcode-btn--hover" @click="showQRPopup = false">鍏抽棴</view>
+			</view>
+		</u-popup>
+
+		<u-popup :show="showPhotoPopup" round="20" mode="bottom">
+			<view class="photo-popup">
+				<view class="photo-popup__header">
+					<view class="photo-popup__placeholder"></view>
+					<text class="photo-popup__title">{{ photoPopupTitle }}</text>
+					<image class="photo-popup__close" src="/static/image/ic_close2@2x.png" mode="aspectFit" @click="closePhotoPopup"></image>
+				</view>
+
+				<view class="photo-popup__section">
+					<view class="photo-popup__label-row">
+						<text class="photo-popup__label">{{ photoPopupLabel }}</text>
+						<text class="photo-popup__required">*</text>
+						<text class="photo-popup__hint">鏈�澶�3寮犵収鐗�</text>
+					</view>
+
+					<view class="photo-popup__photos">
+						<view v-for="(photo, index) in uploadedPhotos" :key="index" class="photo-popup__preview-card">
+							<image class="photo-popup__preview-image" :src="photo" mode="aspectFill"></image>
+							<view class="photo-popup__preview-mask" @click="deletePhoto(index)">
+								<text class="photo-popup__preview-delete">鍒犻櫎</text>
+							</view>
+						</view>
+						<view v-if="uploadedPhotos.length < 3" class="photo-popup__upload-btn" @click="choosePhoto">
+							<image src="/static/image/btn_upload2@2x.png" mode="aspectFit"></image>
+						</view>
+					</view>
+				</view>
+
+				<view class="photo-popup__section photo-popup__section--remark">
+					<text class="photo-popup__remark-title">澶囨敞淇℃伅</text>
+					<textarea v-model="photoRemark" class="photo-popup__textarea" maxlength="200" placeholder="璇疯緭鍏�" placeholder-style="color: #c7cbd3;" />
+				</view>
+
+				<button class="photo-popup__submit" hover-class="photo-popup__submit--hover" @click="submitPhotoPopup">{{ photoPopupSubmitText }}</button>
+			</view>
+		</u-popup>
 	</view>
 </template>
 
@@ -91,29 +160,34 @@
 				orders: [],
 				page: 1,
 				hasMore: true,
-				loading: false
+				loading: false,
+				showCancelModal: false,
+				showQRPopup: false,
+				showPhotoPopup: false,
+				selectedOrder: null,
+				cancelRemain: 0,
+				photoPopupMode: '',
+				photoRemark: '',
+				uploadedPhotos: [],
+				activeOrderCount: null
 			}
 		},
 		computed: {
 			displayTabs() {
-				const countMap = {}
-				this.tabs.forEach(tab => {
-					if (tab.value === null) {
-						countMap[null] = this.orders.length
-					} else {
-						countMap[tab.value] = this.orders.filter((item) => item.status === tab.value).length
-					}
-				})
-
 				return this.tabs.map((tab) => {
-					if (!countMap[tab.value]) {
-						return tab
+					let count = null
+					if (tab.value === 3) {
+						count = this.activeOrderCount?.grabbedCount
+					} else if (tab.value === 4) {
+						count = this.activeOrderCount?.deliveringCount
 					}
-
-					return {
-						...tab,
-						label: `${tab.label} ${countMap[tab.value]}`
+					if (count) {
+						return {
+							...tab,
+							label: `${tab.label} ${count}`
+						}
 					}
+					return tab
 				})
 			},
 
@@ -122,6 +196,15 @@
 					marginTop: this.navHeight + uni.upx2px(88) + 'px',
 					height: `calc(100vh - ${this.navHeight + uni.upx2px(88)}px)`
 				}
+			},
+			photoPopupTitle() {
+				return this.photoPopupMode === 'deliver' ? '鎷嶇収閫佽揪' : '鎷嶇収鍙栬揣'
+			},
+			photoPopupLabel() {
+				return this.photoPopupMode === 'deliver' ? '鎷嶆憚閫佽揪鐓х墖' : '鎷嶆憚鍙栬揣鐓х墖'
+			},
+			photoPopupSubmitText() {
+				return this.photoPopupMode === 'deliver' ? '纭閫佽揪' : '纭鍙栬揣'
 			}
 		},
 		onLoad() {
@@ -131,10 +214,7 @@
 			this.getOrderList()
 		},
 		onShow() {
-			this.page = 1
-			this.hasMore = true
-			this.orders = []
-			this.getOrderList()
+			this.getActiveOrderCount()
 		},
 		onReachBottom() {
 			if (!this.hasMore || this.loading) return
@@ -150,6 +230,17 @@
 			}
 		},
 		methods: {
+			getActiveOrderCount() {
+				this.$u.api.activeOrderCount().then(res => {
+					if (res.code === 200) {
+						this.activeOrderCount = res.data
+					} else {
+						this.activeOrderCount = null
+					}
+				}).catch(() => {
+					this.activeOrderCount = null
+				})
+			},
 			getBadgeIcon(item) {
 				return item.isUrgent ? '/static/image/ic_jisuda@2x.png' : '/static/image/ic_biaosuda@2x.png'
 			},
@@ -158,6 +249,7 @@
 					2: '寰呮帴鍗�',
 					3: '寰呭彇璐�',
 					4: '閰嶉�佷腑',
+					5: '宸插畬鎴�',
 					7: '宸插畬鎴�',
 					99: '宸插彇娑�'
 				}
@@ -171,9 +263,14 @@
 						{ text: '鎷嶇収鍙栬揣', type: 'primary', fill: true }
 					]
 				}
-				if (item.status === 4) {
+				if (item.status === 4 && item.takeShopId) {
 					return [
 						{ text: '瀛樹欢鐮�', type: 'primary', fill: false }
+					]
+				}
+				if (item.status === 4 && !item.takeShopId) {
+					return [
+						{ text: '鎷嶇収閫佽揪', type: 'primary', fill: true }
 					]
 				}
 				return []
@@ -197,15 +294,140 @@
 						}
 						this.hasMore = list.length >= 10
 					}
-				}).catch((err) => {
-					console.log(err)
 				}).finally(() => {
 					this.loading = false
 				})
 			},
 			goToOrderDetail(item, index) {
 				uni.navigateTo({
-					url: `/pages/order-detail/order-detail?id=${item.id}&index=${index + 1}`
+					url: `/pages/order-detail/order-detail?id=${item.id}`
+				})
+			},
+			handleAction(item, action) {
+				const text = action.text
+				if (text === '鍙栨秷璁㈠崟') {
+					this.handleCancelOrder(item)
+				} else if (text === '鍙栬揣鐮�' || text === '瀛樹欢鐮�') {
+					this.handleShowQRCode(item)
+				} else if (text === '鎷嶇収鍙栬揣') {
+					this.handlePhotoPickup(item)
+				} else if (text === '鎷嶇収閫佽揪') {
+					this.handlePhotoDeliver(item)
+				}
+			},
+			handleCancelOrder(item) {
+				this.selectedOrder = item
+				this.$u.api.cancelLimit().then(res => {
+					if (res.code === 200) {
+						this.cancelRemain = res.data.remain
+					}
+				}).finally(() => {
+					this.showCancelModal = true
+				})
+			},
+			confirmCancelOrder() {
+				if (!this.selectedOrder) return
+				this.$u.api.cancelOrder({ orderId: this.selectedOrder.id }).then(res => {
+					this.showCancelModal = false
+					if (res.code === 200) {
+						uni.showToast({ title: '鍙栨秷鎴愬姛', icon: 'success' })
+						this.getOrderList()
+						this.getActiveOrderCount()
+					} else {
+						uni.showToast({ title: res.message || '鍙栨秷澶辫触', icon: 'none' })
+					}
+				}).catch(() => {
+					this.showCancelModal = false
+				})
+			},
+			handleShowQRCode(item) {
+				this.selectedOrder = item
+				this.showQRPopup = true
+			},
+			handlePhotoPickup(item) {
+				this.selectedOrder = item
+				this.photoPopupMode = 'pickup'
+				this.uploadedPhotos = []
+				this.photoRemark = ''
+				this.showPhotoPopup = true
+			},
+			handlePhotoDeliver(item) {
+				this.selectedOrder = item
+				this.photoPopupMode = 'deliver'
+				this.uploadedPhotos = []
+				this.photoRemark = ''
+				this.showPhotoPopup = true
+			},
+			closePhotoPopup() {
+				this.showPhotoPopup = false
+			},
+			choosePhoto() {
+				if (this.uploadedPhotos.length >= 3) {
+					uni.showToast({ title: '鏈�澶氫笂浼�3寮犵収鐗�', icon: 'none' })
+					return
+				}
+				uni.chooseImage({
+					count: 3 - this.uploadedPhotos.length,
+					sourceType: ['camera', 'album'],
+					success: (res) => {
+						this.uploadedPhotos = [...this.uploadedPhotos, ...res.tempFilePaths]
+					}
+				})
+			},
+			deletePhoto(index) {
+				this.uploadedPhotos.splice(index, 1)
+			},
+			submitPhotoPopup() {
+				if (this.uploadedPhotos.length === 0) {
+					uni.showToast({ title: '璇蜂笂浼犵収鐗�', icon: 'none' })
+					return
+				}
+				uni.showLoading({ title: '涓婁紶涓�...' })
+				const uploadTasks = this.uploadedPhotos.map(path => {
+					return new Promise((resolve, reject) => {
+						uni.uploadFile({
+							url: this.$baseUrl + 'web/public/upload',
+							filePath: path,
+							name: 'file',
+							formData: {
+								folder: 'order'
+							},
+							success: (uploadRes) => {
+								const data = JSON.parse(uploadRes.data)
+								if (data.code === 200) {
+									resolve(data.data)
+								} else {
+									reject(new Error(data.msg))
+								}
+							},
+							fail: (err) => {
+								reject(err)
+							}
+						})
+					})
+				})
+
+				Promise.all(uploadTasks).then(images => {
+					const api = this.photoPopupMode === 'deliver' ? 'confirmDeliver' : 'confirmPickup'
+					const params = {
+						images: images.map(img => img.imgaddr),
+						orderId: this.selectedOrder.id,
+						remark: this.photoRemark
+					}
+					return this.$u.api[api](params)
+				}).then(res => {
+					uni.hideLoading()
+					if (res.code === 200) {
+						uni.showToast({ title: '鎻愪氦鎴愬姛', icon: 'success' })
+						this.showPhotoPopup = false
+						this.getOrderList()
+						this.getActiveOrderCount()
+					} else {
+						uni.showToast({ title: res.msg || '鎻愪氦澶辫触', icon: 'none' })
+					}
+				}).catch(err => {
+					uni.hideLoading()
+					uni.showToast({ title: err.message || '涓婁紶澶辫触', icon: 'none' })
 				})
 			}
 		}
@@ -472,8 +694,7 @@
 
 		&__actions {
 			display: flex;
-			justify-content: flex-end;
-			gap: 20rpx;
+			justify-content: space-between;
 			margin-top: 18rpx;
 			padding-top: 18rpx;
 			border-top: 1rpx solid #f0f2f6;
@@ -515,4 +736,204 @@
 			}
 		}
 	}
+
+.qrcode {
+	padding: 30rpx 40rpx 50rpx;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+
+	&-title {
+		width: 100%;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 40rpx;
+
+		image {
+			width: 40rpx;
+			height: 40rpx;
+		}
+
+		text {
+			font-size: 34rpx;
+			font-weight: 700;
+			color: #2d3139;
+		}
+	}
+
+	&-image {
+		width: 400rpx;
+		height: 400rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		background: #f5f7fb;
+		border-radius: 16rpx;
+
+		image {
+			width: 360rpx;
+			height: 360rpx;
+		}
+	}
+
+	&-btn {
+		width: 100%;
+		height: 88rpx;
+		line-height: 88rpx;
+		text-align: center;
+		background: #106EFA;
+		border-radius: 44rpx;
+		font-size: 32rpx;
+		font-weight: 600;
+		color: #ffffff;
+		margin-top: 40rpx;
+
+		&--hover {
+			background: #0d5fc7;
+		}
+	}
+}
+
+.photo-popup {
+	padding: 30rpx 30rpx calc(env(safe-area-inset-bottom) + 30rpx);
+
+	&__header {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 40rpx;
+	}
+
+	&__placeholder {
+		width: 40rpx;
+		height: 40rpx;
+	}
+
+	&__title {
+		font-size: 34rpx;
+		font-weight: 700;
+		color: #2d3139;
+	}
+
+	&__close {
+		width: 40rpx;
+		height: 40rpx;
+	}
+
+	&__section {
+		margin-bottom: 30rpx;
+
+		&--remark {
+			margin-top: 30rpx;
+		}
+	}
+
+	&__label-row {
+		display: flex;
+		align-items: center;
+		margin-bottom: 20rpx;
+	}
+
+	&__label {
+		font-size: 30rpx;
+		font-weight: 600;
+		color: #2d3139;
+	}
+
+	&__required {
+		color: #ff4030;
+		margin-left: 8rpx;
+	}
+
+	&__hint {
+		font-size: 24rpx;
+		color: #8f96a3;
+		margin-left: auto;
+	}
+
+	&__photos {
+		display: flex;
+		flex-wrap: wrap;
+		gap: 20rpx;
+	}
+
+	&__preview-card {
+		position: relative;
+		width: 144rpx;
+		height: 144rpx;
+		border-radius: 12rpx;
+		overflow: hidden;
+	}
+
+	&__preview-image {
+		width: 100%;
+		height: 100%;
+	}
+
+	&__preview-mask {
+		position: absolute;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		height: 56rpx;
+		background: rgba(0, 0, 0, 0.5);
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	&__preview-delete {
+		font-size: 26rpx;
+		color: #ffffff;
+	}
+
+	&__upload-btn {
+		width: 144rpx;
+		height: 144rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+
+		image {
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	&__remark-title {
+		font-size: 30rpx;
+		font-weight: 600;
+		color: #2d3139;
+		margin-bottom: 20rpx;
+		display: block;
+	}
+
+	&__textarea {
+		width: 100%;
+		height: 160rpx;
+		padding: 20rpx;
+		background: #f5f7fb;
+		border-radius: 12rpx;
+		font-size: 28rpx;
+		color: #2d3139;
+		box-sizing: border-box;
+	}
+
+	&__submit {
+		width: 100%;
+		height: 88rpx;
+		line-height: 88rpx;
+		background: #2c7cff;
+		border-radius: 44rpx;
+		font-size: 32rpx;
+		font-weight: 600;
+		color: #ffffff;
+		margin-top: 40rpx;
+
+		&--hover {
+			background: #2678e8;
+		}
+	}
+}
 </style>

--
Gitblit v1.9.3