feat(order): 拆分“确认完成”为“送达”和“确认完成”按钮

- 新增送达操作,已发货且无送达照片时显示,可上传送达凭证
- 确认完成操作仅限已付款订单,标记为已完成,不需上传凭证
- 取消deliveryStatus=30表示已送达的用法,避免混淆“部分发货”状态
- 统一按钮显示逻辑,支持线下付款场景下同时显示确认收款/送达按钮
- 调整订单状态文案,新增“已送达待收款”与“待确认完成”状态描述
- 优化订单列表及详情中付款和物流状态的判断,去除对deliveryStatus=30的依赖
- 确认证据上传界面调整,确认完成操作不再显示上传凭证区域
This commit is contained in:
2026-07-17 16:27:09 +08:00
parent 184763a15c
commit 69862bfc0c
4 changed files with 57 additions and 45 deletions

View File

@@ -124,7 +124,16 @@
| 线下付款+已发货+未付款 | 已发货待收款(红) | 已发货待收款(红) | 已发货待收款(红) |
| 其他已发货 | 待收货(蓝) | 待收货(蓝) | 待收货(蓝) |
### 门店端:未付款已发货也显示"确认完成"按钮
- **问题**:线下付款先发货后结款的订单(未付款+已发货),门店端只有"确认收款"按钮,缺少"确认完成"按钮来上传送达照片
- **修改**`getOrderActions` 中"确认完成"按钮的条件从 `order.payStatus`(已付款)改为 `order.deliveryStatus >= 20`(已发货)
- **效果**:线下付款+未付款+已发货的订单,同时显示"确认收款"和"确认完成"两个按钮
### 门店端:拆分"确认完成"为"送达"和"确认完成"两个操作
- **新增操作类型** `deliver`送达deliveryStatus=20已发货且无 sendEndImg 时显示,上传送达照片后按钮自动隐藏(用 sendEndImg 判断,不改变 deliveryStatus
- **修改** `complete`(确认完成):仅已付款才可操作,只标记 orderStatus=1已完成不需要上传凭证
- ⚠️ `deliveryStatus=30` 是"部分发货"含义,不能用来表示"已送达",所有相关判断已清除
- **按钮显示逻辑**
| 场景 | 送达 | 确认完成 | 确认收款 |
|------|:---:|:---:|:---:|
| 线下付款+未付款+已发货(无送达照片) | ✅ | ❌ | ✅ |
| 线下付款+未付款+已发货(有送达照片) | ❌ | ❌ | ✅ |
| 已付款+已发货(无送达照片) | ✅ | ✅ | ❌ |
| 已付款+已发货(有送达照片) | ❌ | ✅ | ❌ |
- **deliveryStatus 含义**10=待发货, 20=已发货, 30=已送达/已收货
- **状态文案**deliveryStatus=30 + 未付款 → "已送达待收款"deliveryStatus=30 + 已付款 → "待确认完成"

View File

@@ -26,11 +26,10 @@ const getCardStatus = (order: ShopOrder): { text: string; color: string } => {
if (orderStatus === 1) return { text: '已完成', color: '#0e932e' }
// 线下付款(9)已发货但未确认收款:显示"已发货待收款"(红色),与门店端一致
if (!payStatus && payType === 9 && deliveryStatus === 20) return { text: '已发货待收款', color: '#ee0a24' }
if (!payStatus && payType === 9 && deliveryStatus === 20) return { text: '待付款,已发货', color: '#ee0a24' }
// 物流状态优先于付款状态(已发货/已收货的订单,即使未付款也显示物流状态)
// 物流状态优先于付款状态(已发货的订单,即使未付款也显示物流状态)
if (deliveryStatus === 20) return { text: '待收货', color: '#4b9cf5' }
if (deliveryStatus === 30) return { text: '已收货', color: '#0e932e' }
// 货到付款(8):下单时后端已 setPayStatus(true),不会走到这里
// 线下付款(9):保持 payStatus=false待商家确认收款应显示"待付款"与 Tab 一致

View File

@@ -72,12 +72,12 @@ const getOrderDisplayStatus = (order: ShopOrder): { title: string; bgColor: stri
}
// 线下付款已发货但未确认收款:显示"已发货待收款"(红色),与门店端一致
if (isOffline && !payStatus && (deliveryStatus === 20 || deliveryStatus === 30)) {
if (isOffline && !payStatus && deliveryStatus === 20) {
return { bgColor: '#ee0a24', title: '已发货待收款', subtitle: '商品已发货,请尽快转账付款' }
}
// 物流状态优先于付款状态(已发货/已收货的订单,即使未付款也显示物流状态)
if (deliveryStatus === 20 || deliveryStatus === 30) {
// 物流状态优先于付款状态
if (deliveryStatus === 20) {
return { bgColor: '#4b9cf5', title: '待收货', subtitle: '商品运输中,请注意查收' }
}
@@ -118,8 +118,8 @@ const getOrderPhase = (order: ShopOrder): OrderPhase => {
return orderStatus === OrderStatus.Cancelled || orderStatus === OrderStatus.RefundSuccess ? 'cancelled' : 'refund'
}
// 物流状态优先于付款状态(已发货/已收货的订单,即使未付款也进入 shipped 阶段)
if (deliveryStatus === 20 || deliveryStatus === 30) return 'shipped'
// 物流状态优先于付款状态(已发货的订单,即使未付款也进入 shipped 阶段)
if (deliveryStatus === 20) return 'shipped'
// 线下付款且未确认收款:等待商家确认,不显示"立即支付"按钮
if (isOffline && !payStatus) return 'offline_pending'

View File

@@ -151,9 +151,10 @@ function getOrderActions(order: ShopOrder): { label: string; type: OpType }[] {
actions.push({label: '发货', type: 'ship'})
}
}
// 送达:已发货即可上传送达照片(无论是否付款,线下付款先发货后结款场景也需要
const shipped = order.deliveryStatus != null && order.deliveryStatus >= 20
if (shipped) {
// 送达:已发货但未上传送达照片时显示deliveryStatus=20 且 sendEndImg 为空
const shipped = order.deliveryStatus != null && order.deliveryStatus === 20
const hasDeliverProof = order.sendEndImg && order.sendEndImg !== '[]'
if (shipped && !hasDeliverProof) {
actions.push({label: '送达', type: 'deliver'})
}
// 确认完成:仅已付款才可标记订单为已完成
@@ -449,8 +450,7 @@ export default function StoreOrdersPage() {
const updateData: any = {orderId: currentOrder.orderId}
if (opType === 'deliver') {
// 送达:上传送达照片,标记为已收货(不改变付款状态和订单完成状态)
updateData.deliveryStatus = 30 // 已收货
// 送达:上传送达照片(不改变付款状态、deliveryStatus 和订单完成状态)
updateData.deliveryTime = formatDateTime(new Date())
updateData.sendEndImg = JSON.stringify(proofImages)
} else if (opType === 'complete') {
@@ -837,35 +837,39 @@ export default function StoreOrdersPage() {
</View>
)}
{/* 凭证上传 */}
<Text className='text-sm text-gray-600 mb-3 block'>
{opType === 'confirmPay'
? '上传支付凭证(必填,如微信转账截图)'
: opType === 'deliver'
? '上传送达凭证(必填,配送货物到达后拍照上传最多3张'
: '上传凭证照片选填最多3张'}
</Text>
<View className='flex flex-wrap gap-3 mb-4'>
{proofImages.map((url, idx) => (
<View key={idx} className='relative'>
<Image className='w-20 h-20 rounded-lg bg-gray-50' src={getCompressedImageUrl(url)} mode='aspectFill'/>
<View
className='absolute -top-2 -right-2 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center'
onClick={() => removeProofImage(idx)}
>
<Text className='text-white text-xs'>×</Text>
</View>
{/* 凭证上传(确认完成不需要凭证) */}
{opType !== 'complete' && (
<>
<Text className='text-sm text-gray-600 mb-3 block'>
{opType === 'confirmPay'
? '上传支付凭证(必填,如微信转账截图'
: opType === 'deliver'
? '上传送达凭证必填配送货物到达后拍照上传最多3张'
: '上传凭证照片选填最多3张'}
</Text>
<View className='flex flex-wrap gap-3 mb-4'>
{proofImages.map((url, idx) => (
<View key={idx} className='relative'>
<Image className='w-20 h-20 rounded-lg bg-gray-50' src={getCompressedImageUrl(url)} mode='aspectFill'/>
<View
className='absolute -top-2 -right-2 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center'
onClick={() => removeProofImage(idx)}
>
<Text className='text-white text-xs'>×</Text>
</View>
</View>
))}
{proofImages.length < (opType === 'confirmPay' ? 1 : 3) && (
<View
className='w-20 h-20 rounded-lg bg-gray-50 border-2 border-dashed border-gray-200 flex items-center justify-center'
onClick={chooseProofImage}
>
<Text className='text-2xl text-gray-300'>+</Text>
</View>
)}
</View>
))}
{proofImages.length < (opType === 'confirmPay' ? 1 : 3) && (
<View
className='w-20 h-20 rounded-lg bg-gray-50 border-2 border-dashed border-gray-200 flex items-center justify-center'
onClick={chooseProofImage}
>
<Text className='text-2xl text-gray-300'>+</Text>
</View>
)}
</View>
</>
)}
{/* 备注(仅确认收款时显示) */}
{opType === 'confirmPay' && (