| | |
| | | <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> |
| | |
| | | </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> |
| | | |
| | |
| | | </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> |
| | | |
| | |
| | | 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 |
| | | }) |
| | | }, |
| | | |
| | |
| | | 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() { |
| | |
| | | this.getOrderList() |
| | | }, |
| | | onShow() { |
| | | this.page = 1 |
| | | this.hasMore = true |
| | | this.orders = [] |
| | | this.getOrderList() |
| | | this.getActiveOrderCount() |
| | | }, |
| | | onReachBottom() { |
| | | if (!this.hasMore || this.loading) return |
| | |
| | | } |
| | | }, |
| | | 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' |
| | | }, |
| | |
| | | 2: '待接单', |
| | | 3: '待取货', |
| | | 4: '配送中', |
| | | 5: '已完成', |
| | | 7: '已完成', |
| | | 99: '已取消' |
| | | } |
| | |
| | | { 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 [] |
| | |
| | | } |
| | | 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' }) |
| | | }) |
| | | } |
| | | } |
| | |
| | | |
| | | &__actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 20rpx; |
| | | justify-content: space-between; |
| | | margin-top: 18rpx; |
| | | padding-top: 18rpx; |
| | | border-top: 1rpx solid #f0f2f6; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .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> |