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 = 'all' | 'pending' | 'completed' const TABS: { key: TabKey; label: string; params: Partial[] }[] = [ // 全部:不传 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}]}, ] // ─── 操作类型 ───────────────────────────────────────────────────── type OpType = 'pay' | 'complete' const OP_LABEL: Record = { pay: '已收款', complete: '已完成', } const OP_DESC: Record = { pay: '变更支付状态为已付款', complete: '同时变更支付状态为已付款、发货状态为已完成、订单状态为已完成', } // ─── 图片上传 ───────────────────────────────────────────────────── const uploadImage = (filePath: string): Promise => { return new Promise((resolve, reject) => { Taro.uploadFile({ url: 'https://server.websoft.top/api/oss/upload', filePath, name: 'file', header: {'content-type': 'application/json', TenantId}, success: (res) => { try { const data = JSON.parse(res.data) if (data.code === 0 && data.data?.url) { resolve(data.data.url) } else { reject(new Error(data.message || '上传失败')) } } catch { reject(new Error('解析上传响应失败')) } }, fail: () => reject(new Error('上传请求失败')), }) }) } // ─── 状态辅助函数 ────────────────────────────────────────────────── /** 格式化日期为 Spring Boot LocalDateTime 可接受的格式:yyyy-MM-dd HH:mm:ss */ function formatDateTime(date: Date): string { const y = date.getFullYear() const m = String(date.getMonth() + 1).padStart(2, '0') const d = String(date.getDate()).padStart(2, '0') const h = String(date.getHours()).padStart(2, '0') const mi = String(date.getMinutes()).padStart(2, '0') const s = String(date.getSeconds()).padStart(2, '0') 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 === 1) return '已完成' if (order.orderStatus === 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 '进行中' } function getStatusColor(order: ShopOrder): string { if (order.orderStatus === 1) return '#0e932e' if (order.orderStatus === 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 || 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'}) } return actions } // ─── 页面组件 ────────────────────────────────────────────────────── export default function StoreCenterPage() { const [activeTab, setActiveTab] = useState('pending') // 订单列表与分页 const [orderList, setOrderList] = useState([]) const [page, setPage] = useState(1) const [hasMore, setHasMore] = useState(true) const [loading, setLoading] = useState(false) // 操作弹窗状态 const [showModal, setShowModal] = useState(false) const [currentOrder, setCurrentOrder] = useState(null) const [opType, setOpType] = useState('pay') const [proofImages, setProofImages] = useState([]) const [submitting, setSubmitting] = useState(false) 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 setLoading(true) try { const tabConfig = TABS.find(t => t.key === tab) if (!tabConfig) return // 并行请求所有 params 组合,合并去重 const allRequests = tabConfig.params.map(p => pageShopOrder({...p, page: pageNo, limit: pageSize}) ) const allResults = await Promise.all(allRequests) // 合并所有结果列表,按 orderId 去重 const mergedList = allResults.reduce((acc, res) => { const list = res?.list || [] list.forEach(item => { if (!acc.some(existing => existing.orderId === item.orderId)) { acc.push(item) } }) return acc }, []) // 按 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) // 只要任意一个请求还有数据就允许继续加载 const maxLen = Math.max(...allResults.map(r => (r?.list || []).length)) setHasMore(maxLen >= pageSize) } catch (e: any) { Taro.showToast({title: e.message || '加载失败', icon: 'none'}) if (!append) setOrderList([]) } finally { loadingRef.current = false setLoading(false) } }, []) // 切换 tab 时重新加载 useEffect(() => { loadOrders(activeTab, 1) }, [activeTab, loadOrders]) // 页面重新显示时刷新 useDidShow(() => { loadOrders(activeTab, 1) }) /** 加载更多 */ const handleLoadMore = () => { if (hasMore && !loadingRef.current) { loadOrders(activeTab, page + 1, true) } } /** 打开操作弹窗 */ const openModal = (order: ShopOrder, type: OpType) => { setCurrentOrder(order) setOpType(type) setProofImages([]) setShowModal(true) } /** 关闭弹窗 */ const closeModal = () => { setShowModal(false) setCurrentOrder(null) setProofImages([]) } /** 选择并上传凭证图片 */ const chooseProofImage = () => { const maxCount = 3 const remaining = maxCount - proofImages.length if (remaining <= 0) return Taro.chooseImage({ count: remaining, sizeType: ['compressed'], sourceType: ['camera', 'album'], success: async (res) => { for (const filePath of res.tempFilePaths) { try { 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'}) } } }, }) } /** 移除凭证图片 */ const removeProofImage = (idx: number) => { setProofImages(prev => prev.filter((_, i) => i !== idx)) } /** 提交操作 */ const submitOperation = async () => { if (!currentOrder) return // 确认完成必须上传凭证照片 if (opType === 'complete' && proofImages.length === 0) { Taro.showToast({title: '请上传配送凭证照片', icon: 'none'}) return } setSubmitting(true) try { const updateData: any = {orderId: currentOrder.orderId} if (opType === 'pay') { // 确认收款:变更支付状态为已付款 updateData.payStatus = true updateData.payTime = formatDateTime(new Date()) } else if (opType === 'complete') { // 确认完成:变更支付状态为已付款、发货状态为已完成、订单状态为已完成 updateData.payStatus = true updateData.payTime = formatDateTime(new Date()) updateData.deliveryStatus = 20 // 发货状态 → 已完成 updateData.orderStatus = 1 // 订单状态 → 已完成 updateData.sendEndImg = JSON.stringify(proofImages) // 配送员送达拍照(JSON数组) } // 收款操作如有凭证也追加到备注 if (opType === 'pay' && proofImages.length > 0) { const proofText = `【门店收款凭证】:${JSON.stringify(proofImages)}` updateData.comments = (currentOrder.comments || '') + `\n${proofText}` } await updateShopOrder(updateData) Taro.showToast({title: '操作成功', icon: 'success'}) closeModal() loadOrders(activeTab, 1) // 刷新列表 } catch (e: any) { Taro.showToast({title: e.message || '操作失败', icon: 'none'}) } finally { setSubmitting(false) } } /** 删除订单 */ const handleDelete = (order: ShopOrder) => { Taro.showModal({ title: '提示', content: `确定要删除订单 ${order.orderNo} 吗?删除后无法恢复。`, confirmColor: '#ee0a24', success: async (res) => { if (!res.confirm) return try { Taro.showLoading({title: '删除中...'}) await removeShopOrder(order.orderId) Taro.hideLoading() Taro.showToast({title: '删除成功', icon: 'success'}) loadOrders(activeTab, 1) } catch (e: any) { Taro.hideLoading() Taro.showToast({title: e.message || '删除失败', icon: 'none'}) } }, }) } /** 渲染单个订单卡片 */ const renderOrderCard = (order: ShopOrder) => { const actions = getOrderActions(order) const canDelete = isOrderActionable(order) // 仅未完成、未关闭的订单可删除 const orderGoods = (order as any).orderGoods || [] return ( {/* 订单头部 */} 订单号:{order.orderNo} {getStatusText(order)} {/* 商品列表 */} {orderGoods.map((goods: any, idx: number) => ( {goods.coverImage && ( )} {goods.goodsName} {goods.specInfo && ( {goods.specInfo} )} ¥{goods.price} x{goods.quantity} ))} {/* 收货信息 */} {(order.realName || order.phone) && ( {order.realName} {order.phone} {order.address && ( {order.address} )} )} {/* 送达凭证(已完成订单) */} {order.sendEndImg && (() => { const imgs = parseSendEndImg(order.sendEndImg) return imgs.length > 0 && ( 配送凭证: {imgs.map((img, i) => ( Taro.previewImage({ current: img, urls: imgs })} /> ))} ) })()} {/* 金额 + 支付方式 */} {order.payType === 0 ? '货到付款' : order.payType === 4 ? '现金支付' : '货到付款'} 实付:¥{order.payPrice || order.totalPrice} {/* 操作按钮 */} {/* 删除按钮:仅未完成/未关闭的订单显示 */} {canDelete ? ( handleDelete(order)} > 删除订单 ) : ( )} {actions.map(act => ( openModal(order, act.type)} > {act.label} ))} ) } return ( {/* Tab 栏 */} {TABS.map(tab => ( setActiveTab(tab.key)} > {tab.label} ))} {/* 订单列表 */} {loading && orderList.length === 0 ? ( 加载中... ) : orderList.length === 0 ? ( 暂无订单 ) : ( orderList.map(renderOrderCard) )} {loading && orderList.length > 0 && ( 加载中... )} {!hasMore && orderList.length > 0 && ( 没有更多了 )} {/* 操作弹窗 */} {showModal && ( {/* 遮罩 */} {/* 弹窗内容 */} 确认{OP_LABEL[opType]} {/* 订单信息 */} {currentOrder && ( 订单号:{currentOrder.orderNo} 实付金额:¥{currentOrder.payPrice || currentOrder.totalPrice} 操作说明:{OP_DESC[opType]} )} {/* 凭证上传 */} 上传凭证照片{opType === 'complete' ? '(必填,配送货物到达后拍照上传,最多3张)' : '(选填,最多3张)'} {proofImages.map((url, idx) => ( removeProofImage(idx)} > × ))} {proofImages.length < 3 && ( + )} {/* 操作按钮 */} 取消 {submitting ? ( 提交中... ) : ( 确认{OP_LABEL[opType]} )} )} ) }