连接数据库并修改页面
This commit is contained in:
@@ -95,7 +95,11 @@
|
||||
<view v-if="!currentTask && isOnline" class="available-orders-section">
|
||||
<view class="section-header">
|
||||
<text class="section-title">附近订单</text>
|
||||
<text class="refresh-btn" @click="refreshOrders">🔄 刷新</text>
|
||||
<view class="section-header-actions">
|
||||
<text class="refresh-btn" @click="refreshOrders">🔄 刷新</text>
|
||||
<!-- 当可接取订单达到上限时显示更多入口 -->
|
||||
<text v-if="availableOrders && availableOrders.length >= 20" class="more-btn" @click="goToAllOrders">更多 ➜</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="availableOrders.length === 0" class="empty-orders">
|
||||
@@ -164,6 +168,9 @@
|
||||
DeliveryDriverType,
|
||||
DeliveryTaskType
|
||||
} from '@/types/mall-types.uts'
|
||||
|
||||
import supa, { supaReady } from '@/components/supadb/aksupainstance.uts'
|
||||
import { getCurrentUserId, getCurrentUser } from '@/utils/store.uts'
|
||||
|
||||
type TodayStatsType = {
|
||||
completed_orders: number
|
||||
@@ -211,6 +218,10 @@
|
||||
data() {
|
||||
return {
|
||||
isOnline: true,
|
||||
// 防抖:记录上次刷新时间,避免 onShow 导致的频繁 refresh
|
||||
lastRefreshAt: 0,
|
||||
// 控制是否启用自动刷新(onShow)——默认关闭,避免频繁或意外刷新
|
||||
enableAutoRefresh: false,
|
||||
|
||||
driverInfo: {
|
||||
id: '',
|
||||
@@ -243,101 +254,204 @@
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadDriverInfo()
|
||||
this.loadTodayStats()
|
||||
this.loadCurrentTask()
|
||||
this.loadAvailableOrders()
|
||||
async onLoad() {
|
||||
// 确保 userProfile 已加载,以便 getCurrentUserId 能返回正确值
|
||||
try {
|
||||
await getCurrentUser()
|
||||
} catch (e) {
|
||||
console.warn('getCurrentUser failed on onLoad', e)
|
||||
}
|
||||
await this.loadDriverInfo()
|
||||
await this.loadTodayStats()
|
||||
await this.loadCurrentTask()
|
||||
await this.loadAvailableOrders()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 页面显示时刷新数据
|
||||
this.refreshData()
|
||||
async onShow() {
|
||||
// 自动刷新已被禁用(enableAutoRefresh = false)以避免页面抖动。
|
||||
// 如需临时启用,可在控制台设置 `this.enableAutoRefresh = true`。
|
||||
if (!this.enableAutoRefresh) {
|
||||
console.log('onShow: auto refresh disabled')
|
||||
return
|
||||
}
|
||||
const now = Date.now()
|
||||
if (this.lastRefreshAt && (now - this.lastRefreshAt < 5000)) {
|
||||
console.log('onShow: skipped refresh (debounced)')
|
||||
return
|
||||
}
|
||||
this.lastRefreshAt = now
|
||||
await this.refreshData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 加载配送员信息
|
||||
loadDriverInfo() {
|
||||
// TODO: 调用API获取配送员信息
|
||||
this.driverInfo.real_name = '张师傅'
|
||||
this.driverInfo.rating = 4.8
|
||||
this.driverInfo.total_orders = 1250
|
||||
},
|
||||
|
||||
// 加载今日统计
|
||||
loadTodayStats() {
|
||||
// TODO: 调用API获取今日统计
|
||||
this.todayStats = {
|
||||
completed_orders: 8,
|
||||
total_earning: '245.60',
|
||||
total_distance: 45,
|
||||
avg_rating: 4.9
|
||||
async loadDriverInfo() {
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in loadDriverInfo - proceeding')
|
||||
const userId = getCurrentUserId()
|
||||
if (!userId) return
|
||||
// 先按 user_id 查询(userId 可能是 ak_users.id 或 auth.users.id)
|
||||
let res = await supa.from('ml_delivery_drivers').select('*').eq('user_id', userId).limit(1).execute()
|
||||
console.log('loadDriverInfo: try user_id=', userId, 'res=', res)
|
||||
if (!(res && (res.data instanceof Array) && res.data.length > 0)) {
|
||||
// 回退:尝试从 ak_users 表根据 auth_id 查出 ak_users.id
|
||||
const akRes = await supa.from('ak_users').select('id').eq('auth_id', userId).limit(1).execute()
|
||||
console.log('loadDriverInfo: ak_users lookup by auth_id=', userId, 'akRes=', akRes)
|
||||
let akId = ''
|
||||
if (akRes && Array.isArray(akRes.data) && akRes.data.length > 0) {
|
||||
akId = (akRes.data[0] as any).id
|
||||
}
|
||||
if (akId) {
|
||||
res = await supa.from('ml_delivery_drivers').select('*').eq('user_id', akId).limit(1).execute()
|
||||
console.log('loadDriverInfo: retry user_id with akId=', akId, 'res=', res)
|
||||
}
|
||||
}
|
||||
if (res && (res.data instanceof Array) && res.data.length > 0) {
|
||||
this.driverInfo = Object.assign(this.driverInfo, res.data[0])
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('loadDriverInfo error', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 加载当前任务
|
||||
loadCurrentTask() {
|
||||
// TODO: 调用API获取当前任务
|
||||
this.currentTask = {
|
||||
id: '1',
|
||||
order_no: 'D202501081234',
|
||||
status: 2, // 👈 设置为“已接取”,以便测试“开始取货”按钮
|
||||
pickup_address: {
|
||||
detail: '华强北商业区华强电子世界2楼A205',
|
||||
area: '华强北'
|
||||
},
|
||||
delivery_address: {
|
||||
detail: '南山区科技园深南大道9999号',
|
||||
area: '科技园'
|
||||
},
|
||||
pickup_contact: {
|
||||
name: '商家联系人',
|
||||
phone: '138****5678'
|
||||
},
|
||||
delivery_contact: {
|
||||
name: '张先生',
|
||||
phone: '139****1234'
|
||||
},
|
||||
delivery_fee: 8.5,
|
||||
distance: 12.5,
|
||||
estimated_time: 35,
|
||||
created_at: '2025-01-08T14:30:00Z'
|
||||
async loadTodayStats() {
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in loadTodayStats - proceeding')
|
||||
const driverId = this.driverInfo.id || null
|
||||
if (!driverId) return
|
||||
const start = new Date()
|
||||
start.setHours(0,0,0,0)
|
||||
const end = new Date()
|
||||
end.setHours(23,59,59,999)
|
||||
const res = await supa.from('ml_delivery_tasks')
|
||||
.select('id,delivery_fee,distance,created_at,status')
|
||||
.eq('driver_id', driverId)
|
||||
.gte('created_at', start.toISOString())
|
||||
.lte('created_at', end.toISOString())
|
||||
.execute()
|
||||
if (res && res.data) {
|
||||
const rows = res.data as Array<any>
|
||||
const completed = rows.filter(r => r.status >= 5).length
|
||||
const earning = rows.reduce((s, r) => s + (Number(r.delivery_fee) || 0), 0)
|
||||
const distance = rows.reduce((s, r) => s + (Number(r.distance) || 0), 0)
|
||||
this.todayStats = {
|
||||
completed_orders: completed,
|
||||
total_earning: earning.toFixed(2),
|
||||
total_distance: Number(distance.toFixed(2)),
|
||||
avg_rating: this.driverInfo.rating || 0
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('loadTodayStats error', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 加载可接取订单
|
||||
loadAvailableOrders() {
|
||||
async loadCurrentTask() {
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in loadCurrentTask - proceeding')
|
||||
const driverId = this.driverInfo.id || null
|
||||
if (!driverId) {
|
||||
this.currentTask = null
|
||||
return
|
||||
}
|
||||
const res = await supa.from('ml_delivery_tasks')
|
||||
.select('*')
|
||||
.eq('driver_id', driverId)
|
||||
.lt('status', 5)
|
||||
.order('created_at', { ascending: false })
|
||||
.limit(1)
|
||||
.execute()
|
||||
console.log('loadCurrentTask: driverId=', driverId, 'res=', res)
|
||||
if (res && Array.isArray(res.data) && res.data.length > 0) {
|
||||
this.currentTask = this._transformTask(res.data[0])
|
||||
} else {
|
||||
this.currentTask = null
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('loadCurrentTask error', e)
|
||||
}
|
||||
},
|
||||
|
||||
async loadAvailableOrders() {
|
||||
// 如果当前不在线或已有任务,直接清空并返回
|
||||
if (!this.isOnline || this.currentTask) {
|
||||
this.availableOrders = []
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: 调用API获取附近订单
|
||||
this.availableOrders = [
|
||||
{
|
||||
id: '2',
|
||||
order_no: 'D202501081235',
|
||||
pickup_address: {
|
||||
detail: '福田区购物公园',
|
||||
area: '购物公园'
|
||||
},
|
||||
delivery_address: {
|
||||
detail: '南山区海岸城',
|
||||
area: '海岸城'
|
||||
},
|
||||
delivery_fee: 12.0,
|
||||
distance: 8.2,
|
||||
estimated_time: 25,
|
||||
created_at: '2025-01-08T15:00:00Z'
|
||||
// 在加载过程中先清空,避免显示过期或闪现的数据
|
||||
this.availableOrders = []
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in loadAvailableOrders - proceeding')
|
||||
console.log('loadAvailableOrders: supa session=', supa.getSession && supa.getSession())
|
||||
console.log('loadAvailableOrders: getCurrentUserId=', getCurrentUserId())
|
||||
const res = await supa.from('ml_delivery_tasks')
|
||||
.select('*')
|
||||
.is('driver_id', 'null')
|
||||
.eq('status', 1)
|
||||
.range(0, 19)
|
||||
.execute()
|
||||
console.log('loadAvailableOrders: query result=', res)
|
||||
if (res && Array.isArray(res.data)) {
|
||||
const fetched = (res.data as Array<any>).map((r:any) => this._transformTask(r))
|
||||
// 再次检查 currentTask,避免并发情况下短暂展示可接单
|
||||
if (this.currentTask) {
|
||||
this.availableOrders = []
|
||||
} else {
|
||||
this.availableOrders = fetched
|
||||
}
|
||||
}
|
||||
]
|
||||
} catch (e) {
|
||||
console.error('loadAvailableOrders error', e)
|
||||
this.availableOrders = []
|
||||
}
|
||||
},
|
||||
|
||||
// 将 DB 行转换为页面期望的结构
|
||||
_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 } }
|
||||
}
|
||||
const detail = obj.detail || obj.address || obj.full_address || obj.address_detail || obj.name || ''
|
||||
const area = (obj.city || obj.district || obj.area || '')
|
||||
return { detail, area }
|
||||
}
|
||||
|
||||
const parseContact = (c: any) => {
|
||||
if (!c) return { name: '', phone: '' }
|
||||
let obj = c
|
||||
if (typeof c === 'string') {
|
||||
try { obj = JSON.parse(c) } catch (e) { obj = { name: c } }
|
||||
}
|
||||
return { name: obj.name || obj.contact_name || obj.receiver_name || '', phone: obj.phone || obj.mobile || obj.contact_phone || '' }
|
||||
}
|
||||
|
||||
return {
|
||||
id: task.id,
|
||||
order_no: task.order_no || task.orderNo || task.trade_no || '',
|
||||
status: Number(task.status) || 1,
|
||||
pickup_address: parseAddress(task.pickup_address),
|
||||
delivery_address: parseAddress(task.delivery_address),
|
||||
pickup_contact: parseContact(task.pickup_contact),
|
||||
delivery_contact: parseContact(task.delivery_contact),
|
||||
delivery_fee: Number(task.delivery_fee) || 0,
|
||||
distance: Number(task.distance) || 0,
|
||||
estimated_time: Number(task.estimated_time) || 0,
|
||||
created_at: task.created_at || task.createdAt || ''
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新数据
|
||||
refreshData() {
|
||||
this.loadTodayStats()
|
||||
this.loadCurrentTask()
|
||||
this.loadAvailableOrders()
|
||||
async refreshData() {
|
||||
await this.loadTodayStats()
|
||||
await this.loadCurrentTask()
|
||||
await this.loadAvailableOrders()
|
||||
},
|
||||
|
||||
// 刷新订单列表
|
||||
@@ -429,49 +543,71 @@
|
||||
},
|
||||
|
||||
// 任务操作方法
|
||||
acceptTask() {
|
||||
// TODO: 调用API接受任务
|
||||
if (this.currentTask) {
|
||||
this.currentTask.status = 2 // 更新状态为“已接取”
|
||||
async acceptTask() {
|
||||
if (!this.currentTask) return
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in acceptTask - proceeding')
|
||||
const driverId = this.driverInfo.id || null
|
||||
if (!driverId) throw new Error('无配送员ID')
|
||||
const res = await supa.from('ml_delivery_tasks').update({ driver_id: driverId, status: 2 }).eq('id', this.currentTask.id).execute()
|
||||
if (res && !res.error) {
|
||||
this.currentTask.status = 2
|
||||
uni.showToast({ title: '任务已接受', icon: 'success' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('acceptTask error', e)
|
||||
uni.showToast({ title: '接受任务失败', icon: 'none' })
|
||||
}
|
||||
uni.showToast({
|
||||
title: '任务已接受',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
|
||||
startPickup() {
|
||||
// TODO: 调用API开始取货
|
||||
if (this.currentTask) {
|
||||
this.currentTask.status = 3 // 更新状态为“取货中”
|
||||
async startPickup() {
|
||||
if (!this.currentTask) return
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in startPickup - proceeding')
|
||||
const res = await supa.from('ml_delivery_tasks').update({ status: 3 }).eq('id', this.currentTask.id).execute()
|
||||
if (res && !res.error) {
|
||||
this.currentTask.status = 3
|
||||
uni.showToast({ title: '开始取货', icon: 'success' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('startPickup error', e)
|
||||
uni.showToast({ title: '操作失败', icon: 'none' })
|
||||
}
|
||||
uni.showToast({
|
||||
title: '开始取货',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
|
||||
confirmPickup() {
|
||||
// TODO: 调用API确认取货
|
||||
if (this.currentTask) {
|
||||
this.currentTask.status = 5 // 更新状态为“已取货”
|
||||
async confirmPickup() {
|
||||
if (!this.currentTask) return
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in confirmPickup - proceeding')
|
||||
const res = await supa.from('ml_delivery_tasks').update({ status: 4, pickup_time: new Date().toISOString() }).eq('id', this.currentTask.id).execute()
|
||||
if (res && !res.error) {
|
||||
this.currentTask.status = 4
|
||||
uni.showToast({ title: '取货完成', icon: 'success' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('confirmPickup error', e)
|
||||
uni.showToast({ title: '操作失败', icon: 'none' })
|
||||
}
|
||||
uni.showToast({
|
||||
title: '取货完成',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
|
||||
// startDelivery() {
|
||||
// // TODO: 调用API开始配送
|
||||
// if (this.currentTask) {
|
||||
// this.currentTask.status = 5 // 更新状态为“配送中”
|
||||
// }
|
||||
// uni.showToast({
|
||||
// title: '开始配送',
|
||||
// icon: 'success'
|
||||
// })
|
||||
// },
|
||||
async startDelivery() {
|
||||
if (!this.currentTask) return
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in startDelivery - proceeding')
|
||||
const res = await supa.from('ml_delivery_tasks').update({ status: 5 }).eq('id', this.currentTask.id).execute()
|
||||
if (res && !res.error) {
|
||||
this.currentTask.status = 5
|
||||
uni.showToast({ title: '开始配送', icon: 'success' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('startDelivery error', e)
|
||||
uni.showToast({ title: '操作失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 显示确认送达弹框
|
||||
showConfirmDeliveryDialog() {
|
||||
@@ -486,22 +622,23 @@
|
||||
})
|
||||
},
|
||||
|
||||
// 确认送达
|
||||
confirmDelivery() {
|
||||
// TODO: 调用API确认送达
|
||||
if (this.currentTask) {
|
||||
// 1. 将订单状态更新为“已完成” (假设5表示已完成)
|
||||
this.currentTask.status = 5;
|
||||
// 2. 将已完成的任务保存到本地存储,以便历史订单页面可以读取
|
||||
const completedOrder = {...this.currentTask}; // 创建副本,避免引用问题
|
||||
uni.setStorageSync('completed_order_for_history', completedOrder);
|
||||
}
|
||||
uni.showToast({
|
||||
title: '配送完成',
|
||||
icon: 'success'
|
||||
})
|
||||
this.currentTask = null
|
||||
this.loadAvailableOrders()
|
||||
async confirmDelivery() {
|
||||
if (!this.currentTask) return
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in confirmDelivery - proceeding')
|
||||
const res = await supa.from('ml_delivery_tasks').update({ status: 6, delivered_time: new Date().toISOString() }).eq('id', this.currentTask.id).execute()
|
||||
if (res && !res.error) {
|
||||
const completedOrder = { ...this.currentTask }
|
||||
uni.setStorageSync('completed_order_for_history', completedOrder)
|
||||
uni.showToast({ title: '配送完成', icon: 'success' })
|
||||
this.currentTask = null
|
||||
this.loadAvailableOrders()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('confirmDelivery error', e)
|
||||
uni.showToast({ title: '操作失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
contactCustomer() {
|
||||
@@ -538,14 +675,22 @@
|
||||
},
|
||||
|
||||
// 订单操作方法
|
||||
acceptOrder(orderId: string) {
|
||||
// TODO: 调用API接受订单
|
||||
uni.showToast({
|
||||
title: '订单已接受',
|
||||
icon: 'success'
|
||||
})
|
||||
this.loadCurrentTask()
|
||||
this.loadAvailableOrders()
|
||||
async acceptOrder(orderId: string) {
|
||||
try {
|
||||
const ready = await Promise.race([supaReady, new Promise(resolve => setTimeout(() => resolve(false), 1500))])
|
||||
if (!ready) console.warn('supaReady timeout/failed in acceptOrder - proceeding')
|
||||
const driverId = this.driverInfo.id || null
|
||||
if (!driverId) throw new Error('无配送员ID')
|
||||
const res = await supa.from('ml_delivery_tasks').update({ driver_id: driverId, status: 2 }).eq('id', orderId).execute()
|
||||
if (res && !res.error) {
|
||||
uni.showToast({ title: '订单已接受', icon: 'success' })
|
||||
await this.loadCurrentTask()
|
||||
await this.loadAvailableOrders()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('acceptOrder error', e)
|
||||
uni.showToast({ title: '接受订单失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 导航方法
|
||||
@@ -554,6 +699,13 @@
|
||||
url: '/pages/mall/delivery/order-history'
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到“全部可接订单”页面
|
||||
goToAllOrders() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/delivery/all'
|
||||
})
|
||||
},
|
||||
|
||||
goToEarnings() {
|
||||
uni.navigateTo({
|
||||
@@ -666,6 +818,17 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.section-header-actions {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.more-btn {
|
||||
color: #1976d2;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
|
||||
Reference in New Issue
Block a user