diff --git a/src/api/payment/index.ts b/src/api/payment/index.ts index 74b9b74..e6bb0a8 100644 --- a/src/api/payment/index.ts +++ b/src/api/payment/index.ts @@ -5,7 +5,7 @@ import type { ApiResult } from '@/api'; * 统一支付 */ export async function pay(data: any) { - const res = await request.post>('/payment/create',data); + const res = await request.post>('/payment/create-with-order',data); if (res.code === 0) { return res.data; } diff --git a/src/api/shop/shopOrder/model/index.ts b/src/api/shop/shopOrder/model/index.ts index 92709f8..45cd3ce 100644 --- a/src/api/shop/shopOrder/model/index.ts +++ b/src/api/shop/shopOrder/model/index.ts @@ -153,8 +153,8 @@ export interface ShopOrder { * 订单商品项 */ export interface OrderGoodsItem { - goodsId: number; - quantity: number; + goodsId?: number; + quantity?: number; skuId?: number; specInfo?: string; } @@ -164,7 +164,7 @@ export interface OrderGoodsItem { */ export interface OrderCreateRequest { // 商品信息列表 - goodsItems: OrderGoodsItem[]; + goodsItems?: OrderGoodsItem[]; // 收货地址ID addressId?: number; // 支付方式 @@ -185,8 +185,8 @@ export interface OrderCreateRequest { * 订单商品项 */ export interface OrderGoodsItem { - goodsId: number; - quantity: number; + goodsId?: number; + quantity?: number; skuId?: number; specInfo?: string; } @@ -195,8 +195,10 @@ export interface OrderGoodsItem { * 创建订单请求 */ export interface OrderCreateRequest { + // 订单编号 + orderNo?: string; // 商品信息列表 - goodsItems: OrderGoodsItem[]; + goodsItems?: OrderGoodsItem[]; // 收货地址ID addressId?: number; // 支付方式 @@ -209,6 +211,8 @@ export interface OrderCreateRequest { deliveryType?: number; // 自提店铺ID selfTakeMerchantId?: number; + // 订单类型 + type?: number; } /** diff --git a/src/clinic/clinicPatientUser/prescription.tsx b/src/clinic/clinicPatientUser/prescription.tsx index 34c981e..f6d5f1f 100644 --- a/src/clinic/clinicPatientUser/prescription.tsx +++ b/src/clinic/clinicPatientUser/prescription.tsx @@ -4,11 +4,11 @@ import {Button, Cell, CellGroup, Space, Empty, ConfigProvider, Tag} from '@nutui import {View, Text} from '@tarojs/components' import {ClinicPrescription} from "@/api/clinic/clinicPrescription/model"; import { - pageClinicPrescription, + pageClinicPrescription, updateClinicPrescription, WxPayResult } from "@/api/clinic/clinicPrescription"; import {copyText} from "@/utils/common"; -import {pay} from "@/api/payment"; +import {createOrder} from "@/api/shop/shopOrder"; const ClinicPrescriptionList = () => { const [list, setList] = useState([]) @@ -92,38 +92,19 @@ const ClinicPrescriptionList = () => { try { // 调用统一支付接口 - const result = await pay( - // addressId: 10951, - // orderId: 0, - // deliveryType: 0, - // paymentType: 'JSAPI', - // amount: 1, - // subject: '开处方' + const result = await createOrder( { - "paymentType": "WECHAT", - "amount": 100.00, - "subject": "网站建设服务订单", - "description": "网站建设服务", - "orderInfo": { - "type": 0, - "realName": "无", - "address": "无", - "addressId": 0, - "deliveryType": 0, - "channel": 0, - "merchantId": null, - "merchantName": null, - "couponId": null, - "comments": "网站建设服务订单", - "goodsItems": [ - { - "goodsId": 10004, - "skuId": null, - "quantity": 1, - "specInfo": null - } - ] - } + type: 1, + addressId: 10951, + comments: '开方', + deliveryType: 0, + payType: 1, + goodsItems: [ + { + goodsId: 10056, + quantity: 1 + } + ] } ); console.log(result, 'resultresultresultresultresultresult') @@ -144,6 +125,12 @@ const ClinicPrescriptionList = () => { // 支付成功 console.log('支付成功,订单号:', result.orderNo); + await updateClinicPrescription({ + id: item.id, + orderNo: result.orderNo, + status: 2 + }) + Taro.showToast({ title: '支付成功', icon: 'success' @@ -196,9 +183,9 @@ const ClinicPrescriptionList = () => { {list.map((item) => ( 待支付 + {item.status == 2 ? '已支付' : '待支付'} } onClick={() => copyText(`${item.orderNo}`)} /> @@ -239,16 +226,18 @@ const ClinicPrescriptionList = () => { } /> - - - - - + {item.status == 0 && ( + + + + + + )} ))} diff --git a/src/clinic/clinicPrescription/_index.tsx b/src/clinic/clinicPrescription/_index.tsx new file mode 100644 index 0000000..9fd0e85 --- /dev/null +++ b/src/clinic/clinicPrescription/_index.tsx @@ -0,0 +1,201 @@ +import {useState} from "react"; +import Taro, {useDidShow} from '@tarojs/taro' +import {Button, Cell, CellGroup, Space, Empty, ConfigProvider, Tag} from '@nutui/nutui-react-taro' +import {Del, Edit} from '@nutui/icons-react-taro' +import {View, Text} from '@tarojs/components' +import {ClinicPrescription} from "@/api/clinic/clinicPrescription/model"; +import { + pageClinicPrescription, + removeClinicPrescription +} from "@/api/clinic/clinicPrescription"; +import FixedButton from "@/components/FixedButton"; +import {copyText} from "@/utils/common"; + +const ClinicPrescriptionList = () => { + const [list, setList] = useState([]) + const [loading, setLoading] = useState(false) + + const reload = () => { + setLoading(true) + pageClinicPrescription({ + // 添加查询条件 + doctorId: Taro.getStorageSync('UserId'), + }) + .then(data => { + setList(data?.list || []) + }) + .catch(() => { + Taro.showToast({ + title: '获取数据失败', + icon: 'error' + }); + }) + .finally(() => { + setLoading(false) + }) + } + + const onDel = async (item: ClinicPrescription) => { + const res = await Taro.showModal({ + title: '确认删除', + content: `确定要删除处方编号「${item.orderNo}」吗?`, + }) + + if (res.confirm) { + try { + await removeClinicPrescription(item.id) + Taro.showToast({ + title: '删除成功', + icon: 'success' + }); + reload(); + } catch (error) { + Taro.showToast({ + title: '删除失败', + icon: 'error' + }); + } + } + } + + const onEdit = (item: ClinicPrescription) => { + Taro.navigateTo({ + url: `/clinic/clinicPrescription/add?id=${item.id}` + }) + } + + const onDetail = (item: ClinicPrescription) => { + Taro.navigateTo({ + url: `/clinic/clinicPrescription/detail?id=${item.id}` + }) + } + + const getSexName = (sex?: number) => { + return sex === 0 ? '男' : sex === 1 ? '女' : '' + } + + useDidShow(() => { + reload() + }); + + if (list.length === 0 && !loading) { + return ( + + + + + + + + + ) + } + + return ( + <> + + {list.map((item) => ( + + 待支付 + } + onClick={() => copyText(`${item.orderNo}`)} + /> + + {item.realName} + {item.age}岁 + {getSexName(item.sex)} + + } + /> + {/**/} + {/* {getPrescriptionTypeText(item.prescriptionType)}*/} + {/* */} + {/* }*/} + {/*/>*/} + {item.diagnosis && ( + + {item.diagnosis.length > 20 + ? `${item.diagnosis.substring(0, 20)}...` + : item.diagnosis} + + } + /> + )} + + ¥{item.orderPrice || '0.00'} + + } + /> + + {item.createTime} + + } + /> + + + + + + + + + ))} + + + Taro.navigateTo({url: '/clinic/clinicPrescription/add'})} + /> + + ) +} + +export default ClinicPrescriptionList; diff --git a/src/clinic/clinicPrescription/components/OrderList.tsx b/src/clinic/clinicPrescription/components/OrderList.tsx new file mode 100644 index 0000000..b924ffd --- /dev/null +++ b/src/clinic/clinicPrescription/components/OrderList.tsx @@ -0,0 +1,806 @@ +import {Avatar, Cell, Space, Empty, Tabs, Button, TabPane, Image, Dialog} from '@nutui/nutui-react-taro' +import {useEffect, useState, useCallback, CSSProperties} from "react"; +import {View, Text} from '@tarojs/components' +import Taro from '@tarojs/taro'; +import {InfiniteLoading} from '@nutui/nutui-react-taro' +import dayjs from "dayjs"; +import {pageShopOrder, updateShopOrder, createOrder} from "@/api/shop/shopOrder"; +import {ShopOrder, ShopOrderParam} from "@/api/shop/shopOrder/model"; +import {listShopOrderGoods} from "@/api/shop/shopOrderGoods"; +import {ShopOrderGoods} from "@/api/shop/shopOrderGoods/model"; +import {copyText} from "@/utils/common"; +import PaymentCountdown from "@/components/PaymentCountdown"; +import {PaymentType} from "@/utils/payment"; +import {goTo} from "@/utils/navigation"; +import {pageClinicPrescription} from "@/api/clinic/clinicPrescription"; + +// 判断订单是否支付已过期 +const isPaymentExpired = (createTime: string, timeoutHours: number = 24): boolean => { + if (!createTime) return false; + const createTimeObj = dayjs(createTime); + const expireTime = createTimeObj.add(timeoutHours, 'hour'); + const now = dayjs(); + return now.isAfter(expireTime); +}; + +const getInfiniteUlStyle = (showSearch: boolean = false): CSSProperties => ({ + marginTop: showSearch ? '0' : '0', // 如果显示搜索框,增加更多的上边距 + height: showSearch ? '75vh' : '84vh', // 相应调整高度 + width: '100%', + padding: '0', + overflowY: 'auto', + overflowX: 'hidden' + // 注意:小程序不支持 boxShadow +}) + +// 统一的订单状态标签配置,与后端 statusFilter 保持一致 +const tabs = [ + { + index: 0, + key: '全部', + title: '全部', + description: '所有订单', + statusFilter: -1 // 使用-1表示全部订单 + }, + { + index: 1, + key: '待付款', + title: '待付款', + description: '等待付款的订单', + statusFilter: 0 // 对应后端:pay_status = false + }, + { + index: 2, + key: '待发货', + title: '待发货', + description: '已付款待发货的订单', + statusFilter: 1 // 对应后端:pay_status = true AND delivery_status = 10 + }, + { + index: 3, + key: '待收货', + title: '待收货', + description: '已发货待收货的订单', + statusFilter: 3 // 对应后端:pay_status = true AND delivery_status = 20 + }, + { + index: 4, + key: '已完成', + title: '已完成', + description: '已完成的订单', + statusFilter: 5 // 对应后端:order_status = 1 + }, + { + index: 5, + key: '退货/售后', + title: '退货/售后', + description: '退货/售后的订单', + statusFilter: 6 // 对应后端:order_status = 6 (已退款) + } +] + +// 扩展订单接口,包含商品信息 +interface OrderWithGoods extends ShopOrder { + orderGoods?: ShopOrderGoods[]; +} + +interface OrderListProps { + onReload?: () => void; + searchParams?: ShopOrderParam; + showSearch?: boolean; + onSearchParamsChange?: (params: ShopOrderParam) => void; // 新增:通知父组件参数变化 +} + +function OrderList(props: OrderListProps) { + const [list, setList] = useState([]) + const [page, setPage] = useState(1) + const [hasMore, setHasMore] = useState(true) + // 根据传入的statusFilter设置初始tab索引 + const getInitialTabIndex = () => { + if (props.searchParams?.statusFilter !== undefined) { + const tab = tabs.find(t => t.statusFilter === props.searchParams?.statusFilter); + return tab ? tab.index : 0; + } + return 0; + }; + const [tapIndex, setTapIndex] = useState(() => { + const initialIndex = getInitialTabIndex(); + console.log('初始化tapIndex:', initialIndex, '对应statusFilter:', props.searchParams?.statusFilter); + return initialIndex; + }) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const [cancelDialogVisible, setCancelDialogVisible] = useState(false) + const [orderToCancel, setOrderToCancel] = useState(null) + const [confirmReceiveDialogVisible, setConfirmReceiveDialogVisible] = useState(false) + const [orderToConfirmReceive, setOrderToConfirmReceive] = useState(null) + + // 获取订单状态文本 + const getOrderStatusText = (order: ShopOrder) => { + + // 优先检查订单状态 + if (order.orderStatus === 2) return '已取消'; + if (order.orderStatus === 4) return '退款申请中'; + if (order.orderStatus === 5) return '退款被拒绝'; + if (order.orderStatus === 6) return '退款成功'; + if (order.orderStatus === 7) return '客户端申请退款'; + + // 检查支付状态 (payStatus为boolean类型,false/0表示未付款,true/1表示已付款) + if (!order.payStatus) return '等待买家付款'; + + // 已付款后检查发货状态 + if (order.deliveryStatus === 10) return '待发货'; + if (order.deliveryStatus === 20) return '待收货'; + if (order.deliveryStatus === 30) return '已完成'; + + // 最后检查订单完成状态 + if (order.orderStatus === 1) return '已完成'; + if (order.orderStatus === 0) return '未使用'; + + return '未知状态'; + }; + + // 获取订单状态颜色 + const getOrderStatusColor = (order: ShopOrder) => { + // 优先检查订单状态 + if (order.orderStatus === 2) return 'text-gray-500'; // 已取消 + if (order.orderStatus === 4) return 'text-orange-500'; // 退款申请中 + if (order.orderStatus === 5) return 'text-red-500'; // 退款被拒绝 + if (order.orderStatus === 6) return 'text-green-500'; // 退款成功 + if (order.orderStatus === 7) return 'text-orange-500'; // 客户端申请退款 + + // 检查支付状态 + if (!order.payStatus) return 'text-orange-500'; // 等待买家付款 + + // 已付款后检查发货状态 + if (order.deliveryStatus === 10) return 'text-blue-500'; // 待发货 + if (order.deliveryStatus === 20) return 'text-purple-500'; // 待收货 + if (order.deliveryStatus === 30) return 'text-green-500'; // 已收货 + + // 最后检查订单完成状态 + if (order.orderStatus === 1) return 'text-green-600'; // 已完成 + if (order.orderStatus === 0) return 'text-gray-500'; // 未使用 + + return 'text-gray-600'; // 默认颜色 + }; + + // 使用后端统一的 statusFilter 进行筛选 + const getOrderStatusParams = (index: string | number) => { + let params: ShopOrderParam = {}; + // 添加用户ID过滤 + params.userId = Taro.getStorageSync('UserId'); + + // 获取当前tab的statusFilter配置 + const currentTab = tabs.find(tab => tab.index === Number(index)); + if (currentTab && currentTab.statusFilter !== undefined) { + params.statusFilter = currentTab.statusFilter; + } + // 注意:当statusFilter为undefined时,不要添加到params中,这样API请求就不会包含这个参数 + + console.log(`Tab ${index} (${currentTab?.title}) 筛选参数:`, params); + return params; + }; + + const reload = useCallback(async (resetPage = false, targetPage?: number) => { + setLoading(true); + setError(null); // 清除之前的错误 + const currentPage = resetPage ? 1 : (targetPage || page); + const statusParams = getOrderStatusParams(tapIndex); + // 合并搜索条件,tab的statusFilter优先级更高 + const searchConditions: any = { + page: currentPage, + type: 1, + userId: statusParams.userId, // 用户ID + ...props.searchParams, // 搜索关键词等其他条件 + }; + + // statusFilter总是添加到搜索条件中(包括-1表示全部) + if (statusParams.statusFilter !== undefined) { + searchConditions.statusFilter = statusParams.statusFilter; + } + console.log('订单筛选条件:', { + tapIndex, + statusParams, + searchConditions, + finalStatusFilter: searchConditions.statusFilter + }); + + try { + const res = await pageClinicPrescription(searchConditions); + let newList: OrderWithGoods[]; + + if (res?.list && res?.list.length > 0) { + // 使用函数式更新避免依赖 list + setList(res?.list); + + // 正确判断是否还有更多数据 + const hasMoreData = res.list.length >= 10; // 假设每页10条数据 + setHasMore(hasMoreData); + } else { + setList(prevList => resetPage ? [] : prevList); + setHasMore(false); + } + + setPage(currentPage); + setLoading(false); + } catch (error) { + console.error('加载订单失败:', error); + setLoading(false); + setError('加载订单失败,请重试'); + // 添加错误提示 + Taro.showToast({ + title: '加载失败,请重试', + icon: 'none' + }); + } + }, [tapIndex, page, props.searchParams]); // 移除 list 依赖 + + const reloadMore = useCallback(async () => { + if (loading || !hasMore) return; // 防止重复加载 + const nextPage = page + 1; + setPage(nextPage); + await reload(false, nextPage); + }, [loading, hasMore, page, reload]); + + // 确认收货 - 显示确认对话框 + const confirmReceive = (order: ShopOrder) => { + setOrderToConfirmReceive(order); + setConfirmReceiveDialogVisible(true); + }; + + // 确认收货 - 执行收货操作 + const handleConfirmReceive = async () => { + if (!orderToConfirmReceive) return; + + try { + setConfirmReceiveDialogVisible(false); + + await updateShopOrder({ + ...orderToConfirmReceive, + deliveryStatus: 30, // 已收货 + orderStatus: 1 // 已完成 + }); + + Taro.showToast({ + title: '确认收货成功', + icon: 'success' + }); + + await reload(true); // 重新加载列表 + props.onReload?.(); // 通知父组件刷新 + + // 清空状态 + setOrderToConfirmReceive(null); + } catch (error) { + console.error('确认收货失败:', error); + Taro.showToast({ + title: '确认收货失败', + icon: 'none' + }); + // 重新显示对话框 + setConfirmReceiveDialogVisible(true); + } + }; + + // 取消确认收货对话框 + const handleCancelReceiveDialog = () => { + setConfirmReceiveDialogVisible(false); + setOrderToConfirmReceive(null); + }; + + // 申请退款 (待发货状态) + const applyRefund = (order: ShopOrder) => { + // 跳转到退款申请页面 + Taro.navigateTo({ + url: `/user/order/refund/index?orderId=${order.orderId}&orderNo=${order.orderNo}` + }); + }; + + // 查看物流 (待收货状态) + const viewLogistics = (order: ShopOrder) => { + // 跳转到物流查询页面 + Taro.navigateTo({ + url: `/user/order/logistics/index?orderId=${order.orderId}&orderNo=${order.orderNo}&expressNo=${order.transactionId || ''}&expressCompany=SF` + }); + }; + + // 再次购买 (已完成状态) + const buyAgain = (order: ShopOrder) => { + console.log('再次购买:', order); + goTo(`/shop/orderConfirm/index?goodsId=${order.orderGoods[0].goodsId}`) + // Taro.showToast({ + // title: '再次购买功能开发中', + // icon: 'none' + // }); + }; + + // 评价商品 (已完成状态) + const evaluateGoods = (order: ShopOrder) => { + // 跳转到评价页面 + Taro.navigateTo({ + url: `/user/order/evaluate/index?orderId=${order.orderId}&orderNo=${order.orderNo}` + }); + }; + + // 查看进度 (退款/售后状态) + const viewProgress = (order: ShopOrder) => { + // 根据订单状态确定售后类型 + let afterSaleType = 'refund' // 默认退款 + + if (order.orderStatus === 4) { + afterSaleType = 'refund' // 退款申请中 + } else if (order.orderStatus === 7) { + afterSaleType = 'return' // 退货申请中 + } + + // 跳转到售后进度页面 + Taro.navigateTo({ + url: `/user/order/progress/index?orderId=${order.orderId}&orderNo=${order.orderNo}&type=${afterSaleType}` + }); + }; + + // 撤销申请 (退款/售后状态) + const cancelApplication = (order: ShopOrder) => { + console.log('撤销申请:', order); + Taro.showToast({ + title: '撤销申请功能开发中', + icon: 'none' + }); + }; + + // 取消订单 + const cancelOrder = (order: ShopOrder) => { + setOrderToCancel(order); + setCancelDialogVisible(true); + }; + + // 确认取消订单 + const handleConfirmCancel = async () => { + if (!orderToCancel) return; + + try { + setCancelDialogVisible(false); + + // 更新订单状态为已取消,而不是删除订单 + await updateShopOrder({ + ...orderToCancel, + orderStatus: 2 // 已取消 + }); + + Taro.showToast({ + title: '订单已取消', + icon: 'success' + }); + void reload(true); // 重新加载列表 + props.onReload?.(); // 通知父组件刷新 + } catch (error) { + console.error('取消订单失败:', error); + Taro.showToast({ + title: '取消订单失败', + icon: 'error' + }); + } finally { + setOrderToCancel(null); + } + }; + + // 取消对话框的取消操作 + const handleCancelDialog = () => { + setCancelDialogVisible(false); + setOrderToCancel(null); + }; + + // 立即支付 + const payOrder = async (order: ShopOrder) => { + try { + if (!order.orderId || !order.orderNo) { + Taro.showToast({ + title: '订单信息错误', + icon: 'error' + }); + return; + } + + // 检查订单是否已过期 + if (order.createTime && isPaymentExpired(order.createTime)) { + Taro.showToast({ + title: '订单已过期,无法支付', + icon: 'error' + }); + return; + } + + // 检查订单状态 + if (order.payStatus) { + Taro.showToast({ + title: '订单已支付', + icon: 'none' + }); + return; + } + + if (order.orderStatus === 2) { + Taro.showToast({ + title: '订单已取消,无法支付', + icon: 'error' + }); + return; + } + + Taro.showLoading({title: '发起支付...'}); + + // 构建商品数据 + const goodsItems = order.orderGoods?.map(goods => ({ + goodsId: goods.goodsId, + quantity: goods.totalNum || 1 + })) || []; + + // 对于已存在的订单,我们需要重新发起支付 + // 构建支付请求数据,包含完整的商品信息 + const paymentData = { + orderId: order.orderId, + orderNo: order.orderNo, + goodsItems: goodsItems, + addressId: order.addressId, + payType: PaymentType.WECHAT + }; + + console.log('重新支付数据:', paymentData); + + // 直接调用createOrder API进行重新支付 + const result = await createOrder(paymentData as any); + + if (!result) { + throw new Error('支付发起失败'); + } + + // 验证微信支付必要参数 + if (!result.timeStamp || !result.nonceStr || !result.package || !result.paySign) { + throw new Error('微信支付参数不完整'); + } + + // 调用微信支付 + await Taro.requestPayment({ + timeStamp: result.timeStamp, + nonceStr: result.nonceStr, + package: result.package, + signType: (result.signType || 'MD5') as 'MD5' | 'HMAC-SHA256', + paySign: result.paySign, + }); + + // 支付成功 + Taro.showToast({ + title: '支付成功', + icon: 'success' + }); + + // 重新加载订单列表 + void reload(true); + props.onReload?.(); + + // 跳转到订单页面 + setTimeout(() => { + Taro.navigateTo({url: '/user/order/order'}); + }, 2000); + + } catch (error: any) { + console.error('支付失败:', error); + + let errorMessage = '支付失败,请重试'; + if (error.message) { + if (error.message.includes('cancel')) { + errorMessage = '用户取消支付'; + } else if (error.message.includes('余额不足')) { + errorMessage = '账户余额不足'; + } else { + errorMessage = error.message; + } + } + + Taro.showToast({ + title: errorMessage, + icon: 'error' + }); + } finally { + Taro.hideLoading(); + } + }; + + + useEffect(() => { + void reload(true); // 首次加载或tab切换时重置页码 + }, [tapIndex]); // 只监听tapIndex变化,避免reload依赖循环 + + // 监听外部statusFilter变化,同步更新tab索引 + useEffect(() => { + // 获取当前的statusFilter,如果未定义则默认为-1(全部) + const currentStatusFilter = props.searchParams?.statusFilter !== undefined + ? props.searchParams.statusFilter + : -1; + + const tab = tabs.find(t => t.statusFilter === currentStatusFilter); + const targetTabIndex = tab ? tab.index : 0; + + console.log('外部statusFilter变化:', { + statusFilter: currentStatusFilter, + originalStatusFilter: props.searchParams?.statusFilter, + currentTapIndex: tapIndex, + targetTabIndex, + shouldUpdate: targetTabIndex !== tapIndex + }); + + if (targetTabIndex !== tapIndex) { + setTapIndex(targetTabIndex); + // 不需要调用reload,因为tapIndex变化会触发reload + } + }, [props.searchParams?.statusFilter, tapIndex]); // 监听statusFilter变化 + + + return ( + <> + { + console.log('Tab切换:', paneKey, '类型:', typeof paneKey); + const newTapIndex = Number(paneKey); + setTapIndex(newTapIndex); + + // 通知父组件更新 searchParams.statusFilter + const currentTab = tabs.find(tab => tab.index === newTapIndex); + if (currentTab && props.onSearchParamsChange) { + const newSearchParams = { + ...props.searchParams, + statusFilter: currentTab.statusFilter + }; + console.log('通知父组件更新searchParams:', newSearchParams); + props.onSearchParamsChange(newSearchParams); + } + }} + > + { + tabs?.map((item, _) => { + return ( + + ) + }) + } + + + {error ? ( + + {error} + + + ) : ( + { + + }} + onScrollToUpper={() => { + + }} + loadingText={ + <> + 加载中 + + } + loadMoreText={ + list.length === 0 ? ( + + ) : ( + + 没有更多了 + + ) + } + > + + {/* 订单列表 */} + {list.length > 0 && list + ?.filter((item) => { + // 如果是待付款标签页(tapIndex === 1),过滤掉支付已过期的订单 + if (tapIndex === 1 && !item.payStatus && item.orderStatus !== 2 && item.createTime) { + return !isPaymentExpired(item.createTime); + } + return true; + }) + ?.map((item, index) => { + return ( + Taro.navigateTo({url: `/shop/orderDetail/index?orderId=${item.orderId}`})}> + + + + { + e.stopPropagation(); + copyText(`${item.orderNo}`) + }}>{item.orderNo} + + {/* 右侧显示合并的状态和倒计时 */} + + {!item.payStatus && item.orderStatus !== 2 ? ( + + ) : ( + getOrderStatusText(item) + )} + + + {dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')} + + {/* 商品信息 */} + + {item.orderGoods && item.orderGoods.length > 0 ? ( + item.orderGoods.map((goods, goodsIndex) => ( + + + + {goods.goodsName} + {goods.spec && 规格:{goods.spec}} + 数量:{goods.totalNum} + + ¥{goods.price} + + )) + ) : ( + + + + {item.title || '订单商品'} + {item.totalNum}件商品 + + + )} + + + 实付金额:¥{item.payPrice} + + {/* 操作按钮 */} + + {/* 待付款状态:显示取消订单和立即支付 */} + {(!item.payStatus) && item.orderStatus !== 2 && ( + + + + + )} + + {/* 待发货状态:显示申请退款 */} + {/*{item.payStatus && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && (*/} + {/* */} + {/*)}*/} + + {/* 待收货状态:显示查看物流和确认收货 */} + {item.deliveryStatus === 20 && item.orderStatus !== 2 && ( + + {/**/} + + + )} + + {/* 已完成状态:显示再次购买、评价商品、申请退款 */} + {item.orderStatus === 1 && ( + + + {/**/} + {/**/} + + )} + + {/* 退款/售后状态:显示查看进度和撤销申请 */} + {(item.orderStatus === 4 || item.orderStatus === 7) && ( + + {/**/} + + )} + + {/* 退款成功状态:显示再次购买 */} + {item.orderStatus === 6 && ( + + )} + + + + ) + })} + + )} + + + {/* 取消订单确认对话框 */} + + 确定要取消这个订单吗? + + + {/* 确认收货确认对话框 */} + + 确定已经收到商品了吗?确认收货后订单将完成。 + + + ) +} + +export default OrderList diff --git a/src/clinic/clinicPrescription/index.config.ts b/src/clinic/clinicPrescription/index.config.ts index 10c2660..3eee91a 100644 --- a/src/clinic/clinicPrescription/index.config.ts +++ b/src/clinic/clinicPrescription/index.config.ts @@ -1,4 +1,4 @@ export default definePageConfig({ - navigationBarTitleText: '处方', + navigationBarTitleText: '处方管理', navigationBarTextStyle: 'black' }) diff --git a/src/clinic/clinicPrescription/index.scss b/src/clinic/clinicPrescription/index.scss new file mode 100644 index 0000000..07a1ee5 --- /dev/null +++ b/src/clinic/clinicPrescription/index.scss @@ -0,0 +1,72 @@ +page { + background: linear-gradient(to bottom, #f3f3f3, #f9fafb); + background-size: 100%; +} + +.search-container { + transition: all 0.3s ease; + + .nut-input { + background-color: #f8f9fa !important; + border: 1px solid #e5e5e5 !important; + border-radius: 4px !important; + + &:focus { + border-color: #007bff !important; + box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25) !important; + } + } + + .nut-button { + border-radius: 4px !important; + + &--primary { + background: linear-gradient(135deg, #007bff, #0056b3) !important; + border: none !important; + } + + &--small { + padding: 6px 12px !important; + font-size: 12px !important; + } + } +} + +// Tabs样式优化 +.nut-tabs { + .nut-tabs__titles { + background: #ffffff !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; + + .nut-tabs__titles-item { + font-size: 14px !important; + font-weight: 500 !important; + + &--active { + color: #007bff !important; + font-weight: 600 !important; + } + } + + .nut-tabs__line { + background: #007bff !important; + height: 3px !important; + } + } +} + +// 筛选提示样式 +.filter-tip { + animation: slideDown 0.3s ease; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/src/clinic/clinicPrescription/index.tsx b/src/clinic/clinicPrescription/index.tsx index 9fd0e85..6474ff6 100644 --- a/src/clinic/clinicPrescription/index.tsx +++ b/src/clinic/clinicPrescription/index.tsx @@ -1,201 +1,121 @@ -import {useState} from "react"; -import Taro, {useDidShow} from '@tarojs/taro' -import {Button, Cell, CellGroup, Space, Empty, ConfigProvider, Tag} from '@nutui/nutui-react-taro' -import {Del, Edit} from '@nutui/icons-react-taro' -import {View, Text} from '@tarojs/components' -import {ClinicPrescription} from "@/api/clinic/clinicPrescription/model"; -import { - pageClinicPrescription, - removeClinicPrescription -} from "@/api/clinic/clinicPrescription"; -import FixedButton from "@/components/FixedButton"; -import {copyText} from "@/utils/common"; +import {useState, useCallback, useRef, useEffect} from "react"; +import Taro from '@tarojs/taro' +import {Space, Button, Input} from '@nutui/nutui-react-taro' +import {View} from '@tarojs/components'; +import OrderList from "./components/OrderList"; +import {useRouter} from '@tarojs/taro' +import {ShopOrderParam} from "@/api/shop/shopOrder/model"; +import './index.scss' -const ClinicPrescriptionList = () => { - const [list, setList] = useState([]) - const [loading, setLoading] = useState(false) +function ClinicPrescriptionList() { + const {params} = useRouter(); + const [statusBarHeight, setStatusBarHeight] = useState(0) // 默认值为0 + const [searchParams, setSearchParams] = useState({ + statusFilter: params.statusFilter != undefined && params.statusFilter != '' ? parseInt(params.statusFilter) : -1 + }) + const [showSearch, setShowSearch] = useState(false) + const [searchKeyword, setSearchKeyword] = useState('') + const searchTimeoutRef = useRef() - const reload = () => { - setLoading(true) - pageClinicPrescription({ - // 添加查询条件 - doctorId: Taro.getStorageSync('UserId'), - }) - .then(data => { - setList(data?.list || []) - }) - .catch(() => { - Taro.showToast({ - title: '获取数据失败', - icon: 'error' - }); - }) - .finally(() => { - setLoading(false) - }) + const reload = async (where?: ShopOrderParam) => { + console.log(where,'where...') + setSearchParams(prev => ({ ...prev, ...where })) } - const onDel = async (item: ClinicPrescription) => { - const res = await Taro.showModal({ - title: '确认删除', - content: `确定要删除处方编号「${item.orderNo}」吗?`, - }) - - if (res.confirm) { - try { - await removeClinicPrescription(item.id) - Taro.showToast({ - title: '删除成功', - icon: 'success' - }); - reload(); - } catch (error) { - Taro.showToast({ - title: '删除失败', - icon: 'error' - }); - } + // 防抖搜索函数 + const debouncedSearch = useCallback((keyword: string) => { + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); } - } - const onEdit = (item: ClinicPrescription) => { - Taro.navigateTo({ - url: `/clinic/clinicPrescription/add?id=${item.id}` + searchTimeoutRef.current = setTimeout(() => { + if (keyword.trim()) { + handleSearch({keywords: keyword.trim()}); + } else { + // 如果搜索关键词为空,清除keywords参数 + const newSearchParams = { ...searchParams }; + delete newSearchParams.keywords; + setSearchParams(newSearchParams); + reload(newSearchParams).then(); + } + }, 500); // 500ms防抖延迟 + }, [searchParams]); + + // 处理搜索 + const handleSearch = (where: ShopOrderParam) => { + // 合并搜索参数,保留当前的statusFilter + const newSearchParams = { + ...searchParams, // 保留当前的所有参数(包括statusFilter) + ...where // 应用新的搜索条件 + }; + setSearchParams(newSearchParams) + reload(newSearchParams).then() + } + useEffect(() => { + // 获取状态栏高度 + Taro.getSystemInfo({ + success: (res) => { + setStatusBarHeight(res.statusBarHeight ?? 0) + }, }) - } - - const onDetail = (item: ClinicPrescription) => { - Taro.navigateTo({ - url: `/clinic/clinicPrescription/detail?id=${item.id}` - }) - } - - const getSexName = (sex?: number) => { - return sex === 0 ? '男' : sex === 1 ? '女' : '' - } - - useDidShow(() => { - reload() - }); - - if (list.length === 0 && !loading) { - return ( - - - - - - - - - ) - } + reload().then() + }, []); return ( - <> - - {list.map((item) => ( - - 待支付 - } - onClick={() => copyText(`${item.orderNo}`)} - /> - - {item.realName} - {item.age}岁 - {getSexName(item.sex)} - - } - /> - {/**/} - {/* {getPrescriptionTypeText(item.prescriptionType)}*/} - {/* */} - {/* }*/} - {/*/>*/} - {item.diagnosis && ( - - {item.diagnosis.length > 20 - ? `${item.diagnosis.substring(0, 20)}...` - : item.diagnosis} - - } + + {/* 搜索组件 */} + {showSearch && ( + + + + { + setSearchKeyword(value); + debouncedSearch(value); // 使用防抖搜索 + }} + onConfirm={() => { + if (searchKeyword.trim()) { + handleSearch({keywords: searchKeyword.trim()}); + } + }} + style={{ + padding: '8px 12px', + border: '1px solid #e5e5e5', + borderRadius: '4px', + backgroundColor: '#f8f9fa' + }} /> - )} - - ¥{item.orderPrice || '0.00'} - - } - /> - - {item.createTime} - - } - /> - - - - - - - - - ))} - + + + + + + + )} - Taro.navigateTo({url: '/clinic/clinicPrescription/add'})} + {/*订单列表*/} + reload(searchParams)} + searchParams={searchParams} + showSearch={showSearch} + onSearchParamsChange={(newParams) => { + console.log('父组件接收到searchParams变化:', newParams); + setSearchParams(newParams); + }} /> - - ) + + ); } export default ClinicPrescriptionList; diff --git a/src/user/order/components/OrderList.tsx b/src/user/order/components/OrderList.tsx index 1ccbac2..8ba4c6d 100644 --- a/src/user/order/components/OrderList.tsx +++ b/src/user/order/components/OrderList.tsx @@ -188,6 +188,7 @@ function OrderList(props: OrderListProps) { // 合并搜索条件,tab的statusFilter优先级更高 const searchConditions: any = { page: currentPage, + type: 0, userId: statusParams.userId, // 用户ID ...props.searchParams, // 搜索关键词等其他条件 };