修改页面逻辑

This commit is contained in:
not-like-juvenile
2026-02-03 12:01:10 +08:00
parent 8efe6d5e89
commit c803a77c8f
12 changed files with 904 additions and 181 deletions

View File

@@ -0,0 +1,360 @@
<template>
<view class="all-orders-container">
<!-- 头部标题栏 -->
<view class="page-header">
<view class="back-btn" @click="goBack">
<text class="back-icon"></text>
<text class="back-text">返回</text>
</view>
<text class="page-title">全部待接订单</text>
<view class="refresh-action" @click="loadOrders">
<text class="refresh-icon">🔄</text>
</view>
</view>
<!-- 订单列表区 -->
<scroll-view class="order-list-scroll" scroll-y="true" refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh">
<view v-if="orders.length === 0" class="empty-state">
<image src="/static/images/no-order.png" class="empty-img" mode="aspectFit" />
<text class="empty-text">附近暂时没有待接订单</text>
</view>
<view v-for="order in orders" :key="order.id" class="order-card">
<view class="order-fee-center">
<text class="order-fee-text">¥{{ order.delivery_fee }}</text>
</view>
<view class="order-route-vertical">
<view class="route-point">
<text class="route-icon-pink">📍</text>
<text class="route-text-main">{{ order.pickup_address.detail || order.pickup_address.area }}</text>
</view>
<text class="route-arrow-down">↓</text>
<view class="route-point">
<text class="route-icon-home">🏠</text>
<text class="route-text-main">{{ order.delivery_address.detail || order.delivery_address.area }}</text>
</view>
</view>
<view class="order-meta-info">
<text class="meta-label">距离: {{ order.distance }}km</text>
<text class="meta-label">预计: {{ order.estimated_time }}分钟</text>
<text class="meta-label">下单: {{ order.created_at }}</text>
</view>
<view class="order-actions-stack">
<button class="order-btn-full accept" @click="acceptOrder(order.id)">接受订单</button>
<button class="order-btn-full detail" @click="viewOrderDetail(order.id)">查看详情</button>
</view>
</view>
<view v-if="orders.length > 0" class="list-bottom">
<text class="bottom-text">已加载全部订单</text>
</view>
</scroll-view>
</view>
</template>
<script lang="uts">
import supa, { supaReady } from '@/components/supadb/aksupainstance.uts'
import { getCurrentUserId } from '@/utils/store.uts'
export default {
data() {
return {
orders: [] as any[],
isRefreshing: false,
driverId: ''
}
},
async onLoad() {
await this.getDriverId()
await this.loadOrders()
},
methods: {
goBack() {
uni.navigateBack()
},
async getDriverId() {
try {
await supaReady
const userId = getCurrentUserId()
if (!userId) return
const res = await supa.from('ml_delivery_drivers').select('id').eq('user_id', userId).limit(1).execute()
if (res && Array.isArray(res.data) && res.data.length > 0) {
this.driverId = res.data[0].id
}
} catch (e) {
console.error('getDriverId error', e)
}
},
async loadOrders() {
this.isRefreshing = true
try {
await supaReady
const res = await supa.from('ml_delivery_tasks')
.select('*')
.is('driver_id', 'null')
.eq('status', 1)
.order('created_at', { ascending: false })
.execute()
if (res && Array.isArray(res.data)) {
this.orders = res.data.map((r: any) => this._transformTask(r))
}
} catch (e) {
console.error('loadAllOrders error', e)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
this.isRefreshing = false
}
},
onRefresh() {
this.loadOrders()
},
viewOrderDetail(orderId: string) {
uni.navigateTo({
url: `/pages/mall/delivery/order-detail?id=${orderId}&status=1`
})
},
_transformTask(task: any) {
const parseAddress = (a: any) => {
if (!a) return { detail: '', area: '' }
let obj = a
if (typeof a === 'string') {
try { obj = JSON.parse(a) } catch (e) { obj = { detail: a } }
}
return {
detail: obj.detail || obj.address || '',
area: obj.area || obj.district || obj.city || '未知区域'
}
}
return {
id: task.id,
order_no: task.order_no || '无编号',
delivery_fee: Number(task.delivery_fee) || 0,
pickup_address: parseAddress(task.pickup_address),
delivery_address: parseAddress(task.delivery_address),
distance: Number(task.distance) || 0,
estimated_time: Number(task.estimated_time) || 0,
created_at: task.created_at
}
},
async acceptOrder(taskId: string) {
if (!this.driverId) {
uni.showToast({ title: '未找到配送员身份', icon: 'none' })
return
}
uni.showLoading({ title: '正抢单中...' })
try {
// 抢单逻辑:更新 driver_id 和状态
const res = await supa.from('ml_delivery_tasks')
.update({ driver_id: this.driverId, status: 2 })
.eq('id', taskId)
.is('driver_id', 'null') // 并发保护
.execute()
if (res && Array.isArray(res.data) && res.data.length > 0) {
// 同步订单状态
const orderId = (res.data[0] as any).order_id
if (orderId) {
await supa.from('ml_orders').update({ order_status: 2 }).eq('id', orderId).execute()
}
uni.hideLoading()
uni.showToast({ title: '接单成功!', icon: 'success' })
setTimeout(() => {
uni.redirectTo({ url: '/pages/mall/delivery/index' })
}, 1500)
} else {
throw new Error('订单已被抢走')
}
} catch (e) {
uni.hideLoading()
uni.showToast({ title: '抢单失败,可能已被其他配送员接取', icon: 'none' })
this.loadOrders()
}
}
}
}
</script>
<style scoped>
.all-orders-container {
background-color: #f7f8fa;
height: 100vh;
display: flex;
flex-direction: column;
}
.page-header {
background-color: #ffffff;
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1rpx solid #eee;
}
.back-btn {
display: flex;
align-items: center;
padding: 10rpx 0;
}
.back-icon {
font-size: 40rpx;
color: #333;
}
.back-text {
font-size: 28rpx;
margin-left: 5rpx;
}
.page-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.refresh-action {
padding: 10rpx;
}
.order-list-scroll {
flex: 1;
overflow: hidden;
}
.order-card {
background-color: #ffffff;
margin: 20rpx;
padding: 30rpx;
border-radius: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.03);
}
.order-fee-center {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20rpx 0;
margin-bottom: 30rpx;
border-bottom: 1rpx dashed #eee;
}
.order-fee-text {
font-size: 48rpx;
font-weight: bold;
color: #4CAF50;
text-align: center;
}
.order-route-vertical {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20rpx;
}
.route-point {
display: flex;
flex-direction: column;
align-items: center;
gap: 10rpx;
}
.route-icon-pink {
font-size: 32rpx;
}
.route-icon-home {
font-size: 32rpx;
}
.route-text-main {
font-size: 28rpx;
color: #333;
font-weight: 500;
text-align: center;
}
.route-arrow-down {
font-size: 24rpx;
color: #999;
margin: 10rpx 0;
}
.order-meta-info {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
margin-bottom: 30rpx;
}
.meta-label {
font-size: 24rpx;
color: #999;
}
.order-actions-stack {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.order-btn-full {
width: 100%;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
font-weight: 500;
}
.order-btn-full.accept {
background-color: #4CAF50;
color: #fff;
}
.order-btn-full.detail {
background-color: #f0f0f0;
color: #333;
border: 1rpx solid #ddd;
}
.empty-state {
padding-top: 200rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.empty-img {
width: 240rpx;
height: 240rpx;
margin-bottom: 30rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
.list-bottom {
padding: 40rpx;
text-align: center;
}
.bottom-text {
font-size: 24rpx;
color: #ccc;
}
</style>