From ce7f5177eb606cb08ebe46586f53c478c64e0a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 1 Jul 2026 16:54:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(store):=20=E4=BC=98=E5=8C=96=E9=97=A8?= =?UTF-8?q?=E5=BA=97=E4=B8=AD=E5=BF=83=E8=AE=A2=E5=8D=95=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=92=8CCheckout=E8=AE=A2=E5=8D=95=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Checkout创建订单时直接传递payStatus和payTime字段防止未付款订单被删除 - 门店中心Tab改为三个(全部、待处理、已完成),并合并多个statusFilter查询 - 操作按钮逻辑调整为根据订单状态判断,已完成及已关闭订单无操作和删除按钮 - 状态文案和颜色适配完善,添加订单送达凭证照片预览功能 - 确认完成操作强制上传配送凭证照片,凭证支持JSON数组格式存储 - 收款操作支持上传凭证照片并追加至备注中 - 优化订单列表加载逻辑,多个请求结果合并去重并按创建时间降序排序 - 代码格式调整及UI细节优化,提升代码一致性和用户体验 --- .workbuddy/memory/2026-07-01.md | 19 + src/api/shop/shopOrder/model/index.ts | 4 + src/pages/shop/checkout.tsx | 12 +- src/pages/store/center/index.tsx | 965 ++++++++++++++------------ 4 files changed, 545 insertions(+), 455 deletions(-) diff --git a/.workbuddy/memory/2026-07-01.md b/.workbuddy/memory/2026-07-01.md index 73c45d5..d3f3064 100644 --- a/.workbuddy/memory/2026-07-01.md +++ b/.workbuddy/memory/2026-07-01.md @@ -37,3 +37,22 @@ - 已完成订单仅展示,无操作按钮 - 状态文案适配货到付款:待收款/待发货/待收货/已完成 - Tab 颜色改为绿色主题 + +## Checkout 页面货到付款 payStatus 修复 + +- 修改 `src/api/shop/shopOrder/model/index.ts`:`OrderCreateRequest` 增加 `payStatus` 和 `payTime` 可选字段 +- 修改 `src/pages/shop/checkout.tsx`: + - 创建订单时直接传 `payStatus: true` + `payTime`(格式 `yyyy-MM-dd HH:mm:ss`) + - 防止后端定时任务自动删除未付款的货到付款订单 + +## 门店中心 Tab 改为三个(全部 + 待处理 + 已完成) + +- 重写 `src/pages/store/center/index.tsx`:Tab 从2个改为3个 +- 参考后台管理 `shop-admin` 的 `statusFilter` 映射: + - 全部:不传 statusFilter(params: `[{}]`) + - 待处理:合并 `statusFilter=1`(待发货)+ `statusFilter=8`(已关闭) + - 已完成:`statusFilter=5` +- 操作按钮逻辑改为按订单状态判断(`isOrderActionable`),不再按 Tab 判断 + - 已完成/已关闭订单:无操作按钮,无删除按钮 + - 其他订单:显示"确认收款"/"确认完成"和"删除订单" +- 状态文案完善:已完成、已关闭、待收款、待发货、待收货、进行中 diff --git a/src/api/shop/shopOrder/model/index.ts b/src/api/shop/shopOrder/model/index.ts index 2b8d177..2ceeb7b 100644 --- a/src/api/shop/shopOrder/model/index.ts +++ b/src/api/shop/shopOrder/model/index.ts @@ -189,6 +189,10 @@ export interface OrderCreateRequest { addressId?: number; // 支付方式 payType: number; + // 支付状态(货到付款时传 true 防止定时任务删除) + payStatus?: boolean; + // 支付时间(货到付款时传当前时间) + payTime?: string; // 优惠券ID couponId?: number; // 备注 diff --git a/src/pages/shop/checkout.tsx b/src/pages/shop/checkout.tsx index 5d00790..ef0542d 100644 --- a/src/pages/shop/checkout.tsx +++ b/src/pages/shop/checkout.tsx @@ -9,7 +9,6 @@ import { getMyAvailableCoupons } from '@/api/shop/shopUserCoupon' import AddressCard from '@/components/business/AddressCard' import CouponCard from '@/components/business/CouponCard' import { createOrder } from '@/api/shop/shopOrder' -import type { ShopOrder } from '@/api/shop/shopOrder/model' import { listShopGoods } from '@/api/shop/shopGoods' import type { ShopGoods } from '@/api/shop/shopGoods/model' import type { ShopUserCoupon } from '@/api/shop/shopUserCoupon/model' @@ -258,11 +257,19 @@ const CheckoutPage: React.FC = () => { specInfo: item.skuSpec || item.sku?.sku || item.product?.specName, })) + // 格式化当前时间:yyyy-MM-dd HH:mm:ss(与后端 LocalDateTime 兼容) + const now = new Date() + const pad = (n: number) => n.toString().padStart(2, '0') + const payTime = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}` + // 创建订单 + // 货到付款:直接设置 payStatus=true + payTime,防止后端定时任务自动删除未付款订单 const orderParams: OrderCreateRequest = { goodsItems, addressId: defaultAddress.id, payType, + payStatus: true, + payTime, couponId: selectedCoupon?.id ? Number(selectedCoupon.id) : undefined, comments: remarks, deliveryType: 0, // 快递配送 @@ -270,9 +277,6 @@ const CheckoutPage: React.FC = () => { const res = await createOrder(orderParams) - // 货到付款 - 只需创建订单,无需调用支付接口 - console.log('订单创建成功', res) - // 清理数据 if (fromBuyNow) { Taro.removeStorageSync('buy_now') diff --git a/src/pages/store/center/index.tsx b/src/pages/store/center/index.tsx index d8f108e..cbe0166 100644 --- a/src/pages/store/center/index.tsx +++ b/src/pages/store/center/index.tsx @@ -1,504 +1,567 @@ -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: '门店中心', + navigationBarTitleText: '门店中心', }) -// ─── Tab 配置(货到付款模式:待处理 + 已完成)───────────────────── -type TabKey = 'pending' | 'completed' +// ─── Tab 配置(全部 + 待处理 + 已完成)────────────────────────── +type TabKey = 'all' | 'pending' | 'completed' -const TABS: { key: TabKey; label: string; params: Partial }[] = [ - { key: 'pending', label: '待处理', params: { statusFilter: 8 } }, - { key: 'completed', label: '已完成', params: { orderStatus: 1 } }, +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: '已完成', + pay: '已收款', + complete: '已完成', } const OP_DESC: Record = { - pay: '变更支付状态为已付款', - complete: '同时变更支付状态为已付款、发货状态为已完成、订单状态为已完成', + 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('上传请求失败')), + 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}` + 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 === 2) return '待处理' - if (order.orderStatus === 1) return '已完成' - if (order.payStatus === false) return '待收款' - if (order.payStatus && order.deliveryStatus === 10) return '待发货' - if (order.payStatus && order.deliveryStatus === 20) return '待收货' - return '待处理' + 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 === 2) return '#999' - if (order.orderStatus === 1) return '#0e932e' - if (order.payStatus === false) return '#ee0a24' - if (order.payStatus) return '#ff7d00' - return '#999' + 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 }[] { - const actions: { label: string; type: OpType }[] = [] - // 未付款 → 可确认收款,也可直接确认完成 - if (order.payStatus === false) { - 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 + 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 [activeTab, setActiveTab] = useState('pending') - // 订单列表与分页 - const [orderList, setOrderList] = useState([]) - const [page, setPage] = useState(1) - const [hasMore, setHasMore] = useState(true) - const [loading, setLoading] = useState(false) + // 订单列表与分页 + 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 [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) + const pageSize = 10 + const loadingRef = useRef(false) - /** 加载订单列表 */ - const loadOrders = useCallback(async (tab: TabKey, pageNo: number = 1, append = false) => { - if (loadingRef.current) return - loadingRef.current = true - setLoading(true) + /** 加载订单列表(待处理 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 - - const params: ShopOrderParam = { - ...tabConfig.params, - page: pageNo, - limit: pageSize, - } - - const res = await pageShopOrder(params) - const list = res?.list || [] - - setOrderList(prev => append ? [...prev, ...list] : list) - setPage(pageNo) - setHasMore(list.length >= 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 = proofImages.join(',') // 配送员送达拍照 - } - - // 收款操作如有凭证也追加到备注 - if (opType === 'pay' && proofImages.length > 0) { - const proofText = `【门店收款凭证】:${proofImages.join(',')}` - 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 tabConfig = TABS.find(t => t.key === tab) + if (!tabConfig) return - /** 渲染单个订单卡片 */ - const renderOrderCard = (order: ShopOrder) => { - const actions = activeTab === 'pending' ? getOrderActions(order) : [] - const orderGoods = (order as any).orderGoods || [] + // 并行请求所有 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 ( - - {/* 订单头部 */} - - 订单号:{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 && ( - - 配送凭证: - - {order.sendEndImg.split(',').map((img, i) => ( - - ))} - - - )} - - {/* 金额 + 支付方式 */} - - - {order.payType === 0 ? '余额支付' : order.payType === 4 ? '现金支付' : '货到付款'} - - - 实付:¥{order.payPrice || order.totalPrice} - - - - {/* 操作按钮(仅待处理订单) */} - - {/* 删除按钮 */} - 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 && ( - - + - - )} + + {/* Tab 栏 */} + + {TABS.map(tab => ( + setActiveTab(tab.key)} + > + + {tab.label} + + + ))} - {/* 操作按钮 */} - - - 取消 - - - {submitting ? ( - 提交中... + {/* 订单列表 */} + + {loading && orderList.length === 0 ? ( + + 加载中... + + ) : orderList.length === 0 ? ( + + 暂无订单 + ) : ( - 确认{OP_LABEL[opType]} + 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]} + )} + + + + + )} - )} - - ) + ) }