937 lines
27 KiB
Plaintext
937 lines
27 KiB
Plaintext
<template>
|
||
<view class="delivery-order-detail">
|
||
<!-- 返回按钮 -->
|
||
<view class="back-header">
|
||
<view class="back-box" @click="goBack">
|
||
<text class="back-icon">‹</text>
|
||
<text class="back-text">返回</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单状态 -->
|
||
<view class="order-status">
|
||
<view class="status-progress">
|
||
<view class="progress-item" :class="{ active: order.status >= 1 }">
|
||
<view class="progress-dot"></view>
|
||
<text class="progress-text">待接单</text>
|
||
</view>
|
||
<view class="progress-line" :class="{ active: order.status >= 2 }"></view>
|
||
<view class="progress-item" :class="{ active: order.status >= 2 }">
|
||
<view class="progress-dot"></view>
|
||
<text class="progress-text">已接单</text>
|
||
</view>
|
||
<view class="progress-line" :class="{ active: order.status >= 3 }"></view>
|
||
<view class="progress-item" :class="{ active: order.status >= 3 }">
|
||
<view class="progress-dot"></view>
|
||
<text class="progress-text">取货中</text>
|
||
</view>
|
||
<view class="progress-line" :class="{ active: order.status >= 4 }"></view>
|
||
<view class="progress-item" :class="{ active: order.status >= 4 }">
|
||
<view class="progress-dot"></view>
|
||
<text class="progress-text">已取货</text>
|
||
</view>
|
||
<view class="progress-line" :class="{ active: order.status >= 5 }"></view>
|
||
<view class="progress-item" :class="{ active: order.status >= 5 }">
|
||
<view class="progress-dot"></view>
|
||
<text class="progress-text">已送达</text>
|
||
</view>
|
||
</view>
|
||
<text class="status-desc">{{ getStatusDesc() }}</text>
|
||
</view>
|
||
|
||
<!-- 配送信息 -->
|
||
<view class="delivery-info">
|
||
<view class="section-title">配送信息</view>
|
||
<view class="delivery-route">
|
||
<view class="route-item pickup">
|
||
<view class="route-icon">📦</view>
|
||
<view class="route-content">
|
||
<text class="route-title">取货地址</text>
|
||
<text class="route-address">{{ merchant.contact_name }} · {{ merchant.contact_phone }}</text>
|
||
<text class="route-detail">{{ pickupAddress }}</text>
|
||
</view>
|
||
<!-- 只在取货中状态且订单未完成时显示按钮 -->
|
||
<button v-if="order.status === 3 && order.status < 5" class="route-action" @click="confirmPickup">确认取货</button>
|
||
</view>
|
||
|
||
<view class="route-line"></view>
|
||
|
||
<view class="route-item delivery">
|
||
<view class="route-icon">🏠</view>
|
||
<view class="route-content">
|
||
<text class="route-title">送货地址</text>
|
||
<text class="route-address">{{ getDeliveryAddress().name }} · {{ getDeliveryAddress().phone }}</text>
|
||
<text class="route-detail">{{ getDeliveryAddress().detail }}</text>
|
||
</view>
|
||
<!-- 只在已取货状态且订单未完成时显示按钮 -->
|
||
<button v-if="order.status === 4 && order.status < 5" class="route-action" @click="confirmDelivery">确认送达</button>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="delivery-distance">
|
||
<text class="distance-label">配送距离:</text>
|
||
<text class="distance-value">{{ deliveryInfo.distance }}km</text>
|
||
<text class="time-label">预计时长:</text>
|
||
<text class="time-value">{{ deliveryInfo.estimated_time }}分钟</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单商品 -->
|
||
<view class="order-products">
|
||
<view class="section-title">订单商品</view>
|
||
<view class="shop-info">
|
||
<text class="shop-name">{{ merchant.shop_name }}</text>
|
||
<text class="order-no">订单号:{{ order.order_no }}</text>
|
||
</view>
|
||
|
||
<view v-for="item in orderItems" :key="item.id" class="product-item">
|
||
<image :src="item.product_image || '/static/default-product.png'" class="product-image" />
|
||
<view class="product-info">
|
||
<text class="product-name">{{ item.product_name }}</text>
|
||
<text v-if="item.sku_specifications" class="product-spec">{{ getSpecText(item.sku_specifications) }}</text>
|
||
<view class="price-quantity">
|
||
<text class="product-price">¥{{ item.price }}</text>
|
||
<text class="product-quantity">×{{ item.quantity }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="order-summary">
|
||
<view class="summary-item">
|
||
<text class="summary-label">商品总额</text>
|
||
<text class="summary-value">¥{{ order.total_amount }}</text>
|
||
</view>
|
||
<view class="summary-item">
|
||
<text class="summary-label">配送费</text>
|
||
<text class="summary-value delivery-fee">¥{{ order.delivery_fee }}</text>
|
||
</view>
|
||
<view class="summary-item total">
|
||
<text class="summary-label">实付金额</text>
|
||
<text class="summary-value">¥{{ order.actual_amount }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 配送备注 -->
|
||
<view class="delivery-notes">
|
||
<view class="section-title">配送备注</view>
|
||
<view class="note-item">
|
||
<text class="note-label">顾客备注:</text>
|
||
<text class="note-content">{{ customerNote || '无备注' }}</text>
|
||
</view>
|
||
<view class="note-item">
|
||
<text class="note-label">商家备注:</text>
|
||
<text class="note-content">{{ merchantNote || '无备注' }}</text>
|
||
</view>
|
||
<!-- 只在订单未完成时显示输入框 -->
|
||
<view v-if="order.status < 5" class="note-item">
|
||
<text class="note-label">配送备注:</text>
|
||
<input v-model="deliveryNote" class="note-input" placeholder="请输入配送备注" />
|
||
</view>
|
||
<!-- 如果订单已完成,显示存储的备注 -->
|
||
<view v-else-if="deliveryNote" class="note-item">
|
||
<text class="note-label">配送备注:</text>
|
||
<text class="note-content">{{ deliveryNote }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 联系方式 -->
|
||
<view class="contact-section">
|
||
<view class="section-title">联系方式</view>
|
||
<view class="contact-list">
|
||
<view class="contact-item" @click="callCustomer">
|
||
<view class="contact-icon">📞</view>
|
||
<view class="contact-info">
|
||
<text class="contact-name">联系顾客</text>
|
||
<text class="contact-phone">{{ getDeliveryAddress().phone }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="contact-item" @click="callMerchant">
|
||
<view class="contact-icon">🏪</view>
|
||
<view class="contact-info">
|
||
<text class="contact-name">联系商家</text>
|
||
<text class="contact-phone">{{ merchant.contact_phone }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部操作 -->
|
||
<view class="bottom-actions">
|
||
<!-- 只在待接单状态且订单未完成时显示接受/拒绝订单按钮 -->
|
||
<button v-if="order.status === 1" class="action-btn accept" @click="acceptOrder">接受订单</button>
|
||
<button v-if="order.status === 1" class="action-btn reject" @click="rejectOrder">拒绝订单</button>
|
||
|
||
<!-- 只在已接单状态且订单未完成时显示“前往取货”和“正在取货”按钮 -->
|
||
<button v-if="order.status === 2" class="action-btn navigate" @click="startNavigation">前往取货</button>
|
||
<button v-if="order.status === 2" class="action-btn complete" @click="confirmArrivedAtPickup">正在取货</button>
|
||
|
||
<!-- 只在取货中状态且订单未完成时显示“确认取货”按钮 -->
|
||
<button v-if="order.status === 3" class="action-btn complete" @click="confirmPickup">确认取货</button>
|
||
|
||
<!-- 只在已取货状态且订单未完成时显示“确认送达”按钮 -->
|
||
<button v-if="order.status === 4" class="action-btn complete" @click="confirmDelivery">确认送达</button>
|
||
|
||
<!-- 始终显示联系客服按钮 -->
|
||
<button class="action-btn contact" @click="contactService">联系客服</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script lang="uts">
|
||
import supa, { supaReady } from '@/components/supadb/aksupainstance.uts'
|
||
import { getCurrentUserId } from '@/utils/store.uts'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
order: {
|
||
id: '',
|
||
order_no: '',
|
||
user_id: '',
|
||
merchant_id: '',
|
||
status: 0, // 👈 从 URL 参数获取
|
||
total_amount: 0,
|
||
discount_amount: 0,
|
||
delivery_fee: 0,
|
||
actual_amount: 0,
|
||
payment_method: 0,
|
||
payment_status: 0,
|
||
delivery_address: {},
|
||
created_at: ''
|
||
},
|
||
orderItems: [],
|
||
merchant: {
|
||
id: '',
|
||
user_id: '',
|
||
shop_name: '',
|
||
shop_logo: '',
|
||
shop_banner: '',
|
||
shop_description: '',
|
||
contact_name: '',
|
||
contact_phone: '',
|
||
shop_status: 0,
|
||
rating: 0,
|
||
total_sales: 0,
|
||
created_at: ''
|
||
},
|
||
deliveryInfo: {
|
||
distance: 0,
|
||
estimated_time: 0,
|
||
courier_id: '',
|
||
pickup_time: '',
|
||
delivery_time: ''
|
||
},
|
||
pickupAddress: '',
|
||
customerNote: '',
|
||
merchantNote: '',
|
||
deliveryNote: '',
|
||
}
|
||
},
|
||
|
||
onLoad(options: any) {
|
||
const orderId = options.id as string
|
||
// ✅ 从 URL 参数获取 status
|
||
const status = parseInt(options.status as string) || 0
|
||
|
||
if (orderId) {
|
||
this.order.id = orderId
|
||
this.order.status = status // ✅ 设置传入的状态
|
||
this.loadOrderDetail(orderId)
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
goBack() {
|
||
uni.navigateBack()
|
||
},
|
||
|
||
async loadOrderDetail(orderId: string) {
|
||
const originalStatus = this.order.status
|
||
try {
|
||
await supaReady
|
||
console.log('loadOrderDetail called', { orderId })
|
||
|
||
// 获取订单主表:按 id(UUID) / cid(数字) / order_no 三种可能匹配
|
||
let orderRes: any = null
|
||
const isUuid = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(orderId)
|
||
const isNumber = /^\d+$/.test(orderId)
|
||
console.log('loadOrderDetail: supa session=', supa.getSession && supa.getSession())
|
||
console.log('loadOrderDetail: detect id format', { isUuid, isNumber })
|
||
if (isUuid) {
|
||
console.log('loadOrderDetail: querying by id')
|
||
orderRes = await supa.from('ml_orders').select('*').eq('id', orderId).limit(1).execute()
|
||
} else if (isNumber) {
|
||
console.log('loadOrderDetail: querying by cid')
|
||
orderRes = await supa.from('ml_orders').select('*').eq('cid', Number(orderId)).limit(1).execute()
|
||
} else {
|
||
console.log('loadOrderDetail: querying by order_no')
|
||
orderRes = await supa.from('ml_orders').select('*').eq('order_no', orderId).limit(1).execute()
|
||
}
|
||
console.log('loadOrderDetail: orderRes=', orderRes)
|
||
if (orderRes && Array.isArray(orderRes.data) && orderRes.data.length > 0) {
|
||
const row = orderRes.data[0]
|
||
|
||
const shipping = row.shipping_address || {}
|
||
|
||
this.order = Object.assign(this.order, {
|
||
id: row.id,
|
||
order_no: row.order_no || '',
|
||
user_id: row.user_id || '',
|
||
merchant_id: row.merchant_id || '',
|
||
status: Number(row.order_status) || originalStatus,
|
||
total_amount: Number(row.total_amount || row.product_amount || 0),
|
||
discount_amount: Number(row.discount_amount || 0),
|
||
delivery_fee: Number(row.shipping_fee || row.shipping_fee || 0),
|
||
actual_amount: Number(row.paid_amount || row.actual_amount || 0),
|
||
payment_method: row.payment_method || 0,
|
||
payment_status: row.payment_status || 0,
|
||
delivery_address: {
|
||
name: shipping.name || shipping.recipient || '',
|
||
phone: shipping.phone || shipping.mobile || '',
|
||
detail: shipping.detail || shipping.address || JSON.stringify(shipping)
|
||
},
|
||
created_at: row.created_at || ''
|
||
})
|
||
|
||
this.customerNote = row.remark || ''
|
||
this.merchantNote = row.merchant_memo || ''
|
||
|
||
// 读取订单商品 - 使用从主表获得的真实 order id
|
||
const realOrderId = row.id
|
||
const itemsRes: any = await supa.from('ml_order_items').select('*').eq('order_id', realOrderId).execute()
|
||
console.log('loadOrderDetail: itemsRes=', itemsRes)
|
||
if (itemsRes && Array.isArray(itemsRes.data)) {
|
||
this.orderItems = itemsRes.data.map((it:any) => ({
|
||
id: it.id,
|
||
order_id: it.order_id,
|
||
product_id: it.product_id,
|
||
sku_id: it.sku_id,
|
||
product_name: it.product_name,
|
||
sku_specifications: it.specifications || it.sku_name || null,
|
||
price: Number(it.price) || 0,
|
||
quantity: Number(it.quantity) || 0,
|
||
total_amount: Number(it.total_amount) || 0,
|
||
product_image: it.image_url || it.product_image || ''
|
||
}))
|
||
}
|
||
|
||
// 读取商家店铺信息(ml_shops)
|
||
if (row.merchant_id) {
|
||
const shopRes: any = await supa.from('ml_shops').select('*').eq('merchant_id', row.merchant_id).limit(1).execute()
|
||
console.log('loadOrderDetail: shopRes=', shopRes)
|
||
if (shopRes && Array.isArray(shopRes.data) && shopRes.data.length > 0) {
|
||
const s = shopRes.data[0]
|
||
this.merchant = Object.assign(this.merchant, {
|
||
id: s.id || '',
|
||
user_id: s.merchant_id || '',
|
||
shop_name: s.shop_name || s.name || '',
|
||
shop_logo: s.shop_logo || '',
|
||
shop_banner: s.shop_banner || '',
|
||
shop_description: s.description || s.shop_description || '',
|
||
contact_name: s.contact_name || '',
|
||
contact_phone: s.contact_phone || '',
|
||
shop_status: s.status || 0,
|
||
rating: s.rating || 0,
|
||
total_sales: s.total_sales || 0,
|
||
created_at: s.created_at || ''
|
||
})
|
||
this.pickupAddress = s.address || ''
|
||
}
|
||
}
|
||
|
||
// deliveryInfo 从 ml_delivery_tasks 中读取(如果存在)
|
||
const dtRes: any = await supa.from('ml_delivery_tasks').select('*').eq('order_id', realOrderId).limit(1).execute()
|
||
console.log('loadOrderDetail: dtRes=', dtRes)
|
||
if (dtRes && Array.isArray(dtRes.data) && dtRes.data.length > 0) {
|
||
const dt = dtRes.data[0]
|
||
this.deliveryInfo.distance = Number(dt.distance) || this.deliveryInfo.distance
|
||
this.deliveryInfo.estimated_time = Number(dt.estimated_time) || this.deliveryInfo.estimated_time
|
||
this.deliveryInfo.courier_id = dt.driver_id || ''
|
||
this.deliveryInfo.pickup_time = dt.pickup_time || ''
|
||
this.deliveryInfo.delivery_time = dt.delivered_time || ''
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.error('loadOrderDetail db error', e)
|
||
}
|
||
},
|
||
|
||
getStatusDesc(): string {
|
||
if (this.order.status >= 5) {
|
||
return '订单已送达完成'
|
||
} else if (this.order.status === 4) {
|
||
return '已取货,正在前往送达'
|
||
} else if (this.order.status === 3) {
|
||
return '配送员正在前往取货'
|
||
} else if (this.order.status === 2) {
|
||
return '订单已接取'
|
||
} else if (this.order.status === 1) {
|
||
return '等待配送员接单'
|
||
} else {
|
||
return '订单状态未知'
|
||
}
|
||
},
|
||
|
||
getDeliveryAddress(): any {
|
||
return this.order.delivery_address as any
|
||
},
|
||
|
||
getSpecText(specifications: any): string {
|
||
if (!specifications) return ''
|
||
return Object.keys(specifications).map(key => `${key}: ${specifications[key]}`).join(', ')
|
||
},
|
||
|
||
confirmPickup() {
|
||
if (this.order.status < 5) {
|
||
uni.showModal({
|
||
title: '确认取货',
|
||
content: '确认已从商家处取到商品?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
await supaReady
|
||
// 更新 delivery task
|
||
const dtRes: any = await supa.from('ml_delivery_tasks').update({ status: 4, pickup_time: new Date().toISOString() }).eq('order_id', this.order.id).execute()
|
||
// 同步订单状态
|
||
await supa.from('ml_orders').update({ order_status: 4 }).eq('id', this.order.id).execute()
|
||
this.order.status = 4
|
||
uni.showToast({ title: '取货确认成功', icon: 'success' })
|
||
} catch (e) {
|
||
console.error('confirmPickup db error', e)
|
||
uni.showToast({ title: '取货确认失败', icon: 'none' })
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
},
|
||
|
||
confirmDelivery() {
|
||
if (this.order.status < 5) {
|
||
uni.showModal({
|
||
title: '确认送达',
|
||
content: '确认商品已送达到顾客手中?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
await supaReady
|
||
// 更新 delivery task
|
||
await supa.from('ml_delivery_tasks').update({ status: 6, delivered_time: new Date().toISOString() }).eq('order_id', this.order.id).execute()
|
||
// 更新订单状态为已送达
|
||
await supa.from('ml_orders').update({ order_status: 5 }).eq('id', this.order.id).execute()
|
||
this.order.status = 5
|
||
uni.showToast({ title: '送达确认成功', icon: 'success' })
|
||
} catch (e) {
|
||
console.error('confirmDelivery db error', e)
|
||
uni.showToast({ title: '送达确认失败', icon: 'none' })
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
},
|
||
|
||
acceptOrder() {
|
||
if (this.order.status < 5) {
|
||
uni.showModal({
|
||
title: '接受订单',
|
||
content: '确定接受这个配送订单吗?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
await supaReady
|
||
const userId = getCurrentUserId()
|
||
let driverId = null
|
||
if (userId) {
|
||
const dRes: any = await supa.from('ml_delivery_drivers').select('id').eq('user_id', userId).limit(1).execute()
|
||
if (dRes && Array.isArray(dRes.data) && dRes.data.length > 0) driverId = dRes.data[0].id
|
||
}
|
||
|
||
// 尝试更新已有 delivery task
|
||
const updateRes: any = await supa.from('ml_delivery_tasks').update({ driver_id: driverId, status: 2 }).eq('order_id', this.order.id).execute()
|
||
if (!(updateRes && Array.isArray(updateRes.data) && updateRes.data.length > 0)) {
|
||
// 若不存在,则插入新的 task
|
||
await supa.from('ml_delivery_tasks').insert({ order_id: this.order.id, driver_id: driverId, status: 2, created_at: new Date().toISOString() }).execute()
|
||
}
|
||
// 更新订单状态
|
||
await supa.from('ml_orders').update({ order_status: 2 }).eq('id', this.order.id).execute()
|
||
this.order.status = 2
|
||
uni.showToast({ title: '订单接受成功', icon: 'success' })
|
||
} catch (e) {
|
||
console.error('acceptOrder db error', e)
|
||
uni.showToast({ title: '接受订单失败', icon: 'none' })
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
},
|
||
|
||
rejectOrder() {
|
||
if (this.order.status < 5) {
|
||
uni.showModal({
|
||
title: '拒绝订单',
|
||
content: '确定拒绝这个配送订单吗?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
try {
|
||
await supaReady
|
||
// 标记订单为已拒绝(order_status = 7)
|
||
await supa.from('ml_orders').update({ order_status: 7 }).eq('id', this.order.id).execute()
|
||
uni.showToast({ title: '订单已拒绝', icon: 'success' })
|
||
uni.navigateBack()
|
||
} catch (e) {
|
||
console.error('rejectOrder db error', e)
|
||
uni.showToast({ title: '拒绝订单失败', icon: 'none' })
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
},
|
||
|
||
startNavigation() {
|
||
if (this.order.status < 5) {
|
||
uni.showToast({
|
||
title: '正在启动导航',
|
||
icon: 'loading'
|
||
})
|
||
|
||
setTimeout(() => {
|
||
uni.showToast({
|
||
title: '导航已启动',
|
||
icon: 'success'
|
||
})
|
||
}, 1000)
|
||
}
|
||
},
|
||
|
||
callCustomer() {
|
||
const phone = this.getDeliveryAddress().phone
|
||
uni.makePhoneCall({ phoneNumber: phone })
|
||
},
|
||
|
||
callMerchant() {
|
||
uni.makePhoneCall({ phoneNumber: this.merchant.contact_phone })
|
||
},
|
||
|
||
contactService() {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/service/chat?orderId=${this.order.id}&type=delivery`
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
/* 保持原有样式不变 */
|
||
.delivery-order-detail {
|
||
background-color: #f5f5f5;
|
||
min-height: 100vh;
|
||
padding-bottom: 160rpx;
|
||
}
|
||
|
||
/* ... 其余样式保持原样 ... */
|
||
/* 返回按钮头部 */
|
||
.back-header {
|
||
background-color: #fff;
|
||
padding: 20rpx 30rpx;
|
||
position: relative;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.back-box {
|
||
position: absolute;
|
||
left: 30rpx;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
display: flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
padding: 10rpx;
|
||
border-radius: 8rpx;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
|
||
.back-box:active {
|
||
background-color: #f0f0f0;
|
||
}
|
||
|
||
.back-icon {
|
||
font-size: 36rpx;
|
||
color: #333;
|
||
margin-right: 5rpx;
|
||
}
|
||
|
||
.back-text {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.order-status {
|
||
background-color: #fff;
|
||
padding: 40rpx 30rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.status-progress {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.progress-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
flex: 1;
|
||
}
|
||
|
||
.progress-dot {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
border-radius: 50%;
|
||
background-color: #ddd;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.progress-item.active .progress-dot {
|
||
background-color: #4caf50;
|
||
}
|
||
|
||
.progress-text {
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.progress-item.active .progress-text {
|
||
color: #4caf50;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.progress-line {
|
||
height: 2rpx;
|
||
background-color: #ddd;
|
||
flex: 1;
|
||
margin: 0 20rpx;
|
||
margin-bottom: 32rpx;
|
||
}
|
||
|
||
.progress-line.active {
|
||
background-color: #4caf50;
|
||
}
|
||
|
||
.status-desc {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
text-align: center;
|
||
}
|
||
|
||
.delivery-info, .order-products, .delivery-notes, .contact-section {
|
||
background-color: #fff;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 25rpx;
|
||
}
|
||
|
||
.delivery-route {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.route-item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
padding: 25rpx 0;
|
||
}
|
||
|
||
.route-icon {
|
||
font-size: 36rpx;
|
||
margin-right: 20rpx;
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
.route-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.route-title {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.route-address {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.route-detail {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.route-action {
|
||
padding: 15rpx 30rpx;
|
||
background-color: #4caf50;
|
||
color: #fff;
|
||
border-radius: 25rpx;
|
||
font-size: 24rpx;
|
||
border: none;
|
||
}
|
||
|
||
.route-line {
|
||
width: 2rpx;
|
||
height: 40rpx;
|
||
background-color: #ddd;
|
||
margin-left: 38rpx;
|
||
}
|
||
|
||
.delivery-distance {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx;
|
||
background-color: #f8f9fa;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
.distance-label, .time-label {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-right: 10rpx;
|
||
}
|
||
|
||
.distance-value, .time-value {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-right: 30rpx;
|
||
}
|
||
|
||
.shop-info {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 20rpx 0;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
margin-bottom: 25rpx;
|
||
}
|
||
|
||
.shop-name {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.order-no {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.product-item {
|
||
display: flex;
|
||
padding: 25rpx 0;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
}
|
||
|
||
.product-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.product-image {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 8rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.product-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.product-name {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
margin-bottom: 8rpx;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.product-spec {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.price-quantity {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.product-price {
|
||
font-size: 26rpx;
|
||
color: #ff4444;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.product-quantity {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.order-summary {
|
||
margin-top: 25rpx;
|
||
padding-top: 20rpx;
|
||
border-top: 1rpx solid #f5f5f5;
|
||
}
|
||
|
||
.summary-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 8rpx 0;
|
||
}
|
||
|
||
.summary-label {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.summary-value {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.summary-value.delivery-fee {
|
||
color: #4caf50;
|
||
}
|
||
|
||
.summary-item.total {
|
||
border-top: 1rpx solid #f5f5f5;
|
||
margin-top: 10rpx;
|
||
padding-top: 15rpx;
|
||
}
|
||
|
||
.summary-item.total .summary-label,
|
||
.summary-item.total .summary-value {
|
||
font-weight: bold;
|
||
font-size: 28rpx;
|
||
color: #ff4444;
|
||
}
|
||
|
||
.note-item {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.note-label {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.note-content {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.note-input {
|
||
width: 100%;
|
||
padding: 15rpx;
|
||
border: 1rpx solid #ddd;
|
||
border-radius: 8rpx;
|
||
font-size: 26rpx;
|
||
background-color: #f8f9fa;
|
||
}
|
||
|
||
.contact-list {
|
||
display: flex;
|
||
gap: 30rpx;
|
||
}
|
||
|
||
.contact-item {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 25rpx;
|
||
background-color: #f8f9fa;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
.contact-icon {
|
||
font-size: 32rpx;
|
||
margin-right: 15rpx;
|
||
}
|
||
|
||
.contact-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.contact-name {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
margin-bottom: 5rpx;
|
||
}
|
||
|
||
.contact-phone {
|
||
font-size: 24rpx;
|
||
color: #007aff;
|
||
}
|
||
|
||
.bottom-actions {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #fff;
|
||
padding: 25rpx 30rpx;
|
||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||
display: flex;
|
||
gap: 15rpx;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.action-btn {
|
||
flex: 1;
|
||
min-width: 120rpx;
|
||
height: 70rpx;
|
||
border-radius: 35rpx;
|
||
font-size: 26rpx;
|
||
border: none;
|
||
margin: 5rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.action-btn.accept, .action-btn.complete {
|
||
background-color: #4caf50;
|
||
color: #fff;
|
||
}
|
||
|
||
.action-btn.reject {
|
||
background-color: #ff4444;
|
||
color: #fff;
|
||
}
|
||
|
||
.action-btn.navigate {
|
||
background-color: #2196f3;
|
||
color: #fff;
|
||
}
|
||
|
||
.action-btn.contact {
|
||
background-color: #ffa726;
|
||
color: #fff;
|
||
}
|
||
</style> |