@@ -1,20 +1,24 @@
import React , { useState , useEffect , useCallback , useRef } from 'react'
import { View , Text , Image , ScrollView } from '@tarojs/components'
import Taro , { useDidShow } from '@tarojs/taro'
import { pageShopOrder , updateShopOrder , removeShopOrder } from '@/api/shop/shopOrder'
import type { ShopOrder , ShopOrderParam } from '@/api/shop/shopOrder/model'
import { TenantId } from '../../../config/app'
import React , { useState , useEffect , useCallback , useRef } from 'react'
import { View , Text , Image , ScrollView } from '@tarojs/components'
import Taro , { useDidShow } from '@tarojs/taro'
import { pageShopOrder , updateShopOrder , removeShopOrder } from '@/api/shop/shopOrder'
import type { ShopOrder , ShopOrderParam } from '@/api/shop/shopOrder/model'
import { TenantId } from '../../../config/app'
definePageConfig ( {
navigationBarTitleText : '门店中心' ,
} )
// ─── Tab 配置(货到付款模式: 待处理 + 已完成)─────────────────────
type TabKey = 'pending' | 'completed'
// ─── Tab 配置(全部 + 待处理 + 已完成)──────────────────────────
type TabKey = 'all' | ' pending' | 'completed'
const TABS : { key : TabKey ; label : string ; params : Partial < ShopOrderParam > } [ ] = [
{ key : 'pending' , label : '待处理' , params : { statusFilter : 8 } } ,
{ key : 'completed ' , label : '已完成 ' , params : { orderStatus : 1 } } ,
const TABS : { key : TabKey ; label : string ; params : Partial < ShopOrderParam > [ ] } [ ] = [
// 全部:不传 statusFilter
{ key : 'all ' , label : '全部 ' , params : [ { } ] } ,
// 已完成: statusFilter=5( 与后台管理一致)
{ key : 'completed' , label : '已完成' , params : [ { statusFilter : 5 } ] } ,
// 待处理:合并 statusFilter=1( 待发货) 和 statusFilter=8( 已关闭)
{ key : 'pending' , label : '已关闭' , params : [ { statusFilter : 1 } , { statusFilter : 8 } ] } ,
]
// ─── 操作类型 ─────────────────────────────────────────────────────
@@ -37,7 +41,7 @@ const uploadImage = (filePath: string): Promise<string> => {
url : 'https://server.websoft.top/api/oss/upload' ,
filePath ,
name : 'file' ,
header : { 'content-type' : 'application/json' , TenantId } ,
header : { 'content-type' : 'application/json' , TenantId } ,
success : ( res ) = > {
try {
const data = JSON . parse ( res . data )
@@ -68,34 +72,56 @@ function formatDateTime(date: Date): string {
return ` ${ y } - ${ m } - ${ d } ${ h } : ${ mi } : ${ s } `
}
/** 解析 sendEndImg: 兼容 JSON 数组(新格式)和逗号分隔(旧格式) */
function parseSendEndImg ( raw : string ) : string [ ] {
if ( ! raw || ! raw . trim ( ) ) return [ ]
const trimmed = raw . trim ( )
// 尝试 JSON 解析
if ( trimmed . startsWith ( '[' ) ) {
try {
const arr = JSON . parse ( trimmed )
if ( Array . isArray ( arr ) ) return arr . filter ( Boolean )
} catch { /* fallback to comma split */
}
}
// 旧格式:逗号分隔(兼容单张图不含逗号的 URL)
return trimmed . split ( ',' ) . map ( s = > s . trim ( ) ) . filter ( Boolean )
}
function getStatusText ( order : ShopOrder ) : string {
if ( order . orderStatus === 2 ) return '待处理'
if ( order . orderStatus === 1 ) return '已完成'
if ( order . pay Status === false ) return '待收款 '
if ( order . order Status === 2 ) return '已关闭 '
if ( order . payStatus === false || order . payStatus === null ) return '待收款'
if ( order . payStatus && order . deliveryStatus === 10 ) return '待发货'
if ( order . payStatus && order . deliveryStatus === 20 ) return '待收货'
return '待处理 '
return '进行中 '
}
function getStatusColor ( order : ShopOrder ) : string {
if ( order . orderStatus === 2 ) return '#999'
if ( order . orderStatus === 1 ) return '#0e932e'
if ( order . pay Status === false ) return '#ee0a24 '
if ( order . order Status === 2 ) return '#999 '
if ( order . payStatus === false || order . payStatus === null ) return '#ee0a24'
if ( order . payStatus ) return '#ff7d00'
return '#999'
}
/** 获取待处理订单可执行的操作 */
/** 判断订单是否可操作(非已完成、非已关闭) */
function isOrderActionable ( order : ShopOrder ) : boolean {
return order . orderStatus !== 1 && order . orderStatus !== 2
}
/** 获取订单可执行的操作 */
function getOrderActions ( order : ShopOrder ) : { label : string ; type : OpType } [ ] {
if ( ! isOrderActionable ( order ) ) return [ ]
const actions : { label : string ; type : OpType } [ ] = [ ]
// 未付款 → 可确认收款,也可直接确认完成
if ( order . payStatus === false ) {
actions . push ( { label : '确认收款' , type : 'pay' } )
actions . push ( { label : '确认完成' , type : 'complete' } )
if ( order . payStatus === false || order . payStatus === null ) {
actions . push ( { label : '确认收款' , type : 'pay' } )
actions . push ( { label : '确认完成' , type : 'complete' } )
}
// 已付款但未完成 → 可确认完成
if ( order . payStatus && order . orderStatus !== 1 && order . orderStatus !== 2 ) {
actions . push ( { label : '确认完成' , type : 'complete' } )
actions . push ( { label : '确认完成' , type : 'complete' } )
}
return actions
}
@@ -120,7 +146,7 @@ export default function StoreCenterPage() {
const pageSize = 10
const loadingRef = useRef ( false )
/** 加载订单列表 */
/** 加载订单列表(待处理 Tab 会合并多个 statusFilter 的结果) */
const loadOrders = useCallback ( async ( tab : TabKey , pageNo : number = 1 , append = false ) = > {
if ( loadingRef . current ) return
loadingRef . current = true
@@ -130,20 +156,37 @@ export default function StoreCenterPage() {
const tabConfig = TABS . find ( t = > t . key === tab )
if ( ! tabConfig ) return
const params : ShopOrderParam = {
. . . tabConfig . params ,
page : pageNo ,
limit : pageSize ,
}
// 并行请求所有 params 组合,合并去重
const allRequests = tabConfig . params . map ( p = >
pageShopOrder ( { . . . p , page : pageNo , limit : pageSize } )
)
const allResults = await Promise . all ( allRequests )
const res = await pageShopOrder ( params )
// 合并所有结果列表,按 orderId 去重
const mergedList = allResults . reduce < ShopOrder [ ] > ( ( acc , res ) = > {
const list = res ? . list || [ ]
list . forEach ( item = > {
if ( ! acc . some ( existing = > existing . orderId === item . orderId ) ) {
acc . push ( item )
}
} )
return acc
} , [ ] )
setOrderList ( prev = > append ? [ . . . prev , . . . list ] : list )
// 按 createTime 降序排列
mergedList . sort ( ( a , b ) = > {
const ta = a . createTime ? new Date ( a . createTime ) . getTime ( ) : 0
const tb = b . createTime ? new Date ( b . createTime ) . getTime ( ) : 0
return tb - ta
} )
setOrderList ( prev = > append ? [ . . . prev , . . . mergedList ] : mergedList )
setPage ( pageNo )
setHasMore ( list . length >= pageSize )
// 只要任意一个请求还有数据就允许继续加载
const maxLen = Math . max ( . . . allResults . map ( r = > ( r ? . list || [ ] ) . length ) )
setHasMore ( maxLen >= pageSize )
} catch ( e : any ) {
Taro . showToast ( { title : e.message || '加载失败' , icon : 'none' } )
Taro . showToast ( { title : e.message || '加载失败' , icon : 'none' } )
if ( ! append ) setOrderList ( [ ] )
} finally {
loadingRef . current = false
@@ -196,13 +239,13 @@ export default function StoreCenterPage() {
success : async ( res ) = > {
for ( const filePath of res . tempFilePaths ) {
try {
Taro . showLoading ( { title : '上传中...' } )
Taro . showLoading ( { title : '上传中...' } )
const url = await uploadImage ( filePath )
Taro . hideLoading ( )
setProofImages ( prev = > [ . . . prev , url ] )
} catch ( e : any ) {
Taro . hideLoading ( )
Taro . showToast ( { title : e.message || '上传失败' , icon : 'none' } )
Taro . showToast ( { title : e.message || '上传失败' , icon : 'none' } )
}
}
} ,
@@ -220,13 +263,13 @@ export default function StoreCenterPage() {
// 确认完成必须上传凭证照片
if ( opType === 'complete' && proofImages . length === 0 ) {
Taro . showToast ( { title : '请上传配送凭证照片' , icon : 'none' } )
Taro . showToast ( { title : '请上传配送凭证照片' , icon : 'none' } )
return
}
setSubmitting ( true )
try {
const updateData : any = { orderId : currentOrder.orderId }
const updateData : any = { orderId : currentOrder.orderId }
if ( opType === 'pay' ) {
// 确认收款:变更支付状态为已付款
@@ -238,21 +281,21 @@ export default function StoreCenterPage() {
updateData . payTime = formatDateTime ( new Date ( ) )
updateData . deliveryStatus = 20 // 发货状态 → 已完成
updateData . orderStatus = 1 // 订单状态 → 已完成
updateData . sendEndImg = proofImages . join ( ',' ) // 配送员送达拍照
updateData . sendEndImg = JSON . stringify ( proofImages ) // 配送员送达拍照( JSON数组)
}
// 收款操作如有凭证也追加到备注
if ( opType === 'pay' && proofImages . length > 0 ) {
const proofText = ` 【门店收款凭证】: ${ proofImages . join ( ',' ) } `
const proofText = ` 【门店收款凭证】: ${ JSON . stringify ( proofImages ) } `
updateData . comments = ( currentOrder . comments || '' ) + ` \ n ${ proofText } `
}
await updateShopOrder ( updateData )
Taro . showToast ( { title : '操作成功' , icon : 'success' } )
Taro . showToast ( { title : '操作成功' , icon : 'success' } )
closeModal ( )
loadOrders ( activeTab , 1 ) // 刷新列表
} catch ( e : any ) {
Taro . showToast ( { title : e.message || '操作失败' , icon : 'none' } )
Taro . showToast ( { title : e.message || '操作失败' , icon : 'none' } )
} finally {
setSubmitting ( false )
}
@@ -267,14 +310,14 @@ export default function StoreCenterPage() {
success : async ( res ) = > {
if ( ! res . confirm ) return
try {
Taro . showLoading ( { title : '删除中...' } )
Taro . showLoading ( { title : '删除中...' } )
await removeShopOrder ( order . orderId )
Taro . hideLoading ( )
Taro . showToast ( { title : '删除成功' , icon : 'success' } )
Taro . showToast ( { title : '删除成功' , icon : 'success' } )
loadOrders ( activeTab , 1 )
} catch ( e : any ) {
Taro . hideLoading ( )
Taro . showToast ( { title : e.message || '删除失败' , icon : 'none' } )
Taro . showToast ( { title : e.message || '删除失败' , icon : 'none' } )
}
} ,
} )
@@ -282,7 +325,8 @@ export default function StoreCenterPage() {
/** 渲染单个订单卡片 */
const renderOrderCard = ( order : ShopOrder ) = > {
const actions = activeTab === 'pending' ? getOrderActions( order ) : [ ]
const actions = getOrderActions ( order )
const canDelete = isOrderActionable ( order ) // 仅未完成、未关闭的订单可删除
const orderGoods = ( order as any ) . orderGoods || [ ]
return (
@@ -290,7 +334,7 @@ export default function StoreCenterPage() {
{ /* 订单头部 */ }
< View className = 'flex justify-between items-center mb-3' >
< Text className = 'text-xs text-gray-400' > 订 单 号 : { order . orderNo } < / Text >
< Text className = 'text-xs' style = { { color : getStatusColor ( order ) } } >
< Text className = 'text-xs' style = { { color : getStatusColor ( order ) } } >
{ getStatusText ( order ) }
< / Text >
< / View >
@@ -299,7 +343,8 @@ export default function StoreCenterPage() {
{ orderGoods . map ( ( goods : any , idx : number ) = > (
< View key = { idx } className = 'flex items-center gap-3 mb-3' >
{ goods . coverImage && (
< Image className = 'w-16 h-16 rounded-lg bg-gray-50' src = { goods . coverImage } mode = 'aspectFill' / >
< Image className = 'w-16 h-16 rounded-lg bg-gray-50' src = { goods . coverImage }
mode = 'aspectFill' / >
) }
< View className = 'flex-1' >
< Text className = 'text-sm text-gray-800 block' > { goods . goodsName } < / Text >
@@ -325,38 +370,54 @@ export default function StoreCenterPage() {
) }
{ /* 送达凭证(已完成订单) */ }
{ order . sendEndImg && (
{ order . sendEndImg && ( ( ) = > {
const imgs = parseSendEndImg ( order . sendEndImg )
return imgs . length > 0 && (
< View className = 'bg-gray-50 rounded-lg p-3 mb-3' >
< Text className = 'text-xs text-gray-500 mb-2 block' > 配 送 凭 证 : < / Text >
< View className = 'flex flex-wrap gap-2' >
{ order . sendEndImg . split ( ',' ) . map ( ( img , i ) = > (
< Image key = { i } className = 'w-16 h-16 rounded-lg' src = { img } mode = 'aspectFill' / >
{ imgs . map ( ( img , i ) = > (
< Image
key = { i }
className = 'w-20 h-20 rounded-lg bg-gray-100'
src = { img }
mode = 'aspectFill'
onClick = { ( ) = > Taro . previewImage ( {
current : img ,
urls : imgs
} ) }
/ >
) ) }
< / View >
< / View >
) }
)
} ) ( ) }
{ /* 金额 + 支付方式 */ }
< View className = 'flex justify-between items-center mb-3' >
< Text className = 'text-xs text-gray-400' >
{ order . payType === 0 ? '余额支付 ' : order . payType === 4 ? '现金支付' : '货到付款' }
{ order . payType === 0 ? '货到付款 ' : order . payType === 4 ? '现金支付' : '货到付款' }
< / Text >
< Text className = 'text-sm text-gray-700' >
实 付 : < Text className = 'text-red-500 font-medium' > ¥ { order . payPrice || order . totalPrice } < / Text >
< / Text >
< / View >
{ /* 操作按钮(仅待处理订单) */ }
{ /* 操作按钮 */ }
< View className = 'flex justify-between items-center border-t border-gray-50 pt-3' >
{ /* 删除按钮 */ }
{ /* 删除按钮:仅未完成/未关闭的订单显示 */ }
{ canDelete ? (
< View
className = 'px-3 py-1.5'
onClick = { ( ) = > handleDelete ( order ) }
>
< Text className = 'text-xs text-gray-400' > 删 除 订 单 < / Text >
< / View >
) : (
< View / >
) }
< View className = ' flex gap-2' >
< View className = { ` flex gap-2 ${ ! canDelete ? 'w-full justify-end' : '' } ` } >
{ actions . map ( act = > (
< View
key = { act . type }
@@ -390,7 +451,8 @@ export default function StoreCenterPage() {
} ` }
onClick = { ( ) = > setActiveTab ( tab . key ) }
>
< Text className = { ` text-sm ${ activeTab === tab . key ? 'text-green-500 font-medium' : 'text-gray-500' } ` } >
< Text
className = { ` text-sm ${ activeTab === tab . key ? 'text-green-500 font-medium' : 'text-gray-500' } ` } >
{ tab . label }
< / Text >
< / View >
@@ -400,7 +462,7 @@ export default function StoreCenterPage() {
{ /* 订单列表 */ }
< ScrollView
scrollY
style = { { height : 'calc(100vh - 50px)' } }
style = { { height : 'calc(100vh - 50px)' } }
onScrollToLower = { handleLoadMore }
lowerThreshold = { 100 }
>
@@ -425,14 +487,14 @@ export default function StoreCenterPage() {
< Text className = 'text-gray-300 text-xs' > 没 有 更 多 了 < / Text >
< / View >
) }
< View className = 'h-6' / >
< View className = 'h-6' / >
< / ScrollView >
{ /* 操作弹窗 */ }
{ showModal && (
< View className = 'fixed inset-0 z-50 flex items-end justify-center' >
{ /* 遮罩 */ }
< View className = 'absolute inset-0 bg-black/50' onClick = { closeModal } / >
< View className = 'absolute inset-0 bg-black/50' onClick = { closeModal } / >
{ /* 弹窗内容 */ }
< View className = 'relative bg-white rounded-t-2xl w-full px-5 pt-6 pb-10' >
< Text className = 'text-lg font-medium text-gray-800 text-center mb-5 block' >
@@ -444,7 +506,8 @@ export default function StoreCenterPage() {
< View className = 'bg-gray-50 rounded-xl p-4 mb-5' >
< Text className = 'text-sm text-gray-700 block' > 订 单 号 : { currentOrder . orderNo } < / Text >
< Text className = 'text-sm text-gray-700 mt-1 block' >
实 付 金 额 : < Text className = 'text-red-500 font-medium' > ¥ { currentOrder . payPrice || currentOrder . totalPrice } < / Text >
实 付 金 额 : < Text
className = 'text-red-500 font-medium' > ¥ { currentOrder . payPrice || currentOrder . totalPrice } < / Text >
< / Text >
< Text className = 'text-xs text-gray-500 mt-2 block' >
操 作 说 明 : { OP_DESC [ opType ] }
@@ -459,7 +522,7 @@ export default function StoreCenterPage() {
< View className = 'flex flex-wrap gap-3 mb-6' >
{ proofImages . map ( ( url , idx ) = > (
< View key = { idx } className = 'relative' >
< Image className = 'w-20 h-20 rounded-lg bg-gray-50' src = { url } mode = 'aspectFill' / >
< Image className = 'w-20 h-20 rounded-lg bg-gray-50' src = { 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 ) }